From 732b9e59b2d707994dae0f905f1c799fd617f2ba Mon Sep 17 00:00:00 2001 From: Agustin Pazos Date: Thu, 30 Nov 2023 11:22:20 -0300 Subject: [PATCH] Add comoshub support --- tx-tracker/chains/api_wormchain.go | 121 +++++++++++++++++++++++++++-- tx-tracker/chains/chains.go | 18 +++-- tx-tracker/config/structs.go | 2 + 3 files changed, 127 insertions(+), 14 deletions(-) diff --git a/tx-tracker/chains/api_wormchain.go b/tx-tracker/chains/api_wormchain.go index b65194b7..005d178f 100644 --- a/tx-tracker/chains/api_wormchain.go +++ b/tx-tracker/chains/api_wormchain.go @@ -12,13 +12,15 @@ import ( ) type apiWormchain struct { - osmosisUrl string - osmosisRateLimiter *time.Ticker - kujiraUrl string - kujiraRateLimiter *time.Ticker - evmosUrl string - evmosRateLimiter *time.Ticker - p2pNetwork string + osmosisUrl string + osmosisRateLimiter *time.Ticker + kujiraUrl string + kujiraRateLimiter *time.Ticker + evmosUrl string + evmosRateLimiter *time.Ticker + cosmoshubUrl string + cosmoshubRateLimiter *time.Ticker + p2pNetwork string } type wormchainTxDetail struct { @@ -366,6 +368,84 @@ func fetchKujiraDetail(ctx context.Context, baseUrl string, rateLimiter *time.Ti return &kujiraTx{txHash: strings.ToLower(kReponse.Result.Txs[0].Hash)}, nil } +type cosmoshubRequest struct { + Jsonrpc string `json:"jsonrpc"` + ID int `json:"id"` + Method string `json:"method"` + Params struct { + Query string `json:"query"` + Page string `json:"page"` + } `json:"params"` +} + +type cosmoshubResponse struct { + Jsonrpc string `json:"jsonrpc"` + ID int `json:"id"` + Result struct { + Txs []struct { + Hash string `json:"hash"` + Height string `json:"height"` + Index int `json:"index"` + TxResult struct { + Code int `json:"code"` + Data string `json:"data"` + Log string `json:"log"` + Info string `json:"info"` + GasWanted string `json:"gas_wanted"` + GasUsed string `json:"gas_used"` + Events []struct { + Type string `json:"type"` + Attributes []struct { + Key string `json:"key"` + Value string `json:"value"` + Index bool `json:"index"` + } `json:"attributes"` + } `json:"events"` + Codespace string `json:"codespace"` + } `json:"tx_result"` + Tx string `json:"tx"` + } `json:"txs"` + TotalCount string `json:"total_count"` + } `json:"result"` +} + +type cosmoshubTx struct { + txHash string +} + +func fetchCosmoshubDetail(ctx context.Context, baseUrl string, rateLimiter *time.Ticker, sequence, timestamp, srcChannel, dstChannel string) (*cosmoshubTx, error) { + queryTemplate := `send_packet.packet_sequence='%s' AND send_packet.packet_timeout_timestamp='%s' AND send_packet.packet_src_channel='%s' AND send_packet.packet_dst_channel='%s'` + query := fmt.Sprintf(queryTemplate, sequence, timestamp, srcChannel, dstChannel) + q := osmosisRequest{ + Jsonrpc: "2.0", + ID: 1, + Method: "tx_search", + Params: struct { + Query string `json:"query"` + Page string `json:"page"` + }{ + Query: query, + Page: "1", + }, + } + + response, err := httpPost(ctx, rateLimiter, baseUrl, q) + if err != nil { + return nil, err + } + + var cReponse cosmoshubResponse + err = json.Unmarshal(response, &cReponse) + if err != nil { + return nil, err + } + + if len(cReponse.Result.Txs) == 0 { + return nil, fmt.Errorf("can not found hash for sequence %s, timestamp %s, srcChannel %s, dstChannel %s", sequence, timestamp, srcChannel, dstChannel) + } + return &cosmoshubTx{txHash: strings.ToLower(cReponse.Result.Txs[0].Hash)}, nil +} + type WorchainAttributeTxDetail struct { OriginChainID sdk.ChainID `bson:"originChainId"` OriginTxHash string `bson:"originTxHash"` @@ -446,6 +526,26 @@ func (a *apiWormchain) fetchWormchainTx( }, nil } + if a.isCosmoshubTx(wormchainTx) { + cosmoshubTx, err := fetchCosmoshubDetail(ctx, a.evmosUrl, a.evmosRateLimiter, wormchainTx.sequence, wormchainTx.timestamp, wormchainTx.srcChannel, wormchainTx.dstChannel) + if err != nil { + return nil, err + } + return &TxDetail{ + NativeTxHash: txHash, + From: wormchainTx.receiver, + Attribute: &AttributeTxDetail{ + Type: "wormchain-gateway", + Value: &WorchainAttributeTxDetail{ + OriginChainID: ChainIDCosmoshub, + OriginTxHash: cosmoshubTx.txHash, + OriginAddress: wormchainTx.sender, + }, + }, + }, nil + } + + // Verify if this transaction is from cosmoshub by wormchain return &TxDetail{ NativeTxHash: txHash, From: wormchainTx.receiver, @@ -483,3 +583,10 @@ func (a *apiWormchain) isEvmosTx(tx *worchainTx) bool { // } return false } + +func (a *apiWormchain) isCosmoshubTx(tx *worchainTx) bool { + if a.p2pNetwork == domain.P2pTestNet { + return tx.srcChannel == "channel-3086" && tx.dstChannel == "channel-5" + } + return false +} diff --git a/tx-tracker/chains/chains.go b/tx-tracker/chains/chains.go index 5f958a4d..39858811 100644 --- a/tx-tracker/chains/chains.go +++ b/tx-tracker/chains/chains.go @@ -25,6 +25,7 @@ var ( // WARNING: The following chain IDs are not supported by the wormhole-sdk: const ChainIDOsmosis sdk.ChainID = 20 +const ChainIDCosmoshub sdk.ChainID = 4000 const ChainIDEvmos sdk.ChainID = 4001 const ChainIDKujira sdk.ChainID = 4002 @@ -67,6 +68,7 @@ func Initialize(cfg *config.RpcProviderSettings) { rateLimitersByChain[sdk.ChainIDBase] = convertToRateLimiter(cfg.BaseRequestsPerMinute) rateLimitersByChain[sdk.ChainIDBSC] = convertToRateLimiter(cfg.BscRequestsPerMinute) rateLimitersByChain[sdk.ChainIDCelo] = convertToRateLimiter(cfg.CeloRequestsPerMinute) + rateLimitersByChain[ChainIDCosmoshub] = convertToRateLimiter(cfg.CosmoshubRequestsPerMinute) rateLimitersByChain[sdk.ChainIDEthereum] = convertToRateLimiter(cfg.EthereumRequestsPerMinute) rateLimitersByChain[sdk.ChainIDFantom] = convertToRateLimiter(cfg.FantomRequestsPerMinute) rateLimitersByChain[sdk.ChainIDInjective] = convertToRateLimiter(cfg.InjectiveRequestsPerMinute) @@ -158,13 +160,15 @@ func FetchTx( return nil, errors.New("found no rate limiter for chain osmosis") } apiWormchain := &apiWormchain{ - osmosisUrl: cfg.OsmosisBaseUrl, - osmosisRateLimiter: rateLimiter, - evmosUrl: cfg.EvmosBaseUrl, - evmosRateLimiter: rateLimiter, - kujiraUrl: cfg.KujiraBaseUrl, - kujiraRateLimiter: rateLimiter, - p2pNetwork: p2pNetwork, + osmosisUrl: cfg.OsmosisBaseUrl, + osmosisRateLimiter: rateLimiter, + evmosUrl: cfg.EvmosBaseUrl, + evmosRateLimiter: rateLimiter, + kujiraUrl: cfg.KujiraBaseUrl, + kujiraRateLimiter: rateLimiter, + cosmoshubUrl: cfg.CosmoshubBaseUrl, + cosmoshubRateLimiter: rateLimiter, + p2pNetwork: p2pNetwork, } fetchFunc = apiWormchain.fetchWormchainTx case sdk.ChainIDSei: diff --git a/tx-tracker/config/structs.go b/tx-tracker/config/structs.go index 491fb429..b22a1592 100644 --- a/tx-tracker/config/structs.go +++ b/tx-tracker/config/structs.go @@ -79,6 +79,8 @@ type RpcProviderSettings struct { BscRequestsPerMinute uint16 `split_words:"true" required:"true"` CeloBaseUrl string `split_words:"true" required:"true"` CeloRequestsPerMinute uint16 `split_words:"true" required:"true"` + CosmoshubBaseUrl string `split_words:"true" required:"true"` + CosmoshubRequestsPerMinute uint16 `split_words:"true" required:"true"` EthereumBaseUrl string `split_words:"true" required:"true"` EthereumRequestsPerMinute uint16 `split_words:"true" required:"true"` EvmosBaseUrl string `split_words:"true" required:"true"`