From 07e89e96b880fc6b8c358422ec109d6c167a0120 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Tue, 12 Mar 2024 14:31:36 -0400 Subject: [PATCH 01/16] re-organized zetatool folder --- Makefile | 4 + cmd/zetatool/config/config.go | 78 ++++++++ cmd/zetatool/filterdeposit/btc.go | 147 +++++++++++++++ cmd/zetatool/filterdeposit/evm.go | 198 ++++++++++++++++++++ cmd/zetatool/filterdeposit/filterdeposit.go | 59 ++++++ cmd/zetatool/main.go | 26 +++ go.mod | 1 + go.sum | 2 + 8 files changed, 515 insertions(+) create mode 100644 cmd/zetatool/config/config.go create mode 100644 cmd/zetatool/filterdeposit/btc.go create mode 100644 cmd/zetatool/filterdeposit/evm.go create mode 100644 cmd/zetatool/filterdeposit/filterdeposit.go create mode 100644 cmd/zetatool/main.go diff --git a/Makefile b/Makefile index b888d22629..43e447f956 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,10 @@ install-zetaclient-race-test-only-build: go.sum @echo "--> Installing zetaclientd" @go install -race -mod=readonly $(BUILD_FLAGS) ./cmd/zetaclientd +install-zetatool: go.sum + @echo "--> Installing zetatool" + @go install -mod=readonly $(BUILD_FLAGS) ./cmd/zetatool + ############################################################################### ### Local network ### ############################################################################### diff --git a/cmd/zetatool/config/config.go b/cmd/zetatool/config/config.go new file mode 100644 index 0000000000..af29f39c93 --- /dev/null +++ b/cmd/zetatool/config/config.go @@ -0,0 +1,78 @@ +package config + +import ( + "encoding/json" + "os" +) + +const ( + Flag = "config" + defaultCfgFileName = "InboundTxFilter_config.json" + ZetaUrl = "http://46.4.15.110:1317" //http://100.71.167.102:26657 + TssAddressBTC = "bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y" + TssAddressEVM = "0x70e967acfcc17c3941e87562161406d41676fd83" + BtcExplorer = "https://blockstream.info/api/address/bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y/txs" + EthRPC = "https://rpc.ankr.com/eth/2da24e4a1fd28f2bec1569eceb2c38a5694b7f5c83fd24c69ae714a89a514f9b" + ConnectorAddress = "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a" + CustodyAddress = "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10" + EvmStartBlock = 19200110 + EvmMaxRange = 1000 +) + +type Config struct { + ZetaUrl string + TssAddressBTC string + TssAddressEVM string + BtcExplorer string + EthRPC string + ConnectorAddress string + CustodyAddress string + EvmStartBlock uint64 + EvmMaxRange uint64 +} + +func DefaultConfig() *Config { + return &Config{ + ZetaUrl: ZetaUrl, + TssAddressBTC: TssAddressBTC, + TssAddressEVM: TssAddressEVM, + BtcExplorer: BtcExplorer, + EthRPC: EthRPC, + ConnectorAddress: ConnectorAddress, + CustodyAddress: CustodyAddress, + EvmStartBlock: EvmStartBlock, + EvmMaxRange: EvmMaxRange, + } +} + +func (c *Config) Save() error { + file, err := json.MarshalIndent(c, "", " ") + if err != nil { + return err + } + err = os.WriteFile(defaultCfgFileName, file, 0644) + return err +} + +func (c *Config) Read(filename string) error { + data, err := os.ReadFile(filename) + if err != nil { + return err + } + err = json.Unmarshal(data, c) + return err +} + +func GetConfig(filename string) (*Config, error) { + //Check if cfgFile is empty, if so return default Config and save to file + if filename == "" { + cfg := DefaultConfig() + err := cfg.Save() + return cfg, err + } + + //if file is specified, open file and return struct + cfg := &Config{} + err := cfg.Read(filename) + return cfg, err +} diff --git a/cmd/zetatool/filterdeposit/btc.go b/cmd/zetatool/filterdeposit/btc.go new file mode 100644 index 0000000000..579fb9c97e --- /dev/null +++ b/cmd/zetatool/filterdeposit/btc.go @@ -0,0 +1,147 @@ +package filterdeposit + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "strings" + + "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/cmd/zetatool/config" +) + +var btcCmd = &cobra.Command{ + Use: "btc", + Short: "Filter inbound btc deposits", + Run: FilterBTCTransactions, +} + +func init() { + Cmd.AddCommand(btcCmd) +} + +func FilterBTCTransactions(cmd *cobra.Command, _ []string) { + configFile, err := cmd.Flags().GetString(config.Flag) + fmt.Println("config file name: ", configFile) + if err != nil { + log.Fatal(err) + } + cfg, err := config.GetConfig(configFile) + if err != nil { + log.Fatal(err) + } + list := getHashList(cfg) + CheckForCCTX(list, cfg) +} + +func getHashList(cfg *config.Config) []deposit { + var list []deposit + lastHash := "" + + url := cfg.BtcExplorer + + for { + nextQuery := url + if lastHash != "" { + path := fmt.Sprintf("/chain/%s", lastHash) + nextQuery = url + path + } + res, getErr := http.Get(nextQuery) + if getErr != nil { + log.Fatal(getErr) + } + + body, readErr := ioutil.ReadAll(res.Body) + if readErr != nil { + log.Fatal(readErr) + } + + var txns []map[string]interface{} + err := json.Unmarshal(body, &txns) + if err != nil { + fmt.Println("error unmarshalling: ", err.Error()) + } + + if len(txns) == 0 { + break + } + + fmt.Println("Length of txns: ", len(txns)) + + for _, txn := range txns { + hash := txn["txid"].(string) + + vout := txn["vout"].([]interface{}) + vout0 := vout[0].(map[string]interface{}) + var vout1 map[string]interface{} + if len(vout) > 1 { + vout1 = vout[1].(map[string]interface{}) + } else { + continue + } + _, found := vout0["scriptpubkey"] + scriptpubkey := "" + if found { + scriptpubkey = vout0["scriptpubkey"].(string) + } + _, found = vout0["scriptpubkey_address"] + targetAddr := "" + if found { + targetAddr = vout0["scriptpubkey_address"].(string) + } + + //Check if txn is confirmed + status := txn["status"].(map[string]interface{}) + confirmed := status["confirmed"].(bool) + if !confirmed { + continue + } + + //Filter out deposits less than min base fee + if vout0["value"].(float64) < 1360 { + continue + } + + //Check if deposit is a donation + scriptpubkey1 := vout1["scriptpubkey"].(string) + if len(scriptpubkey1) >= 4 && scriptpubkey1[:2] == "6a" { + memoSize, err := strconv.ParseInt(scriptpubkey1[2:4], 16, 32) + if err != nil { + continue + } + if int(memoSize) != (len(scriptpubkey1)-4)/2 { + continue + } + memoBytes, err := hex.DecodeString(scriptpubkey1[4:]) + if err != nil { + continue + } + if bytes.Equal(memoBytes, []byte(DonationMessage)) { + continue + } + } else { + continue + } + + //Make sure deposit is sent to correct tss address + if strings.Compare("0014", scriptpubkey[:4]) == 0 && targetAddr == cfg.TssAddressBTC { + entry := deposit{ + hash, + vout0["value"].(float64), + } + list = append(list, entry) + } + } + + lastTxn := txns[len(txns)-1] + lastHash = lastTxn["txid"].(string) + //fmt.Println("last hash: ", lastHash) + } + + return list +} diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go new file mode 100644 index 0000000000..e4ded1b713 --- /dev/null +++ b/cmd/zetatool/filterdeposit/evm.go @@ -0,0 +1,198 @@ +package filterdeposit + +import ( + "context" + "fmt" + "log" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/nanmu42/etherscan-api" + "github.com/spf13/cobra" + "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol" + "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.non-eth.sol" + "github.com/zeta-chain/zetacore/cmd/zetatool/config" +) + +const ( + TopicsDeposited = 2 + TopicsZetaSent = 3 + DonationMessage = "I am rich!" +) + +var evmCmd = &cobra.Command{ + Use: "evm", + Short: "Filter inbound eth deposits", + Run: FilterEVMTransactions, +} + +func init() { + Cmd.AddCommand(evmCmd) +} + +func FilterEVMTransactions(cmd *cobra.Command, _ []string) { + configFile, err := cmd.Flags().GetString(config.Flag) + if err != nil { + log.Fatal(err) + } + cfg, err := config.GetConfig(configFile) + if err != nil { + log.Fatal(err) + } + list := GetEthHashList(cfg) + CheckForCCTX(list, cfg) +} + +func GetEthHashList(cfg *config.Config) []deposit { + startBlock := cfg.EvmStartBlock + client, err := ethclient.Dial(cfg.EthRPC) + if err != nil { + log.Fatal(err) + } + fmt.Println("Connection successful") + + header, err := client.HeaderByNumber(context.Background(), nil) + if err != nil { + log.Fatal(err) + } + latestBlock := uint64(header.Number.Int64()) + fmt.Println("latest Block: ", latestBlock) + + endBlock := startBlock + cfg.EvmMaxRange + deposits := make([]deposit, 0) + segment := 0 + for startBlock < latestBlock { + fmt.Printf("adding segment: %d, startblock: %d\n", segment, startBlock) + deposits = append(deposits, GetHashListSegment(client, startBlock, endBlock, cfg)...) + startBlock = endBlock + endBlock = endBlock + cfg.EvmMaxRange + if endBlock > latestBlock { + endBlock = latestBlock + } + segment++ + } + return deposits +} + +func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock uint64, cfg *config.Config) []deposit { + deposits := make([]deposit, 0) + + connectorAddress := common.HexToAddress(cfg.ConnectorAddress) + connectorContract, err := zetaconnector.NewZetaConnectorNonEth(connectorAddress, client) + if err != nil { + fmt.Println("error: ", err.Error()) + } + erc20CustodyAddress := common.HexToAddress(cfg.CustodyAddress) + erc20CustodyContract, err := erc20custody.NewERC20Custody(erc20CustodyAddress, client) + if err != nil { + fmt.Println("error: ", err.Error()) + } + + custodyIter, err := erc20CustodyContract.FilterDeposited(&bind.FilterOpts{ + Start: startBlock, + End: &endBlock, + Context: context.TODO(), + }, []common.Address{}) + if err != nil { + fmt.Println("error loading filter: ", err.Error()) + return deposits + } + + connectorIter, err := connectorContract.FilterZetaSent(&bind.FilterOpts{ + Start: startBlock, + End: &endBlock, + Context: context.TODO(), + }, []common.Address{}, []*big.Int{}) + if err != nil { + fmt.Println("error loading filter: ", err.Error()) + return deposits + } + + // ********************** Get ERC20 Custody deposit events + for custodyIter.Next() { + // sanity check tx event + err := CheckEvmTxLog(&custodyIter.Event.Raw, erc20CustodyAddress, "", TopicsDeposited) + if err == nil { + //fmt.Println("adding deposits") + deposits = append(deposits, deposit{ + txId: custodyIter.Event.Raw.TxHash.Hex(), + amount: float64(custodyIter.Event.Amount.Int64()), + }) + } + } + + // ********************** Get Connector ZetaSent events + for connectorIter.Next() { + // sanity check tx event + err := CheckEvmTxLog(&connectorIter.Event.Raw, connectorAddress, "", TopicsZetaSent) + if err == nil { + //fmt.Println("adding deposits") + deposits = append(deposits, deposit{ + txId: connectorIter.Event.Raw.TxHash.Hex(), + amount: float64(connectorIter.Event.ZetaValueAndGas.Int64()), + }) + } + } + + //********************** Get Transactions sent directly to TSS address + tssDeposits, err := getTSSDeposits(cfg.TssAddressEVM, int(startBlock), int(endBlock)) + if err != nil { + fmt.Printf("getTSSDeposits returned err: %s", err.Error()) + } + deposits = append(deposits, tssDeposits...) + + return deposits +} + +func getTSSDeposits(tssAddress string, startBlock int, endBlock int) ([]deposit, error) { + client := etherscan.New(etherscan.Mainnet, "S3AVTNXDJQZQQUVXJM4XVIPBRYECGK88VX") + deposits := make([]deposit, 0) + + txns, err := client.NormalTxByAddress(tssAddress, &startBlock, &endBlock, 0, 0, true) + if err != nil { + return deposits, err + } + + fmt.Println("getTSSDeposits - Num of transactions: ", len(txns)) + + for _, tx := range txns { + if tx.To == tssAddress { + if strings.Compare(tx.Input, DonationMessage) == 0 { + continue // skip donation tx + } + if tx.TxReceiptStatus != "1" { + continue + } + //fmt.Println("getTSSDeposits - adding deposit") + deposits = append(deposits, deposit{ + txId: tx.Hash, + amount: float64(tx.Value.Int().Int64()), + }) + } + } + + return deposits, nil +} + +func CheckEvmTxLog(vLog *ethtypes.Log, wantAddress common.Address, wantHash string, wantTopics int) error { + if vLog.Removed { + return fmt.Errorf("log is removed, chain reorg?") + } + if vLog.Address != wantAddress { + return fmt.Errorf("log emitter address mismatch: want %s got %s", wantAddress.Hex(), vLog.Address.Hex()) + } + if vLog.TxHash.Hex() == "" { + return fmt.Errorf("log tx hash is empty: %d %s", vLog.BlockNumber, vLog.TxHash.Hex()) + } + if wantHash != "" && vLog.TxHash.Hex() != wantHash { + return fmt.Errorf("log tx hash mismatch: want %s got %s", wantHash, vLog.TxHash.Hex()) + } + if len(vLog.Topics) != wantTopics { + return fmt.Errorf("number of topics mismatch: want %d got %d", wantTopics, len(vLog.Topics)) + } + return nil +} diff --git a/cmd/zetatool/filterdeposit/filterdeposit.go b/cmd/zetatool/filterdeposit/filterdeposit.go new file mode 100644 index 0000000000..c97ef7edd5 --- /dev/null +++ b/cmd/zetatool/filterdeposit/filterdeposit.go @@ -0,0 +1,59 @@ +package filterdeposit + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/url" + + "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/cmd/zetatool/config" +) + +var Cmd = &cobra.Command{ + Use: "filterdeposit", + Short: "filter missing inbound deposits", +} + +type deposit struct { + txId string + amount float64 +} + +func CheckForCCTX(list []deposit, cfg *config.Config) { + var missedList []deposit + + fmt.Println("Going through list, num of transactions: ", len(list)) + for _, entry := range list { + zetaUrl, err := url.JoinPath(cfg.ZetaUrl, "zeta-chain", "crosschain", "in_tx_hash_to_cctx_data", entry.txId) + if err != nil { + log.Fatal(err) + } + res, getErr := http.Get(zetaUrl) + if getErr != nil { + log.Fatal(getErr) + } + + data, readErr := ioutil.ReadAll(res.Body) + if readErr != nil { + log.Fatal(readErr) + } + + var cctx map[string]interface{} + err = json.Unmarshal(data, &cctx) + if err != nil { + fmt.Println("error unmarshalling: ", err.Error()) + } + + if _, ok := cctx["code"]; ok { + missedList = append(missedList, entry) + //fmt.Println("appending to missed list: ", entry) + } + } + + for _, entry := range missedList { + fmt.Printf("%s, amount: %d\n", entry.txId, int64(entry.amount)) + } +} diff --git a/cmd/zetatool/main.go b/cmd/zetatool/main.go new file mode 100644 index 0000000000..7eef1865a5 --- /dev/null +++ b/cmd/zetatool/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/cmd/zetatool/config" + "github.com/zeta-chain/zetacore/cmd/zetatool/filterdeposit" + "os" +) + +var rootCmd = &cobra.Command{ + Use: "zetatool", + Short: "utility tool for zeta-chain", +} + +func init() { + rootCmd.AddCommand(filterdeposit.Cmd) + rootCmd.PersistentFlags().String(config.Flag, "", "custom config file: --config filename.json") +} + +func main() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/go.mod b/go.mod index 6669039f30..9560f12c9e 100644 --- a/go.mod +++ b/go.mod @@ -59,6 +59,7 @@ require ( require ( github.com/binance-chain/tss-lib v0.0.0-20201118045712-70b2cb4bf916 + github.com/nanmu42/etherscan-api v1.10.0 github.com/onrik/ethrpc v1.2.0 ) diff --git a/go.sum b/go.sum index 7b2dc1998c..96e3c53ae9 100644 --- a/go.sum +++ b/go.sum @@ -2314,6 +2314,8 @@ github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/nanmu42/etherscan-api v1.10.0 h1:8lAwKbaHEVzXK+cbLaApxbmp4Kai12WKEcY9CxqxKbY= +github.com/nanmu42/etherscan-api v1.10.0/go.mod h1:P8oAUxbYfsdfGXQnHCgjTDs4YbmasUVCtYAYc4rrZ5w= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= From 1fab44498f5d5a705a270434f7845ce33f0ad63e Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Tue, 12 Mar 2024 14:39:58 -0400 Subject: [PATCH 02/16] added changelog --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index 9d615c4f01..c101420e6a 100644 --- a/changelog.md +++ b/changelog.md @@ -21,6 +21,7 @@ * [1789](https://github.com/zeta-chain/node/issues/1789) - block cross-chain transactions that involve restricted addresses * [1755](https://github.com/zeta-chain/node/issues/1755) - use evm JSON RPC for inbound tx (including blob tx) observation. * [1815](https://github.com/zeta-chain/node/pull/1815) - add authority module for authorized actions +* [1884](https://github.com/zeta-chain/node/pull/1884) - added zetatool cmd, added subcommand to filter deposits ### Tests From ef31bc4c42ca9364274c27f7f43528236a9c4a52 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Tue, 12 Mar 2024 15:09:34 -0400 Subject: [PATCH 03/16] fix lint and gosec errors --- cmd/zetatool/config/config.go | 8 ++--- cmd/zetatool/filterdeposit/btc.go | 15 ++++++--- cmd/zetatool/filterdeposit/evm.go | 34 ++++++++++----------- cmd/zetatool/filterdeposit/filterdeposit.go | 21 ++++++++----- cmd/zetatool/main.go | 3 +- 5 files changed, 46 insertions(+), 35 deletions(-) diff --git a/cmd/zetatool/config/config.go b/cmd/zetatool/config/config.go index af29f39c93..eac4d4e2f7 100644 --- a/cmd/zetatool/config/config.go +++ b/cmd/zetatool/config/config.go @@ -8,7 +8,7 @@ import ( const ( Flag = "config" defaultCfgFileName = "InboundTxFilter_config.json" - ZetaUrl = "http://46.4.15.110:1317" //http://100.71.167.102:26657 + ZetaURL = "http://46.4.15.110:1317" //http://100.71.167.102:26657 TssAddressBTC = "bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y" TssAddressEVM = "0x70e967acfcc17c3941e87562161406d41676fd83" BtcExplorer = "https://blockstream.info/api/address/bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y/txs" @@ -20,7 +20,7 @@ const ( ) type Config struct { - ZetaUrl string + ZetaURL string TssAddressBTC string TssAddressEVM string BtcExplorer string @@ -33,7 +33,7 @@ type Config struct { func DefaultConfig() *Config { return &Config{ - ZetaUrl: ZetaUrl, + ZetaURL: ZetaURL, TssAddressBTC: TssAddressBTC, TssAddressEVM: TssAddressEVM, BtcExplorer: BtcExplorer, @@ -50,7 +50,7 @@ func (c *Config) Save() error { if err != nil { return err } - err = os.WriteFile(defaultCfgFileName, file, 0644) + err = os.WriteFile(defaultCfgFileName, file, 0600) return err } diff --git a/cmd/zetatool/filterdeposit/btc.go b/cmd/zetatool/filterdeposit/btc.go index 579fb9c97e..f1d9bee836 100644 --- a/cmd/zetatool/filterdeposit/btc.go +++ b/cmd/zetatool/filterdeposit/btc.go @@ -39,8 +39,8 @@ func FilterBTCTransactions(cmd *cobra.Command, _ []string) { CheckForCCTX(list, cfg) } -func getHashList(cfg *config.Config) []deposit { - var list []deposit +func getHashList(cfg *config.Config) []Deposit { + var list []Deposit lastHash := "" url := cfg.BtcExplorer @@ -51,6 +51,7 @@ func getHashList(cfg *config.Config) []deposit { path := fmt.Sprintf("/chain/%s", lastHash) nextQuery = url + path } + // #nosec G107 url must be variable res, getErr := http.Get(nextQuery) if getErr != nil { log.Fatal(getErr) @@ -60,6 +61,10 @@ func getHashList(cfg *config.Config) []deposit { if readErr != nil { log.Fatal(readErr) } + closeErr := res.Body.Close() + if closeErr != nil { + log.Fatal(closeErr) + } var txns []map[string]interface{} err := json.Unmarshal(body, &txns) @@ -107,7 +112,7 @@ func getHashList(cfg *config.Config) []deposit { continue } - //Check if deposit is a donation + //Check if Deposit is a donation scriptpubkey1 := vout1["scriptpubkey"].(string) if len(scriptpubkey1) >= 4 && scriptpubkey1[:2] == "6a" { memoSize, err := strconv.ParseInt(scriptpubkey1[2:4], 16, 32) @@ -128,9 +133,9 @@ func getHashList(cfg *config.Config) []deposit { continue } - //Make sure deposit is sent to correct tss address + //Make sure Deposit is sent to correct tss address if strings.Compare("0014", scriptpubkey[:4]) == 0 && targetAddr == cfg.TssAddressBTC { - entry := deposit{ + entry := Deposit{ hash, vout0["value"].(float64), } diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go index e4ded1b713..f49c0860a9 100644 --- a/cmd/zetatool/filterdeposit/evm.go +++ b/cmd/zetatool/filterdeposit/evm.go @@ -47,7 +47,7 @@ func FilterEVMTransactions(cmd *cobra.Command, _ []string) { CheckForCCTX(list, cfg) } -func GetEthHashList(cfg *config.Config) []deposit { +func GetEthHashList(cfg *config.Config) []Deposit { startBlock := cfg.EvmStartBlock client, err := ethclient.Dial(cfg.EthRPC) if err != nil { @@ -63,7 +63,7 @@ func GetEthHashList(cfg *config.Config) []deposit { fmt.Println("latest Block: ", latestBlock) endBlock := startBlock + cfg.EvmMaxRange - deposits := make([]deposit, 0) + deposits := make([]Deposit, 0) segment := 0 for startBlock < latestBlock { fmt.Printf("adding segment: %d, startblock: %d\n", segment, startBlock) @@ -78,8 +78,8 @@ func GetEthHashList(cfg *config.Config) []deposit { return deposits } -func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock uint64, cfg *config.Config) []deposit { - deposits := make([]deposit, 0) +func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock uint64, cfg *config.Config) []Deposit { + deposits := make([]Deposit, 0) connectorAddress := common.HexToAddress(cfg.ConnectorAddress) connectorContract, err := zetaconnector.NewZetaConnectorNonEth(connectorAddress, client) @@ -112,15 +112,15 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui return deposits } - // ********************** Get ERC20 Custody deposit events + // ********************** Get ERC20 Custody Deposit events for custodyIter.Next() { // sanity check tx event err := CheckEvmTxLog(&custodyIter.Event.Raw, erc20CustodyAddress, "", TopicsDeposited) if err == nil { //fmt.Println("adding deposits") - deposits = append(deposits, deposit{ - txId: custodyIter.Event.Raw.TxHash.Hex(), - amount: float64(custodyIter.Event.Amount.Int64()), + deposits = append(deposits, Deposit{ + TxID: custodyIter.Event.Raw.TxHash.Hex(), + Amount: float64(custodyIter.Event.Amount.Int64()), }) } } @@ -131,9 +131,9 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui err := CheckEvmTxLog(&connectorIter.Event.Raw, connectorAddress, "", TopicsZetaSent) if err == nil { //fmt.Println("adding deposits") - deposits = append(deposits, deposit{ - txId: connectorIter.Event.Raw.TxHash.Hex(), - amount: float64(connectorIter.Event.ZetaValueAndGas.Int64()), + deposits = append(deposits, Deposit{ + TxID: connectorIter.Event.Raw.TxHash.Hex(), + Amount: float64(connectorIter.Event.ZetaValueAndGas.Int64()), }) } } @@ -148,9 +148,9 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui return deposits } -func getTSSDeposits(tssAddress string, startBlock int, endBlock int) ([]deposit, error) { +func getTSSDeposits(tssAddress string, startBlock int, endBlock int) ([]Deposit, error) { client := etherscan.New(etherscan.Mainnet, "S3AVTNXDJQZQQUVXJM4XVIPBRYECGK88VX") - deposits := make([]deposit, 0) + deposits := make([]Deposit, 0) txns, err := client.NormalTxByAddress(tssAddress, &startBlock, &endBlock, 0, 0, true) if err != nil { @@ -167,10 +167,10 @@ func getTSSDeposits(tssAddress string, startBlock int, endBlock int) ([]deposit, if tx.TxReceiptStatus != "1" { continue } - //fmt.Println("getTSSDeposits - adding deposit") - deposits = append(deposits, deposit{ - txId: tx.Hash, - amount: float64(tx.Value.Int().Int64()), + //fmt.Println("getTSSDeposits - adding Deposit") + deposits = append(deposits, Deposit{ + TxID: tx.Hash, + Amount: float64(tx.Value.Int().Int64()), }) } } diff --git a/cmd/zetatool/filterdeposit/filterdeposit.go b/cmd/zetatool/filterdeposit/filterdeposit.go index c97ef7edd5..29792c3a39 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit.go +++ b/cmd/zetatool/filterdeposit/filterdeposit.go @@ -17,21 +17,22 @@ var Cmd = &cobra.Command{ Short: "filter missing inbound deposits", } -type deposit struct { - txId string - amount float64 +type Deposit struct { + TxID string + Amount float64 } -func CheckForCCTX(list []deposit, cfg *config.Config) { - var missedList []deposit +func CheckForCCTX(list []Deposit, cfg *config.Config) { + var missedList []Deposit fmt.Println("Going through list, num of transactions: ", len(list)) for _, entry := range list { - zetaUrl, err := url.JoinPath(cfg.ZetaUrl, "zeta-chain", "crosschain", "in_tx_hash_to_cctx_data", entry.txId) + zetaURL, err := url.JoinPath(cfg.ZetaURL, "zeta-chain", "crosschain", "in_tx_hash_to_cctx_data", entry.TxID) if err != nil { log.Fatal(err) } - res, getErr := http.Get(zetaUrl) + // #nosec G107 url must be variable + res, getErr := http.Get(zetaURL) if getErr != nil { log.Fatal(getErr) } @@ -40,6 +41,10 @@ func CheckForCCTX(list []deposit, cfg *config.Config) { if readErr != nil { log.Fatal(readErr) } + closeErr := res.Body.Close() + if closeErr != nil { + log.Fatal(closeErr) + } var cctx map[string]interface{} err = json.Unmarshal(data, &cctx) @@ -54,6 +59,6 @@ func CheckForCCTX(list []deposit, cfg *config.Config) { } for _, entry := range missedList { - fmt.Printf("%s, amount: %d\n", entry.txId, int64(entry.amount)) + fmt.Printf("%s, amount: %d\n", entry.TxID, int64(entry.Amount)) } } diff --git a/cmd/zetatool/main.go b/cmd/zetatool/main.go index 7eef1865a5..b648c26fd0 100644 --- a/cmd/zetatool/main.go +++ b/cmd/zetatool/main.go @@ -2,10 +2,11 @@ package main import ( "fmt" + "os" + "github.com/spf13/cobra" "github.com/zeta-chain/zetacore/cmd/zetatool/config" "github.com/zeta-chain/zetacore/cmd/zetatool/filterdeposit" - "os" ) var rootCmd = &cobra.Command{ From 62b3f1c3cc8396d39f8e3f4b4b446a4c5bc88cfd Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Tue, 12 Mar 2024 19:07:55 -0400 Subject: [PATCH 04/16] add unit tests for config package --- cmd/zetatool/config/config.go | 31 ++++++------ cmd/zetatool/config/config_test.go | 80 ++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 14 deletions(-) create mode 100644 cmd/zetatool/config/config_test.go diff --git a/cmd/zetatool/config/config.go b/cmd/zetatool/config/config.go index eac4d4e2f7..1fbf991a66 100644 --- a/cmd/zetatool/config/config.go +++ b/cmd/zetatool/config/config.go @@ -2,21 +2,24 @@ package config import ( "encoding/json" - "os" + + "github.com/spf13/afero" ) +var AppFs = afero.NewOsFs() + const ( - Flag = "config" - defaultCfgFileName = "InboundTxFilter_config.json" - ZetaURL = "http://46.4.15.110:1317" //http://100.71.167.102:26657 - TssAddressBTC = "bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y" - TssAddressEVM = "0x70e967acfcc17c3941e87562161406d41676fd83" - BtcExplorer = "https://blockstream.info/api/address/bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y/txs" - EthRPC = "https://rpc.ankr.com/eth/2da24e4a1fd28f2bec1569eceb2c38a5694b7f5c83fd24c69ae714a89a514f9b" - ConnectorAddress = "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a" - CustodyAddress = "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10" - EvmStartBlock = 19200110 - EvmMaxRange = 1000 + Flag = "config" + defaultCfgFileName = "InboundTxFilter_config.json" + ZetaURL = "http://46.4.15.110:1317" //http://100.71.167.102:26657 + TssAddressBTC = "bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y" + TssAddressEVM = "0x70e967acfcc17c3941e87562161406d41676fd83" + BtcExplorer = "https://blockstream.info/api/address/bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y/txs" + EthRPC = "https://rpc.ankr.com/eth/2da24e4a1fd28f2bec1569eceb2c38a5694b7f5c83fd24c69ae714a89a514f9b" + ConnectorAddress = "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a" + CustodyAddress = "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10" + EvmStartBlock uint64 = 19200110 + EvmMaxRange uint64 = 1000 ) type Config struct { @@ -50,12 +53,12 @@ func (c *Config) Save() error { if err != nil { return err } - err = os.WriteFile(defaultCfgFileName, file, 0600) + err = afero.WriteFile(AppFs, defaultCfgFileName, file, 0600) return err } func (c *Config) Read(filename string) error { - data, err := os.ReadFile(filename) + data, err := afero.ReadFile(AppFs, filename) if err != nil { return err } diff --git a/cmd/zetatool/config/config_test.go b/cmd/zetatool/config/config_test.go new file mode 100644 index 0000000000..1dda4936ce --- /dev/null +++ b/cmd/zetatool/config/config_test.go @@ -0,0 +1,80 @@ +package config + +import ( + "github.com/spf13/afero" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDefaultConfig(t *testing.T) { + cfg := DefaultConfig() + require.Equal(t, cfg.EthRPC, EthRPC) + require.Equal(t, cfg.ZetaURL, ZetaURL) + require.Equal(t, cfg.TssAddressBTC, TssAddressBTC) + require.Equal(t, cfg.TssAddressEVM, TssAddressEVM) + require.Equal(t, cfg.BtcExplorer, BtcExplorer) + require.Equal(t, cfg.ConnectorAddress, ConnectorAddress) + require.Equal(t, cfg.CustodyAddress, CustodyAddress) + require.Equal(t, cfg.EvmStartBlock, EvmStartBlock) + require.Equal(t, cfg.EvmMaxRange, EvmMaxRange) +} + +func TestGetConfig(t *testing.T) { + AppFs = afero.NewMemMapFs() + defaultCfg := DefaultConfig() + + t.Run("No config file specified", func(t *testing.T) { + cfg, err := GetConfig("") + require.NoError(t, err) + require.Equal(t, cfg, defaultCfg) + + exists, err := afero.Exists(AppFs, defaultCfgFileName) + require.NoError(t, err) + require.True(t, exists) + }) + + t.Run("config file specified", func(t *testing.T) { + cfg, err := GetConfig(defaultCfgFileName) + require.NoError(t, err) + require.Equal(t, cfg, defaultCfg) + }) +} + +func TestConfig_Read(t *testing.T) { + AppFs = afero.NewMemMapFs() + cfg, err := GetConfig("") + require.NoError(t, err) + + t.Run("read existing file", func(t *testing.T) { + c := &Config{} + err := c.Read(defaultCfgFileName) + require.NoError(t, err) + require.Equal(t, c, cfg) + }) + + t.Run("read non-existent file", func(t *testing.T) { + err := AppFs.Remove(defaultCfgFileName) + require.NoError(t, err) + c := &Config{} + err = c.Read(defaultCfgFileName) + require.ErrorContains(t, err, "file does not exist") + require.NotEqual(t, c, cfg) + }) +} + +func TestConfig_Save(t *testing.T) { + AppFs = afero.NewMemMapFs() + cfg := DefaultConfig() + cfg.EvmMaxRange = uint64(2000) + + t.Run("save modified cfg", func(t *testing.T) { + err := cfg.Save() + require.NoError(t, err) + + newCfg, err := GetConfig(defaultCfgFileName) + require.NoError(t, err) + require.Equal(t, cfg, newCfg) + }) + + // Should test invalid json encoding but currently not able to without interface +} From 3741ecc98de860fcc20ea6a3dd047e2436f4d479 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Wed, 13 Mar 2024 13:06:03 -0400 Subject: [PATCH 05/16] fix some gosec issues --- cmd/zetatool/filterdeposit/btc.go | 3 ++- cmd/zetatool/filterdeposit/evm.go | 18 +++++++++++------- cmd/zetatool/filterdeposit/filterdeposit.go | 4 ++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/cmd/zetatool/filterdeposit/btc.go b/cmd/zetatool/filterdeposit/btc.go index f1d9bee836..4606182784 100644 --- a/cmd/zetatool/filterdeposit/btc.go +++ b/cmd/zetatool/filterdeposit/btc.go @@ -137,7 +137,8 @@ func getHashList(cfg *config.Config) []Deposit { if strings.Compare("0014", scriptpubkey[:4]) == 0 && targetAddr == cfg.TssAddressBTC { entry := Deposit{ hash, - vout0["value"].(float64), + // #nosec G701 parsing json requires float64 type from blockstream + uint64(vout0["value"].(float64)), } list = append(list, entry) } diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go index f49c0860a9..5fdb4479ad 100644 --- a/cmd/zetatool/filterdeposit/evm.go +++ b/cmd/zetatool/filterdeposit/evm.go @@ -59,7 +59,7 @@ func GetEthHashList(cfg *config.Config) []Deposit { if err != nil { log.Fatal(err) } - latestBlock := uint64(header.Number.Int64()) + latestBlock := header.Number.Uint64() fmt.Println("latest Block: ", latestBlock) endBlock := startBlock + cfg.EvmMaxRange @@ -120,7 +120,7 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui //fmt.Println("adding deposits") deposits = append(deposits, Deposit{ TxID: custodyIter.Event.Raw.TxHash.Hex(), - Amount: float64(custodyIter.Event.Amount.Int64()), + Amount: custodyIter.Event.Amount.Uint64(), }) } } @@ -133,13 +133,13 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui //fmt.Println("adding deposits") deposits = append(deposits, Deposit{ TxID: connectorIter.Event.Raw.TxHash.Hex(), - Amount: float64(connectorIter.Event.ZetaValueAndGas.Int64()), + Amount: connectorIter.Event.ZetaValueAndGas.Uint64(), }) } } //********************** Get Transactions sent directly to TSS address - tssDeposits, err := getTSSDeposits(cfg.TssAddressEVM, int(startBlock), int(endBlock)) + tssDeposits, err := getTSSDeposits(cfg.TssAddressEVM, startBlock, endBlock) if err != nil { fmt.Printf("getTSSDeposits returned err: %s", err.Error()) } @@ -148,11 +148,15 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui return deposits } -func getTSSDeposits(tssAddress string, startBlock int, endBlock int) ([]Deposit, error) { +func getTSSDeposits(tssAddress string, startBlock uint64, endBlock uint64) ([]Deposit, error) { client := etherscan.New(etherscan.Mainnet, "S3AVTNXDJQZQQUVXJM4XVIPBRYECGK88VX") deposits := make([]Deposit, 0) - txns, err := client.NormalTxByAddress(tssAddress, &startBlock, &endBlock, 0, 0, true) + // #nosec G701 these block numbers need to be *int for this particular client package + startInt := int(startBlock) + // #nosec G701 + endInt := int(endBlock) + txns, err := client.NormalTxByAddress(tssAddress, &startInt, &endInt, 0, 0, true) if err != nil { return deposits, err } @@ -170,7 +174,7 @@ func getTSSDeposits(tssAddress string, startBlock int, endBlock int) ([]Deposit, //fmt.Println("getTSSDeposits - adding Deposit") deposits = append(deposits, Deposit{ TxID: tx.Hash, - Amount: float64(tx.Value.Int().Int64()), + Amount: tx.Value.Int().Uint64(), }) } } diff --git a/cmd/zetatool/filterdeposit/filterdeposit.go b/cmd/zetatool/filterdeposit/filterdeposit.go index 29792c3a39..9f2cef1ef0 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit.go +++ b/cmd/zetatool/filterdeposit/filterdeposit.go @@ -19,7 +19,7 @@ var Cmd = &cobra.Command{ type Deposit struct { TxID string - Amount float64 + Amount uint64 } func CheckForCCTX(list []Deposit, cfg *config.Config) { @@ -59,6 +59,6 @@ func CheckForCCTX(list []Deposit, cfg *config.Config) { } for _, entry := range missedList { - fmt.Printf("%s, amount: %d\n", entry.TxID, int64(entry.Amount)) + fmt.Printf("%s, amount: %d\n", entry.TxID, entry.Amount) } } From 8a370e747a1c7ca684f6bdad58344d7f8387ac02 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Wed, 13 Mar 2024 13:15:01 -0400 Subject: [PATCH 06/16] ran make generate --- cmd/zetatool/config/config_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/zetatool/config/config_test.go b/cmd/zetatool/config/config_test.go index 1dda4936ce..7f4f982bb6 100644 --- a/cmd/zetatool/config/config_test.go +++ b/cmd/zetatool/config/config_test.go @@ -1,9 +1,10 @@ package config import ( + "testing" + "github.com/spf13/afero" "github.com/stretchr/testify/require" - "testing" ) func TestDefaultConfig(t *testing.T) { From 638b81407202230483e07d2e7124783e3a5a2bc3 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Wed, 13 Mar 2024 13:39:18 -0400 Subject: [PATCH 07/16] added comments --- cmd/zetatool/filterdeposit/btc.go | 6 ++++++ cmd/zetatool/filterdeposit/evm.go | 6 ++++++ cmd/zetatool/filterdeposit/filterdeposit.go | 6 +++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cmd/zetatool/filterdeposit/btc.go b/cmd/zetatool/filterdeposit/btc.go index 4606182784..35c7d4fde6 100644 --- a/cmd/zetatool/filterdeposit/btc.go +++ b/cmd/zetatool/filterdeposit/btc.go @@ -25,6 +25,8 @@ func init() { Cmd.AddCommand(btcCmd) } +// FilterBTCTransactions is a command that queries the bitcoin explorer for inbound transactions that qualify for +// cross chain transactions. func FilterBTCTransactions(cmd *cobra.Command, _ []string) { configFile, err := cmd.Flags().GetString(config.Flag) fmt.Println("config file name: ", configFile) @@ -39,6 +41,7 @@ func FilterBTCTransactions(cmd *cobra.Command, _ []string) { CheckForCCTX(list, cfg) } +// getHashList is called by FilterBTCTransactions to help query and filter inbound transactions on btc func getHashList(cfg *config.Config) []Deposit { var list []Deposit lastHash := "" @@ -66,6 +69,9 @@ func getHashList(cfg *config.Config) []Deposit { log.Fatal(closeErr) } + // NOTE: decoding json from request dynamically is not ideal, however there isn't a detailed, defined data structure + // provided by blockstream. Will need to create one in the future using following definition: + // https://github.com/Blockstream/esplora/blob/master/API.md#transaction-format var txns []map[string]interface{} err := json.Unmarshal(body, &txns) if err != nil { diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go index 5fdb4479ad..7cd596188d 100644 --- a/cmd/zetatool/filterdeposit/evm.go +++ b/cmd/zetatool/filterdeposit/evm.go @@ -34,6 +34,8 @@ func init() { Cmd.AddCommand(evmCmd) } +// FilterEVMTransactions is a command that queries an EVM explorer and Contracts for inbound transactions that qualify +// for cross chain transactions. func FilterEVMTransactions(cmd *cobra.Command, _ []string) { configFile, err := cmd.Flags().GetString(config.Flag) if err != nil { @@ -47,6 +49,7 @@ func FilterEVMTransactions(cmd *cobra.Command, _ []string) { CheckForCCTX(list, cfg) } +// GetEthHashList is a helper function querying total inbound txns in segments of blocks in ranges defined by the config func GetEthHashList(cfg *config.Config) []Deposit { startBlock := cfg.EvmStartBlock client, err := ethclient.Dial(cfg.EthRPC) @@ -78,6 +81,7 @@ func GetEthHashList(cfg *config.Config) []Deposit { return deposits } +// GetHashListSegment queries and filters deposits for a given range func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock uint64, cfg *config.Config) []Deposit { deposits := make([]Deposit, 0) @@ -148,6 +152,7 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui return deposits } +// getTSSDeposits more specifically queries and filters deposits based on direct transfers the TSS address. func getTSSDeposits(tssAddress string, startBlock uint64, endBlock uint64) ([]Deposit, error) { client := etherscan.New(etherscan.Mainnet, "S3AVTNXDJQZQQUVXJM4XVIPBRYECGK88VX") deposits := make([]Deposit, 0) @@ -182,6 +187,7 @@ func getTSSDeposits(tssAddress string, startBlock uint64, endBlock uint64) ([]De return deposits, nil } +// CheckEvmTxLog is a helper function used to validate receipts, logic is taken from zetaclient. func CheckEvmTxLog(vLog *ethtypes.Log, wantAddress common.Address, wantHash string, wantTopics int) error { if vLog.Removed { return fmt.Errorf("log is removed, chain reorg?") diff --git a/cmd/zetatool/filterdeposit/filterdeposit.go b/cmd/zetatool/filterdeposit/filterdeposit.go index 9f2cef1ef0..ba8798f470 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit.go +++ b/cmd/zetatool/filterdeposit/filterdeposit.go @@ -17,11 +17,14 @@ var Cmd = &cobra.Command{ Short: "filter missing inbound deposits", } +// Deposit is a data structure for keeping track of inbound transactions type Deposit struct { TxID string Amount uint64 } +// CheckForCCTX is querying zeta core for a cctx associated with a confirmed transaction hash. If the cctx is not found, +// then the transaction hash is added to the list of missed inbound transactions. func CheckForCCTX(list []Deposit, cfg *config.Config) { var missedList []Deposit @@ -52,9 +55,10 @@ func CheckForCCTX(list []Deposit, cfg *config.Config) { fmt.Println("error unmarshalling: ", err.Error()) } + // successful query of the given cctx will not contain a "code" field, therefore if it exists then the cctx + // was not found and is added to the missing list. if _, ok := cctx["code"]; ok { missedList = append(missedList, entry) - //fmt.Println("appending to missed list: ", entry) } } From 331ab6340b36f38222639a4e2cf08147c2d5f5f6 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Wed, 13 Mar 2024 15:34:48 -0400 Subject: [PATCH 08/16] added tests for filterdeposit.go --- cmd/zetatool/filterdeposit/evm.go | 2 +- cmd/zetatool/filterdeposit/filterdeposit.go | 29 +++++++--- .../filterdeposit/filterdeposit_test.go | 57 +++++++++++++++++++ 3 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 cmd/zetatool/filterdeposit/filterdeposit_test.go diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go index 7cd596188d..a16482186d 100644 --- a/cmd/zetatool/filterdeposit/evm.go +++ b/cmd/zetatool/filterdeposit/evm.go @@ -49,7 +49,7 @@ func FilterEVMTransactions(cmd *cobra.Command, _ []string) { CheckForCCTX(list, cfg) } -// GetEthHashList is a helper function querying total inbound txns in segments of blocks in ranges defined by the config +// GetEthHashList is a helper function querying total inbound txns by segments of blocks in ranges defined by the config func GetEthHashList(cfg *config.Config) []Deposit { startBlock := cfg.EvmStartBlock client, err := ethclient.Dial(cfg.EthRPC) diff --git a/cmd/zetatool/filterdeposit/filterdeposit.go b/cmd/zetatool/filterdeposit/filterdeposit.go index ba8798f470..e7e2091fd5 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit.go +++ b/cmd/zetatool/filterdeposit/filterdeposit.go @@ -7,6 +7,7 @@ import ( "log" "net/http" "net/url" + "strings" "github.com/spf13/cobra" "github.com/zeta-chain/zetacore/cmd/zetatool/config" @@ -25,7 +26,7 @@ type Deposit struct { // CheckForCCTX is querying zeta core for a cctx associated with a confirmed transaction hash. If the cctx is not found, // then the transaction hash is added to the list of missed inbound transactions. -func CheckForCCTX(list []Deposit, cfg *config.Config) { +func CheckForCCTX(list []Deposit, cfg *config.Config) []Deposit { var missedList []Deposit fmt.Println("Going through list, num of transactions: ", len(list)) @@ -34,17 +35,24 @@ func CheckForCCTX(list []Deposit, cfg *config.Config) { if err != nil { log.Fatal(err) } - // #nosec G107 url must be variable - res, getErr := http.Get(zetaURL) + + request, err := http.NewRequest(http.MethodGet, zetaURL, nil) + if err != nil { + log.Fatal(err) + } + request.Header.Add("Accept", "application/json") + client := &http.Client{} + + response, getErr := client.Do(request) if getErr != nil { log.Fatal(getErr) } - data, readErr := ioutil.ReadAll(res.Body) + data, readErr := ioutil.ReadAll(response.Body) if readErr != nil { log.Fatal(readErr) } - closeErr := res.Body.Close() + closeErr := response.Body.Close() if closeErr != nil { log.Fatal(closeErr) } @@ -55,14 +63,17 @@ func CheckForCCTX(list []Deposit, cfg *config.Config) { fmt.Println("error unmarshalling: ", err.Error()) } - // successful query of the given cctx will not contain a "code" field, therefore if it exists then the cctx - // was not found and is added to the missing list. - if _, ok := cctx["code"]; ok { - missedList = append(missedList, entry) + // successful query of the given cctx will not contain a "message" field with value "not found", if it was not + // found then it is added to the missing list. + if _, ok := cctx["message"]; ok { + if strings.Compare(cctx["message"].(string), "not found") == 0 { + missedList = append(missedList, entry) + } } } for _, entry := range missedList { fmt.Printf("%s, amount: %d\n", entry.TxID, entry.Amount) } + return missedList } diff --git a/cmd/zetatool/filterdeposit/filterdeposit_test.go b/cmd/zetatool/filterdeposit/filterdeposit_test.go new file mode 100644 index 0000000000..658db2f152 --- /dev/null +++ b/cmd/zetatool/filterdeposit/filterdeposit_test.go @@ -0,0 +1,57 @@ +package filterdeposit + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/cmd/zetatool/config" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestCheckForCCTX(t *testing.T) { + t.Run("no missed inbound txns found", func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/zeta-chain/crosschain/in_tx_hash_to_cctx_data/0x093f4ca4c1884df0fd9dd59b75979342ded29d3c9b6861644287a2e1417b9a39" { + t.Errorf("Expected to request '/zeta-chain', got: %s", r.URL.Path) + } + w.WriteHeader(http.StatusOK) + //Return CCtx + cctx := types.CrossChainTx{} + bytes, err := json.Marshal(cctx) + require.NoError(t, err) + _, err = w.Write(bytes) + require.NoError(t, err) + })) + defer server.Close() + + deposits := []Deposit{{ + TxID: "0x093f4ca4c1884df0fd9dd59b75979342ded29d3c9b6861644287a2e1417b9a39", + Amount: uint64(657177295293237048), + }} + cfg := config.DefaultConfig() + cfg.ZetaURL = server.URL + missedInbounds := CheckForCCTX(deposits, cfg) + require.Equal(t, 0, len(missedInbounds)) + }) + + t.Run("1 missed inbound txn found", func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, err := w.Write([]byte("{\n \"code\": 5,\n \"message\": \"not found\",\n \"details\": [\n ]\n}")) + require.NoError(t, err) + })) + defer server.Close() + + deposits := []Deposit{{ + TxID: "0x093f4ca4c1884df0fd9dd59b75979342ded29d3c9b6861644287a2e1417b9a39", + Amount: uint64(657177295293237048), + }} + cfg := config.DefaultConfig() + cfg.ZetaURL = server.URL + missedInbounds := CheckForCCTX(deposits, cfg) + require.Equal(t, 1, len(missedInbounds)) + }) +} From cf7a4aa75b877d51cad9538654709b35902ad7fc Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Thu, 14 Mar 2024 15:23:36 -0400 Subject: [PATCH 09/16] added targets and docs --- Makefile | 12 +++- cmd/zetatool/filterdeposit/evm.go | 2 +- cmd/zetatool/filterdeposit/filterdeposit.go | 1 + docs/cli/zetatool/filterdeposit.md | 24 +++++++ docs/cli/zetatool/readme.md | 63 +++++++++++++++++++ .../InboundTxFilter_config.json | 11 ++++ .../filter_missed_btc.sh | 3 + .../filter_missed_eth.sh | 3 + 8 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 docs/cli/zetatool/filterdeposit.md create mode 100644 docs/cli/zetatool/readme.md create mode 100644 tool/filter_missed_deposits/InboundTxFilter_config.json create mode 100755 tool/filter_missed_deposits/filter_missed_btc.sh create mode 100755 tool/filter_missed_deposits/filter_missed_eth.sh diff --git a/Makefile b/Makefile index f0913e5ca7..529738bedb 100644 --- a/Makefile +++ b/Makefile @@ -290,4 +290,14 @@ mainnet-bitcoind-node: cd contrib/mainnet/bitcoind && DOCKER_TAG=$(DOCKER_TAG) docker-compose up athens3-zetarpc-node: - cd contrib/athens3/zetacored && DOCKER_TAG=$(DOCKER_TAG) docker-compose up \ No newline at end of file + cd contrib/athens3/zetacored && DOCKER_TAG=$(DOCKER_TAG) docker-compose up + +############################################################################### +### Debug Tools ### +############################################################################### + +filter-missed-btc: install-zetatool + ./tool/filter_missed_deposits/filter_missed_btc.sh + +filter-missed-eth: install-zetatool + ./tool/filter_missed_deposits/filter_missed_eth.sh \ No newline at end of file diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go index a16482186d..ee43946400 100644 --- a/cmd/zetatool/filterdeposit/evm.go +++ b/cmd/zetatool/filterdeposit/evm.go @@ -25,7 +25,7 @@ const ( ) var evmCmd = &cobra.Command{ - Use: "evm", + Use: "eth", Short: "Filter inbound eth deposits", Run: FilterEVMTransactions, } diff --git a/cmd/zetatool/filterdeposit/filterdeposit.go b/cmd/zetatool/filterdeposit/filterdeposit.go index e7e2091fd5..98fda63943 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit.go +++ b/cmd/zetatool/filterdeposit/filterdeposit.go @@ -72,6 +72,7 @@ func CheckForCCTX(list []Deposit, cfg *config.Config) []Deposit { } } + fmt.Printf("Found %d missed transactions.\n", len(missedList)) for _, entry := range missedList { fmt.Printf("%s, amount: %d\n", entry.TxID, entry.Amount) } diff --git a/docs/cli/zetatool/filterdeposit.md b/docs/cli/zetatool/filterdeposit.md new file mode 100644 index 0000000000..475ca1b540 --- /dev/null +++ b/docs/cli/zetatool/filterdeposit.md @@ -0,0 +1,24 @@ +# filterdeposit + +Filter missing inbound deposits + +### Synopsis + +Filters relevant inbound transactions for a given network and attempts to find an associated cctx from the core. If a +cctx is not found, the associated transaction hash and amount is added to a list and displayed. + +``` +zetatool filterdeposit [command] +``` +### Options + +``` +Available Commands: +btc Filter inbound btc deposits +eth Filter inbound eth deposits +``` + +### Options inherited from parent commands +``` +--config string custom config file: --config filename.json +``` \ No newline at end of file diff --git a/docs/cli/zetatool/readme.md b/docs/cli/zetatool/readme.md new file mode 100644 index 0000000000..e83352bb15 --- /dev/null +++ b/docs/cli/zetatool/readme.md @@ -0,0 +1,63 @@ +# Zeta Tool + +Currently, has only one subcommand which finds inbound transactions or deposits that weren't observed on a particular +network. `filterdeposit` + +## Configuring + +#### RPC endpoints +Configuring the tool for specific networks will require different reliable endpoints. For example, if you wanted to +configure an ethereum rpc endpoint, then you will have to find an evm rpc endpoint for eth mainnet and set the field: +`EthRPC` + +#### Zeta URL +You will need to find an enpoint for zetachain and set the field: `ZetaURL` + +#### TSS Addresses +Depending on which network you are using, you will have to populate the tss addresses for both EVM and BTC using these +fields: `TssAddressBTC`, `TssAddressEVM` + +#### Contract Addresses +Depending on the network, connector and custody contract addresses must be set using these fields: `ConnectorAddress`, +`CustodyAddress` + +#### EVM Block Ranges +When filtering evm transactions, a range of blocks is required and to reduce runtime of the command, a suitable range +must be selected and set in these fields: `EvmStartBlock`, `EvmMaxRange` + +If a configuration file is not provided, a default config will be generated under the name +`InboundTxFilter_config.json`. Below is an example of a configuration file used for mainnet: + +```json +{ + "ZetaURL": "http://46.4.15.110:1317", + "TssAddressBTC": "bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y", + "TssAddressEVM": "0x70e967acfcc17c3941e87562161406d41676fd83", + "BtcExplorer": "https://blockstream.info/api/address/bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y/txs", + "EthRPC": "https://ethereum-rpc.publicnode.com", + "ConnectorAddress": "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a", + "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10", + "EvmStartBlock": 19200110, + "EvmMaxRange": 1000 +} +``` + +## Running Tool + +There are two targets available: + +``` +filter-missed-btc: install-zetatool + ./tool/filter_missed_deposits/filter_missed_btc.sh + +filter-missed-eth: install-zetatool + ./tool/filter_missed_deposits/filter_missed_eth.sh +``` + +Running the commands can be simply done through the makefile in the node repo: + +``` +make filter-missed-btc +or ... +make filter-missed-eth +``` \ No newline at end of file diff --git a/tool/filter_missed_deposits/InboundTxFilter_config.json b/tool/filter_missed_deposits/InboundTxFilter_config.json new file mode 100644 index 0000000000..5ccc92f6d2 --- /dev/null +++ b/tool/filter_missed_deposits/InboundTxFilter_config.json @@ -0,0 +1,11 @@ +{ + "ZetaURL": "http://46.4.15.110:1317", + "TssAddressBTC": "bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y", + "TssAddressEVM": "0x70e967acfcc17c3941e87562161406d41676fd83", + "BtcExplorer": "https://blockstream.info/api/address/bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y/txs", + "EthRPC": "https://ethereum-rpc.publicnode.com", + "ConnectorAddress": "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a", + "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10", + "EvmStartBlock": 19200110, + "EvmMaxRange": 1000 +} \ No newline at end of file diff --git a/tool/filter_missed_deposits/filter_missed_btc.sh b/tool/filter_missed_deposits/filter_missed_btc.sh new file mode 100755 index 0000000000..f654f9c32e --- /dev/null +++ b/tool/filter_missed_deposits/filter_missed_btc.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +zetatool filterdeposit btc --config ./tool/filter_missed_deposits/InboundTxFilter_config.json \ No newline at end of file diff --git a/tool/filter_missed_deposits/filter_missed_eth.sh b/tool/filter_missed_deposits/filter_missed_eth.sh new file mode 100755 index 0000000000..f8151bc81c --- /dev/null +++ b/tool/filter_missed_deposits/filter_missed_eth.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +zetatool filterdeposit eth --config ./tool/filter_missed_deposits/InboundTxFilter_config.json \ No newline at end of file From ed850893e7c363bb5ed1073bb80aaa059b730321 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Mon, 18 Mar 2024 16:54:46 -0400 Subject: [PATCH 10/16] addressed comments --- Makefile | 7 +- cmd/zetatool/config/config.go | 36 ++---- cmd/zetatool/config/config_test.go | 10 +- cmd/zetatool/filterdeposit/btc.go | 85 ++++++++---- cmd/zetatool/filterdeposit/evm.go | 122 +++++++++++------- cmd/zetatool/filterdeposit/filterdeposit.go | 64 +++++++-- .../filterdeposit/filterdeposit_test.go | 6 +- cmd/zetatool/main.go | 7 +- docs/cli/zetatool/filterdeposit.md | 2 +- docs/cli/zetatool/readme.md | 6 +- .../InboundTxFilter_config.json | 11 -- .../filter_missed_btc.sh | 3 - .../filter_missed_eth.sh | 3 - .../zetatool_config.json | 8 ++ 14 files changed, 226 insertions(+), 144 deletions(-) delete mode 100644 tool/filter_missed_deposits/InboundTxFilter_config.json delete mode 100755 tool/filter_missed_deposits/filter_missed_btc.sh delete mode 100755 tool/filter_missed_deposits/filter_missed_eth.sh create mode 100644 tool/filter_missed_deposits/zetatool_config.json diff --git a/Makefile b/Makefile index 529738bedb..9a4ccfe3fa 100644 --- a/Makefile +++ b/Makefile @@ -297,7 +297,10 @@ athens3-zetarpc-node: ############################################################################### filter-missed-btc: install-zetatool - ./tool/filter_missed_deposits/filter_missed_btc.sh + zetatool filterdeposit btc --config ./tool/filter_missed_deposits/zetatool_config.json filter-missed-eth: install-zetatool - ./tool/filter_missed_deposits/filter_missed_eth.sh \ No newline at end of file + zetatool filterdeposit eth \ + --config ./tool/filter_missed_deposits/zetatool_config.json \ + --evm-max-range 1000 \ + --evm-start-block 19464041 \ No newline at end of file diff --git a/cmd/zetatool/config/config.go b/cmd/zetatool/config/config.go index 1fbf991a66..6f3face04d 100644 --- a/cmd/zetatool/config/config.go +++ b/cmd/zetatool/config/config.go @@ -9,42 +9,32 @@ import ( var AppFs = afero.NewOsFs() const ( - Flag = "config" - defaultCfgFileName = "InboundTxFilter_config.json" - ZetaURL = "http://46.4.15.110:1317" //http://100.71.167.102:26657 - TssAddressBTC = "bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y" - TssAddressEVM = "0x70e967acfcc17c3941e87562161406d41676fd83" - BtcExplorer = "https://blockstream.info/api/address/bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y/txs" - EthRPC = "https://rpc.ankr.com/eth/2da24e4a1fd28f2bec1569eceb2c38a5694b7f5c83fd24c69ae714a89a514f9b" - ConnectorAddress = "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a" - CustodyAddress = "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10" - EvmStartBlock uint64 = 19200110 - EvmMaxRange uint64 = 1000 + FlagConfig = "config" + defaultCfgFileName = "zetatool_config.json" + ZetaURL = "127.0.0.1:1317" + BtcExplorerURL = "https://blockstream.info/api/" + EthRPCURL = "https://ethereum-rpc.publicnode.com" + ConnectorAddress = "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a" + CustodyAddress = "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10" ) +// Config is a struct the defines the configuration fields used by zetatool type Config struct { ZetaURL string - TssAddressBTC string - TssAddressEVM string - BtcExplorer string - EthRPC string + BtcExplorerURL string + EthRPCURL string + EtherscanAPIkey string ConnectorAddress string CustodyAddress string - EvmStartBlock uint64 - EvmMaxRange uint64 } func DefaultConfig() *Config { return &Config{ ZetaURL: ZetaURL, - TssAddressBTC: TssAddressBTC, - TssAddressEVM: TssAddressEVM, - BtcExplorer: BtcExplorer, - EthRPC: EthRPC, + BtcExplorerURL: BtcExplorerURL, + EthRPCURL: EthRPCURL, ConnectorAddress: ConnectorAddress, CustodyAddress: CustodyAddress, - EvmStartBlock: EvmStartBlock, - EvmMaxRange: EvmMaxRange, } } diff --git a/cmd/zetatool/config/config_test.go b/cmd/zetatool/config/config_test.go index 7f4f982bb6..dd56604d5f 100644 --- a/cmd/zetatool/config/config_test.go +++ b/cmd/zetatool/config/config_test.go @@ -9,15 +9,11 @@ import ( func TestDefaultConfig(t *testing.T) { cfg := DefaultConfig() - require.Equal(t, cfg.EthRPC, EthRPC) + require.Equal(t, cfg.EthRPCURL, EthRPCURL) require.Equal(t, cfg.ZetaURL, ZetaURL) - require.Equal(t, cfg.TssAddressBTC, TssAddressBTC) - require.Equal(t, cfg.TssAddressEVM, TssAddressEVM) - require.Equal(t, cfg.BtcExplorer, BtcExplorer) + require.Equal(t, cfg.BtcExplorerURL, BtcExplorerURL) require.Equal(t, cfg.ConnectorAddress, ConnectorAddress) require.Equal(t, cfg.CustodyAddress, CustodyAddress) - require.Equal(t, cfg.EvmStartBlock, EvmStartBlock) - require.Equal(t, cfg.EvmMaxRange, EvmMaxRange) } func TestGetConfig(t *testing.T) { @@ -66,7 +62,7 @@ func TestConfig_Read(t *testing.T) { func TestConfig_Save(t *testing.T) { AppFs = afero.NewMemMapFs() cfg := DefaultConfig() - cfg.EvmMaxRange = uint64(2000) + cfg.EtherscanAPIkey = "DIFFERENTAPIKEY" t.Run("save modified cfg", func(t *testing.T) { err := cfg.Save() diff --git a/cmd/zetatool/filterdeposit/btc.go b/cmd/zetatool/filterdeposit/btc.go index 35c7d4fde6..f479bd1bfc 100644 --- a/cmd/zetatool/filterdeposit/btc.go +++ b/cmd/zetatool/filterdeposit/btc.go @@ -6,67 +6,91 @@ import ( "encoding/json" "fmt" "io/ioutil" - "log" "net/http" + "net/url" "strconv" "strings" "github.com/spf13/cobra" "github.com/zeta-chain/zetacore/cmd/zetatool/config" + "github.com/zeta-chain/zetacore/common" ) -var btcCmd = &cobra.Command{ - Use: "btc", - Short: "Filter inbound btc deposits", - Run: FilterBTCTransactions, -} - -func init() { - Cmd.AddCommand(btcCmd) +func NewBtcCmd() *cobra.Command { + return &cobra.Command{ + Use: "btc", + Short: "Filter inbound btc deposits", + RunE: FilterBTCTransactions, + } } // FilterBTCTransactions is a command that queries the bitcoin explorer for inbound transactions that qualify for // cross chain transactions. -func FilterBTCTransactions(cmd *cobra.Command, _ []string) { - configFile, err := cmd.Flags().GetString(config.Flag) +func FilterBTCTransactions(cmd *cobra.Command, _ []string) error { + configFile, err := cmd.Flags().GetString(config.FlagConfig) fmt.Println("config file name: ", configFile) if err != nil { - log.Fatal(err) + return err + } + btcChainID, err := cmd.Flags().GetString(BTCChainIDFlag) + if err != nil { + return err } cfg, err := config.GetConfig(configFile) if err != nil { - log.Fatal(err) + return err + } + fmt.Println("getting tss Address") + res, err := getTssAddress(cfg, btcChainID) + if err != nil { + return err } - list := getHashList(cfg) - CheckForCCTX(list, cfg) + fmt.Println("got tss Address") + list, err := getHashList(cfg, res.Btc) + if err != nil { + return err + } + + _, err = CheckForCCTX(list, cfg) + return err } // getHashList is called by FilterBTCTransactions to help query and filter inbound transactions on btc -func getHashList(cfg *config.Config) []Deposit { +func getHashList(cfg *config.Config, tssAddress string) ([]Deposit, error) { var list []Deposit lastHash := "" - url := cfg.BtcExplorer + // Setup URL for query + btcURL, err := url.JoinPath(cfg.BtcExplorerURL, "address", tssAddress, "txs") + if err != nil { + return list, err + } + // This loop will query the bitcoin explorer for transactions associated with the TSS address. Since the api only + // allows a response of 25 transactions per request, several requests will be required in order to retrieve a + // complete list. for { - nextQuery := url + // The Next Query is determined by the last transaction hash provided by the previous response. + nextQuery := btcURL if lastHash != "" { - path := fmt.Sprintf("/chain/%s", lastHash) - nextQuery = url + path + nextQuery, err = url.JoinPath(btcURL, "chain", lastHash) + if err != nil { + return list, err + } } // #nosec G107 url must be variable res, getErr := http.Get(nextQuery) if getErr != nil { - log.Fatal(getErr) + return list, getErr } body, readErr := ioutil.ReadAll(res.Body) if readErr != nil { - log.Fatal(readErr) + return list, readErr } closeErr := res.Body.Close() if closeErr != nil { - log.Fatal(closeErr) + return list, closeErr } // NOTE: decoding json from request dynamically is not ideal, however there isn't a detailed, defined data structure @@ -75,7 +99,7 @@ func getHashList(cfg *config.Config) []Deposit { var txns []map[string]interface{} err := json.Unmarshal(body, &txns) if err != nil { - fmt.Println("error unmarshalling: ", err.Error()) + return list, err } if len(txns) == 0 { @@ -84,9 +108,15 @@ func getHashList(cfg *config.Config) []Deposit { fmt.Println("Length of txns: ", len(txns)) + // The "/address" blockstream api provides a maximum of 25 transactions associated with a given address. This + // loop will iterate over that list of transactions to determine whether each transaction can be considered + // a deposit to ZetaChain. for _, txn := range txns { + // Get tx hash of the current transaction hash := txn["txid"].(string) + // Read the first output of the transaction and parse the destination address. + // This address should be the TSS address. vout := txn["vout"].([]interface{}) vout0 := vout[0].(map[string]interface{}) var vout1 map[string]interface{} @@ -132,7 +162,7 @@ func getHashList(cfg *config.Config) []Deposit { if err != nil { continue } - if bytes.Equal(memoBytes, []byte(DonationMessage)) { + if bytes.Equal(memoBytes, []byte(common.DonationMessage)) { continue } } else { @@ -140,7 +170,7 @@ func getHashList(cfg *config.Config) []Deposit { } //Make sure Deposit is sent to correct tss address - if strings.Compare("0014", scriptpubkey[:4]) == 0 && targetAddr == cfg.TssAddressBTC { + if strings.Compare("0014", scriptpubkey[:4]) == 0 && targetAddr == tssAddress { entry := Deposit{ hash, // #nosec G701 parsing json requires float64 type from blockstream @@ -152,8 +182,7 @@ func getHashList(cfg *config.Config) []Deposit { lastTxn := txns[len(txns)-1] lastHash = lastTxn["txid"].(string) - //fmt.Println("last hash: ", lastHash) } - return list + return list, nil } diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go index ee43946400..7d7faf0b93 100644 --- a/cmd/zetatool/filterdeposit/evm.go +++ b/cmd/zetatool/filterdeposit/evm.go @@ -7,6 +7,8 @@ import ( "math/big" "strings" + "github.com/zeta-chain/zetacore/zetaclient/evm" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -16,84 +18,118 @@ import ( "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.non-eth.sol" "github.com/zeta-chain/zetacore/cmd/zetatool/config" + zetacommon "github.com/zeta-chain/zetacore/common" ) const ( - TopicsDeposited = 2 - TopicsZetaSent = 3 - DonationMessage = "I am rich!" + EvmMaxRangeFlag = "evm-max-range" + EvmStartBlockFlag = "evm-start-block" ) -var evmCmd = &cobra.Command{ - Use: "eth", - Short: "Filter inbound eth deposits", - Run: FilterEVMTransactions, -} +func NewEvmCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "eth", + Short: "Filter inbound eth deposits", + RunE: FilterEVMTransactions, + } + + cmd.Flags().Uint64(EvmMaxRangeFlag, 1000, "number of blocks to scan per iteration") + cmd.Flags().Uint64(EvmStartBlockFlag, 19463725, "block height to start scanning from") -func init() { - Cmd.AddCommand(evmCmd) + return cmd } // FilterEVMTransactions is a command that queries an EVM explorer and Contracts for inbound transactions that qualify // for cross chain transactions. -func FilterEVMTransactions(cmd *cobra.Command, _ []string) { - configFile, err := cmd.Flags().GetString(config.Flag) +func FilterEVMTransactions(cmd *cobra.Command, _ []string) error { + // Get flags + configFile, err := cmd.Flags().GetString(config.FlagConfig) if err != nil { - log.Fatal(err) + return err + } + startBlock, err := cmd.Flags().GetUint64(EvmStartBlockFlag) + if err != nil { + return err } + blockRange, err := cmd.Flags().GetUint64(EvmMaxRangeFlag) + if err != nil { + return err + } + btcChainID, err := cmd.Flags().GetString(BTCChainIDFlag) + if err != nil { + return err + } + // Scan for deposits cfg, err := config.GetConfig(configFile) if err != nil { log.Fatal(err) } - list := GetEthHashList(cfg) - CheckForCCTX(list, cfg) + res, err := getTssAddress(cfg, btcChainID) + if err != nil { + return err + } + list, err := GetEthHashList(cfg, res.Eth, startBlock, blockRange) + if err != nil { + return err + } + _, err = CheckForCCTX(list, cfg) + return nil } // GetEthHashList is a helper function querying total inbound txns by segments of blocks in ranges defined by the config -func GetEthHashList(cfg *config.Config) []Deposit { - startBlock := cfg.EvmStartBlock - client, err := ethclient.Dial(cfg.EthRPC) +func GetEthHashList(cfg *config.Config, tssAddress string, startBlock uint64, blockRange uint64) ([]Deposit, error) { + client, err := ethclient.Dial(cfg.EthRPCURL) if err != nil { - log.Fatal(err) + return []Deposit{}, err } fmt.Println("Connection successful") header, err := client.HeaderByNumber(context.Background(), nil) if err != nil { - log.Fatal(err) + return []Deposit{}, err } latestBlock := header.Number.Uint64() fmt.Println("latest Block: ", latestBlock) - endBlock := startBlock + cfg.EvmMaxRange + endBlock := startBlock + blockRange deposits := make([]Deposit, 0) segment := 0 for startBlock < latestBlock { fmt.Printf("adding segment: %d, startblock: %d\n", segment, startBlock) - deposits = append(deposits, GetHashListSegment(client, startBlock, endBlock, cfg)...) + segmentRes, err := GetHashListSegment(client, startBlock, endBlock, tssAddress, cfg) + if err != nil { + fmt.Println(err.Error()) + continue + } + deposits = append(deposits, segmentRes...) startBlock = endBlock - endBlock = endBlock + cfg.EvmMaxRange + endBlock = endBlock + blockRange if endBlock > latestBlock { endBlock = latestBlock } segment++ } - return deposits + return deposits, nil } // GetHashListSegment queries and filters deposits for a given range -func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock uint64, cfg *config.Config) []Deposit { - deposits := make([]Deposit, 0) +func GetHashListSegment( + client *ethclient.Client, + startBlock uint64, + endBlock uint64, + tssAddress string, + cfg *config.Config) ([]Deposit, error) { + deposits := make([]Deposit, 0) connectorAddress := common.HexToAddress(cfg.ConnectorAddress) connectorContract, err := zetaconnector.NewZetaConnectorNonEth(connectorAddress, client) if err != nil { - fmt.Println("error: ", err.Error()) + return deposits, err } erc20CustodyAddress := common.HexToAddress(cfg.CustodyAddress) erc20CustodyContract, err := erc20custody.NewERC20Custody(erc20CustodyAddress, client) if err != nil { - fmt.Println("error: ", err.Error()) + return deposits, err } custodyIter, err := erc20CustodyContract.FilterDeposited(&bind.FilterOpts{ @@ -102,8 +138,7 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui Context: context.TODO(), }, []common.Address{}) if err != nil { - fmt.Println("error loading filter: ", err.Error()) - return deposits + return deposits, err } connectorIter, err := connectorContract.FilterZetaSent(&bind.FilterOpts{ @@ -112,16 +147,14 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui Context: context.TODO(), }, []common.Address{}, []*big.Int{}) if err != nil { - fmt.Println("error loading filter: ", err.Error()) - return deposits + return deposits, err } - // ********************** Get ERC20 Custody Deposit events + // Get ERC20 Custody Deposit events for custodyIter.Next() { // sanity check tx event - err := CheckEvmTxLog(&custodyIter.Event.Raw, erc20CustodyAddress, "", TopicsDeposited) + err := CheckEvmTxLog(&custodyIter.Event.Raw, erc20CustodyAddress, "", evm.TopicsDeposited) if err == nil { - //fmt.Println("adding deposits") deposits = append(deposits, Deposit{ TxID: custodyIter.Event.Raw.TxHash.Hex(), Amount: custodyIter.Event.Amount.Uint64(), @@ -129,12 +162,11 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui } } - // ********************** Get Connector ZetaSent events + // Get Connector ZetaSent events for connectorIter.Next() { // sanity check tx event - err := CheckEvmTxLog(&connectorIter.Event.Raw, connectorAddress, "", TopicsZetaSent) + err := CheckEvmTxLog(&connectorIter.Event.Raw, connectorAddress, "", evm.TopicsZetaSent) if err == nil { - //fmt.Println("adding deposits") deposits = append(deposits, Deposit{ TxID: connectorIter.Event.Raw.TxHash.Hex(), Amount: connectorIter.Event.ZetaValueAndGas.Uint64(), @@ -142,19 +174,19 @@ func GetHashListSegment(client *ethclient.Client, startBlock uint64, endBlock ui } } - //********************** Get Transactions sent directly to TSS address - tssDeposits, err := getTSSDeposits(cfg.TssAddressEVM, startBlock, endBlock) + // Get Transactions sent directly to TSS address + tssDeposits, err := getTSSDeposits(tssAddress, startBlock, endBlock, cfg.EtherscanAPIkey) if err != nil { - fmt.Printf("getTSSDeposits returned err: %s", err.Error()) + return deposits, err } deposits = append(deposits, tssDeposits...) - return deposits + return deposits, nil } // getTSSDeposits more specifically queries and filters deposits based on direct transfers the TSS address. -func getTSSDeposits(tssAddress string, startBlock uint64, endBlock uint64) ([]Deposit, error) { - client := etherscan.New(etherscan.Mainnet, "S3AVTNXDJQZQQUVXJM4XVIPBRYECGK88VX") +func getTSSDeposits(tssAddress string, startBlock uint64, endBlock uint64, apiKey string) ([]Deposit, error) { + client := etherscan.New(etherscan.Mainnet, apiKey) deposits := make([]Deposit, 0) // #nosec G701 these block numbers need to be *int for this particular client package @@ -170,7 +202,7 @@ func getTSSDeposits(tssAddress string, startBlock uint64, endBlock uint64) ([]De for _, tx := range txns { if tx.To == tssAddress { - if strings.Compare(tx.Input, DonationMessage) == 0 { + if strings.Compare(tx.Input, zetacommon.DonationMessage) == 0 { continue // skip donation tx } if tx.TxReceiptStatus != "1" { diff --git a/cmd/zetatool/filterdeposit/filterdeposit.go b/cmd/zetatool/filterdeposit/filterdeposit.go index 98fda63943..428b5a6b60 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit.go +++ b/cmd/zetatool/filterdeposit/filterdeposit.go @@ -4,18 +4,32 @@ import ( "encoding/json" "fmt" "io/ioutil" - "log" "net/http" "net/url" "strings" "github.com/spf13/cobra" "github.com/zeta-chain/zetacore/cmd/zetatool/config" + "github.com/zeta-chain/zetacore/x/observer/types" ) -var Cmd = &cobra.Command{ - Use: "filterdeposit", - Short: "filter missing inbound deposits", +const ( + BTCChainIDFlag = "btc-chain-id" +) + +func NewFilterDepositCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "filterdeposit", + Short: "filter missing inbound deposits", + } + + cmd.AddCommand(NewBtcCmd()) + cmd.AddCommand(NewEvmCmd()) + + // Required for TSS address query + cmd.PersistentFlags().String(BTCChainIDFlag, "8332", "chain id used on zetachain to identify bitcoin - default: 8332") + + return cmd } // Deposit is a data structure for keeping track of inbound transactions @@ -26,41 +40,41 @@ type Deposit struct { // CheckForCCTX is querying zeta core for a cctx associated with a confirmed transaction hash. If the cctx is not found, // then the transaction hash is added to the list of missed inbound transactions. -func CheckForCCTX(list []Deposit, cfg *config.Config) []Deposit { +func CheckForCCTX(list []Deposit, cfg *config.Config) ([]Deposit, error) { var missedList []Deposit fmt.Println("Going through list, num of transactions: ", len(list)) for _, entry := range list { zetaURL, err := url.JoinPath(cfg.ZetaURL, "zeta-chain", "crosschain", "in_tx_hash_to_cctx_data", entry.TxID) if err != nil { - log.Fatal(err) + return missedList, err } request, err := http.NewRequest(http.MethodGet, zetaURL, nil) if err != nil { - log.Fatal(err) + return missedList, err } request.Header.Add("Accept", "application/json") client := &http.Client{} response, getErr := client.Do(request) if getErr != nil { - log.Fatal(getErr) + return missedList, getErr } data, readErr := ioutil.ReadAll(response.Body) if readErr != nil { - log.Fatal(readErr) + return missedList, readErr } closeErr := response.Body.Close() if closeErr != nil { - log.Fatal(closeErr) + return missedList, closeErr } var cctx map[string]interface{} err = json.Unmarshal(data, &cctx) if err != nil { - fmt.Println("error unmarshalling: ", err.Error()) + return missedList, err } // successful query of the given cctx will not contain a "message" field with value "not found", if it was not @@ -76,5 +90,31 @@ func CheckForCCTX(list []Deposit, cfg *config.Config) []Deposit { for _, entry := range missedList { fmt.Printf("%s, amount: %d\n", entry.TxID, entry.Amount) } - return missedList + return missedList, nil +} + +func getTssAddress(cfg *config.Config, btcChainID string) (*types.QueryGetTssAddressResponse, error) { + res := &types.QueryGetTssAddressResponse{} + requestURL, err := url.JoinPath(cfg.ZetaURL, "zeta-chain", "observer", "get_tss_address", btcChainID) + request, err := http.NewRequest(http.MethodGet, requestURL, nil) + if err != nil { + return res, err + } + request.Header.Add("Accept", "application/json") + zetacoreHttpClient := &http.Client{} + response, getErr := zetacoreHttpClient.Do(request) + if getErr != nil { + return res, err + } + data, readErr := ioutil.ReadAll(response.Body) + if readErr != nil { + return res, err + } + closeErr := response.Body.Close() + if closeErr != nil { + return res, closeErr + } + err = json.Unmarshal(data, res) + + return res, nil } diff --git a/cmd/zetatool/filterdeposit/filterdeposit_test.go b/cmd/zetatool/filterdeposit/filterdeposit_test.go index 658db2f152..847326a384 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit_test.go +++ b/cmd/zetatool/filterdeposit/filterdeposit_test.go @@ -33,7 +33,8 @@ func TestCheckForCCTX(t *testing.T) { }} cfg := config.DefaultConfig() cfg.ZetaURL = server.URL - missedInbounds := CheckForCCTX(deposits, cfg) + missedInbounds, err := CheckForCCTX(deposits, cfg) + require.NoError(t, err) require.Equal(t, 0, len(missedInbounds)) }) @@ -51,7 +52,8 @@ func TestCheckForCCTX(t *testing.T) { }} cfg := config.DefaultConfig() cfg.ZetaURL = server.URL - missedInbounds := CheckForCCTX(deposits, cfg) + missedInbounds, err := CheckForCCTX(deposits, cfg) + require.NoError(t, err) require.Equal(t, 1, len(missedInbounds)) }) } diff --git a/cmd/zetatool/main.go b/cmd/zetatool/main.go index b648c26fd0..584d21b747 100644 --- a/cmd/zetatool/main.go +++ b/cmd/zetatool/main.go @@ -4,9 +4,10 @@ import ( "fmt" "os" + "github.com/zeta-chain/zetacore/cmd/zetatool/filterdeposit" + "github.com/spf13/cobra" "github.com/zeta-chain/zetacore/cmd/zetatool/config" - "github.com/zeta-chain/zetacore/cmd/zetatool/filterdeposit" ) var rootCmd = &cobra.Command{ @@ -15,8 +16,8 @@ var rootCmd = &cobra.Command{ } func init() { - rootCmd.AddCommand(filterdeposit.Cmd) - rootCmd.PersistentFlags().String(config.Flag, "", "custom config file: --config filename.json") + rootCmd.AddCommand(filterdeposit.NewFilterDepositCmd()) + rootCmd.PersistentFlags().String(config.FlagConfig, "", "custom config file: --config filename.json") } func main() { diff --git a/docs/cli/zetatool/filterdeposit.md b/docs/cli/zetatool/filterdeposit.md index 475ca1b540..f70ead820d 100644 --- a/docs/cli/zetatool/filterdeposit.md +++ b/docs/cli/zetatool/filterdeposit.md @@ -4,7 +4,7 @@ Filter missing inbound deposits ### Synopsis -Filters relevant inbound transactions for a given network and attempts to find an associated cctx from the core. If a +Filters relevant inbound transactions for a given network and attempts to find an associated cctx from zetacore. If a cctx is not found, the associated transaction hash and amount is added to a list and displayed. ``` diff --git a/docs/cli/zetatool/readme.md b/docs/cli/zetatool/readme.md index e83352bb15..b5e4e8864a 100644 --- a/docs/cli/zetatool/readme.md +++ b/docs/cli/zetatool/readme.md @@ -26,14 +26,12 @@ When filtering evm transactions, a range of blocks is required and to reduce run must be selected and set in these fields: `EvmStartBlock`, `EvmMaxRange` If a configuration file is not provided, a default config will be generated under the name -`InboundTxFilter_config.json`. Below is an example of a configuration file used for mainnet: +`zetatool_config.json`. Below is an example of a configuration file used for mainnet: ```json { "ZetaURL": "http://46.4.15.110:1317", - "TssAddressBTC": "bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y", - "TssAddressEVM": "0x70e967acfcc17c3941e87562161406d41676fd83", - "BtcExplorer": "https://blockstream.info/api/address/bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y/txs", + "BtcExplorer": "https://blockstream.info/api/", "EthRPC": "https://ethereum-rpc.publicnode.com", "ConnectorAddress": "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a", "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10", diff --git a/tool/filter_missed_deposits/InboundTxFilter_config.json b/tool/filter_missed_deposits/InboundTxFilter_config.json deleted file mode 100644 index 5ccc92f6d2..0000000000 --- a/tool/filter_missed_deposits/InboundTxFilter_config.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "ZetaURL": "http://46.4.15.110:1317", - "TssAddressBTC": "bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y", - "TssAddressEVM": "0x70e967acfcc17c3941e87562161406d41676fd83", - "BtcExplorer": "https://blockstream.info/api/address/bc1qm24wp577nk8aacckv8np465z3dvmu7ry45el6y/txs", - "EthRPC": "https://ethereum-rpc.publicnode.com", - "ConnectorAddress": "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a", - "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10", - "EvmStartBlock": 19200110, - "EvmMaxRange": 1000 -} \ No newline at end of file diff --git a/tool/filter_missed_deposits/filter_missed_btc.sh b/tool/filter_missed_deposits/filter_missed_btc.sh deleted file mode 100755 index f654f9c32e..0000000000 --- a/tool/filter_missed_deposits/filter_missed_btc.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -zetatool filterdeposit btc --config ./tool/filter_missed_deposits/InboundTxFilter_config.json \ No newline at end of file diff --git a/tool/filter_missed_deposits/filter_missed_eth.sh b/tool/filter_missed_deposits/filter_missed_eth.sh deleted file mode 100755 index f8151bc81c..0000000000 --- a/tool/filter_missed_deposits/filter_missed_eth.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -zetatool filterdeposit eth --config ./tool/filter_missed_deposits/InboundTxFilter_config.json \ No newline at end of file diff --git a/tool/filter_missed_deposits/zetatool_config.json b/tool/filter_missed_deposits/zetatool_config.json new file mode 100644 index 0000000000..ca3b76984f --- /dev/null +++ b/tool/filter_missed_deposits/zetatool_config.json @@ -0,0 +1,8 @@ +{ + "ZetaURL": "http://46.4.15.110:1317", + "BtcExplorerURL": "https://blockstream.info/api/", + "EthRPCURL": "https://ethereum-rpc.publicnode.com", + "EtherscanAPIkey": "S3AVTNXDJQZQQUVXJM4XVIPBRYECGK88VX", + "ConnectorAddress": "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a", + "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10" +} \ No newline at end of file From 0e2d750e876c666944dc24509e259c9b3c77cda6 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Mon, 18 Mar 2024 16:57:23 -0400 Subject: [PATCH 11/16] removed sensitive data from sample config --- tool/filter_missed_deposits/zetatool_config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tool/filter_missed_deposits/zetatool_config.json b/tool/filter_missed_deposits/zetatool_config.json index ca3b76984f..f3189e52e0 100644 --- a/tool/filter_missed_deposits/zetatool_config.json +++ b/tool/filter_missed_deposits/zetatool_config.json @@ -1,8 +1,8 @@ { - "ZetaURL": "http://46.4.15.110:1317", + "ZetaURL": "127.0.0.1:1317", "BtcExplorerURL": "https://blockstream.info/api/", "EthRPCURL": "https://ethereum-rpc.publicnode.com", - "EtherscanAPIkey": "S3AVTNXDJQZQQUVXJM4XVIPBRYECGK88VX", + "EtherscanAPIkey": "", "ConnectorAddress": "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a", "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10" } \ No newline at end of file From 1223d284cf732f204a783a5df4246f3bf740f1c3 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Mon, 18 Mar 2024 17:01:48 -0400 Subject: [PATCH 12/16] ran make generate and lint --- cmd/zetatool/filterdeposit/evm.go | 2 +- cmd/zetatool/filterdeposit/filterdeposit.go | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go index 7d7faf0b93..1445eb4572 100644 --- a/cmd/zetatool/filterdeposit/evm.go +++ b/cmd/zetatool/filterdeposit/evm.go @@ -73,7 +73,7 @@ func FilterEVMTransactions(cmd *cobra.Command, _ []string) error { return err } _, err = CheckForCCTX(list, cfg) - return nil + return err } // GetEthHashList is a helper function querying total inbound txns by segments of blocks in ranges defined by the config diff --git a/cmd/zetatool/filterdeposit/filterdeposit.go b/cmd/zetatool/filterdeposit/filterdeposit.go index 428b5a6b60..237d5078be 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit.go +++ b/cmd/zetatool/filterdeposit/filterdeposit.go @@ -96,13 +96,16 @@ func CheckForCCTX(list []Deposit, cfg *config.Config) ([]Deposit, error) { func getTssAddress(cfg *config.Config, btcChainID string) (*types.QueryGetTssAddressResponse, error) { res := &types.QueryGetTssAddressResponse{} requestURL, err := url.JoinPath(cfg.ZetaURL, "zeta-chain", "observer", "get_tss_address", btcChainID) + if err != nil { + return res, err + } request, err := http.NewRequest(http.MethodGet, requestURL, nil) if err != nil { return res, err } request.Header.Add("Accept", "application/json") - zetacoreHttpClient := &http.Client{} - response, getErr := zetacoreHttpClient.Do(request) + zetacoreHTTPClient := &http.Client{} + response, getErr := zetacoreHTTPClient.Do(request) if getErr != nil { return res, err } @@ -115,6 +118,5 @@ func getTssAddress(cfg *config.Config, btcChainID string) (*types.QueryGetTssAdd return res, closeErr } err = json.Unmarshal(data, res) - - return res, nil + return res, err } From 048db16c92bc16e6c57094142b11a4c84591efc8 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Mon, 18 Mar 2024 18:44:51 -0400 Subject: [PATCH 13/16] added test case --- cmd/zetatool/filterdeposit/btc.go | 2 +- cmd/zetatool/filterdeposit/evm.go | 2 +- cmd/zetatool/filterdeposit/filterdeposit.go | 2 +- .../filterdeposit/filterdeposit_test.go | 38 +++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/cmd/zetatool/filterdeposit/btc.go b/cmd/zetatool/filterdeposit/btc.go index f479bd1bfc..bc2397523d 100644 --- a/cmd/zetatool/filterdeposit/btc.go +++ b/cmd/zetatool/filterdeposit/btc.go @@ -41,7 +41,7 @@ func FilterBTCTransactions(cmd *cobra.Command, _ []string) error { return err } fmt.Println("getting tss Address") - res, err := getTssAddress(cfg, btcChainID) + res, err := GetTssAddress(cfg, btcChainID) if err != nil { return err } diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go index 1445eb4572..73e1f8b78f 100644 --- a/cmd/zetatool/filterdeposit/evm.go +++ b/cmd/zetatool/filterdeposit/evm.go @@ -64,7 +64,7 @@ func FilterEVMTransactions(cmd *cobra.Command, _ []string) error { if err != nil { log.Fatal(err) } - res, err := getTssAddress(cfg, btcChainID) + res, err := GetTssAddress(cfg, btcChainID) if err != nil { return err } diff --git a/cmd/zetatool/filterdeposit/filterdeposit.go b/cmd/zetatool/filterdeposit/filterdeposit.go index 237d5078be..73a2601cd8 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit.go +++ b/cmd/zetatool/filterdeposit/filterdeposit.go @@ -93,7 +93,7 @@ func CheckForCCTX(list []Deposit, cfg *config.Config) ([]Deposit, error) { return missedList, nil } -func getTssAddress(cfg *config.Config, btcChainID string) (*types.QueryGetTssAddressResponse, error) { +func GetTssAddress(cfg *config.Config, btcChainID string) (*types.QueryGetTssAddressResponse, error) { res := &types.QueryGetTssAddressResponse{} requestURL, err := url.JoinPath(cfg.ZetaURL, "zeta-chain", "observer", "get_tss_address", btcChainID) if err != nil { diff --git a/cmd/zetatool/filterdeposit/filterdeposit_test.go b/cmd/zetatool/filterdeposit/filterdeposit_test.go index 847326a384..be915ddc2d 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit_test.go +++ b/cmd/zetatool/filterdeposit/filterdeposit_test.go @@ -2,6 +2,7 @@ package filterdeposit import ( "encoding/json" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" "net/http" "net/http/httptest" "testing" @@ -57,3 +58,40 @@ func TestCheckForCCTX(t *testing.T) { require.Equal(t, 1, len(missedInbounds)) }) } + +func TestGetTssAddress(t *testing.T) { + t.Run("should run successfully", func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/zeta-chain/observer/get_tss_address/8332" { + t.Errorf("Expected to request '/zeta-chain', got: %s", r.URL.Path) + } + w.WriteHeader(http.StatusOK) + response := observertypes.QueryGetTssAddressResponse{} + bytes, err := json.Marshal(response) + require.NoError(t, err) + _, err = w.Write(bytes) + require.NoError(t, err) + })) + cfg := config.DefaultConfig() + cfg.ZetaURL = server.URL + _, err := GetTssAddress(cfg, "8332") + require.NoError(t, err) + }) + + t.Run("bad request", func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/zeta-chain/observer/get_tss_address/8332" { + w.WriteHeader(http.StatusBadRequest) + response := observertypes.QueryGetTssAddressResponse{} + bytes, err := json.Marshal(response) + require.NoError(t, err) + _, err = w.Write(bytes) + require.NoError(t, err) + } + })) + cfg := config.DefaultConfig() + cfg.ZetaURL = server.URL + _, err := GetTssAddress(cfg, "8332") + require.Error(t, err) + }) +} From 5805c63f6f551a2b747e4f6e6f8628079d7026c0 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Tue, 19 Mar 2024 11:33:42 -0400 Subject: [PATCH 14/16] fix import format --- cmd/zetatool/filterdeposit/filterdeposit_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/zetatool/filterdeposit/filterdeposit_test.go b/cmd/zetatool/filterdeposit/filterdeposit_test.go index be915ddc2d..2140a43c08 100644 --- a/cmd/zetatool/filterdeposit/filterdeposit_test.go +++ b/cmd/zetatool/filterdeposit/filterdeposit_test.go @@ -2,7 +2,6 @@ package filterdeposit import ( "encoding/json" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" "net/http" "net/http/httptest" "testing" @@ -10,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/cmd/zetatool/config" "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) func TestCheckForCCTX(t *testing.T) { From 9d9fefad3df9c285a3e07704f0896c963be58934 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Tue, 19 Mar 2024 11:57:22 -0400 Subject: [PATCH 15/16] update docs --- docs/cli/zetatool/filterdeposit.md | 5 +++++ docs/cli/zetatool/readme.md | 20 +++++++------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/cli/zetatool/filterdeposit.md b/docs/cli/zetatool/filterdeposit.md index f70ead820d..cec577a1e1 100644 --- a/docs/cli/zetatool/filterdeposit.md +++ b/docs/cli/zetatool/filterdeposit.md @@ -18,6 +18,11 @@ btc Filter inbound btc deposits eth Filter inbound eth deposits ``` +### Flags +``` +--btc-chain-id string chain id used on zetachain to identify bitcoin - default: 8332 (default "8332") +``` + ### Options inherited from parent commands ``` --config string custom config file: --config filename.json diff --git a/docs/cli/zetatool/readme.md b/docs/cli/zetatool/readme.md index b5e4e8864a..1fe7fa0ec8 100644 --- a/docs/cli/zetatool/readme.md +++ b/docs/cli/zetatool/readme.md @@ -13,30 +13,24 @@ configure an ethereum rpc endpoint, then you will have to find an evm rpc endpoi #### Zeta URL You will need to find an enpoint for zetachain and set the field: `ZetaURL` -#### TSS Addresses -Depending on which network you are using, you will have to populate the tss addresses for both EVM and BTC using these -fields: `TssAddressBTC`, `TssAddressEVM` - #### Contract Addresses Depending on the network, connector and custody contract addresses must be set using these fields: `ConnectorAddress`, `CustodyAddress` -#### EVM Block Ranges -When filtering evm transactions, a range of blocks is required and to reduce runtime of the command, a suitable range -must be selected and set in these fields: `EvmStartBlock`, `EvmMaxRange` - If a configuration file is not provided, a default config will be generated under the name `zetatool_config.json`. Below is an example of a configuration file used for mainnet: -```json +#### Etherscan API Key +In order to make requests to etherscan, an api key will need to be configured. + +``` { - "ZetaURL": "http://46.4.15.110:1317", + "ZetaURL": "", "BtcExplorer": "https://blockstream.info/api/", "EthRPC": "https://ethereum-rpc.publicnode.com", "ConnectorAddress": "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a", - "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10", - "EvmStartBlock": 19200110, - "EvmMaxRange": 1000 + "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10", + "EtherscanAPIkey": "", } ``` From 10f618e57dca72532524235f1979bd60b4a13594 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Tue, 19 Mar 2024 12:02:38 -0400 Subject: [PATCH 16/16] update docs --- docs/cli/zetatool/readme.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/cli/zetatool/readme.md b/docs/cli/zetatool/readme.md index 1fe7fa0ec8..c35d5009a7 100644 --- a/docs/cli/zetatool/readme.md +++ b/docs/cli/zetatool/readme.md @@ -8,7 +8,7 @@ network. `filterdeposit` #### RPC endpoints Configuring the tool for specific networks will require different reliable endpoints. For example, if you wanted to configure an ethereum rpc endpoint, then you will have to find an evm rpc endpoint for eth mainnet and set the field: -`EthRPC` +`EthRPCURL` #### Zeta URL You will need to find an enpoint for zetachain and set the field: `ZetaURL` @@ -26,11 +26,11 @@ In order to make requests to etherscan, an api key will need to be configured. ``` { "ZetaURL": "", - "BtcExplorer": "https://blockstream.info/api/", - "EthRPC": "https://ethereum-rpc.publicnode.com", - "ConnectorAddress": "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a", - "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10", + "BtcExplorerURL": "https://blockstream.info/api/", + "EthRPCURL": "https://ethereum-rpc.publicnode.com", "EtherscanAPIkey": "", + "ConnectorAddress": "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a", + "CustodyAddress": "0x0000030Ec64DF25301d8414eE5a29588C4B0dE10" } ```