Add methods to identify kujira & evmos (#729)
* Add methods to identify kujira & evmos * Add fetch methods to kajira and evmos * fix fetch kujira and evmos methods * Add support to search vaas gateway chain txHash * Add deploy config to tx-tracker for evmos & kujira
This commit is contained in:
parent
b46ba72d6b
commit
f4fe630623
|
@ -72,10 +72,13 @@ func (r *Repository) FindVaasByTxHashWorkaround(
|
|||
{"$or", bson.A{
|
||||
bson.D{{"originTx.nativeTxHash", bson.M{"$eq": query.txHash}}},
|
||||
bson.D{{"originTx.nativeTxHash", bson.M{"$eq": "0x" + query.txHash}}},
|
||||
bson.D{{"originTx.attribute.value.originTxHash", bson.M{"$eq": query.txHash}}},
|
||||
bson.D{{"originTx.attribute.value.originTxHash", bson.M{"$eq": "0x" + query.txHash}}},
|
||||
}},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
requestID := fmt.Sprintf("%v", ctx.Value("requestid"))
|
||||
r.logger.Error("failed to find globalTransactions by TxHash",
|
||||
|
|
|
@ -40,6 +40,9 @@ CELO_REQUESTS_PER_MINUTE=12
|
|||
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth
|
||||
ETHEREUM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
EVMOS_BASE_URL=https://tm.evmos.lava.build
|
||||
EVMOS_REQUESTS_PER_MINUTE=12
|
||||
|
||||
FANTOM_BASE_URL=https://rpc.ankr.com/fantom
|
||||
FANTOM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
|
@ -54,6 +57,9 @@ KARURA_REQUESTS_PER_MINUTE=12
|
|||
KLAYTN_BASE_URL=https://klaytn-mainnet-rpc.allthatnode.com:8551
|
||||
KLAYTN_REQUESTS_PER_MINUTE=12
|
||||
|
||||
KUJIRA_BASE_URL=https://kujira-rpc.ibs.team
|
||||
KUJIRA_REQUESTS_PER_MINUTE=12
|
||||
|
||||
MOONBEAM_BASE_URL=https://rpc.api.moonbeam.network
|
||||
MOONBEAM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ CELO_REQUESTS_PER_MINUTE=12
|
|||
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth_goerli
|
||||
ETHEREUM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
EVMOS_BASE_URL=https://evmos-testnet-rpc.polkachu.com
|
||||
EVMOS_REQUESTS_PER_MINUTE=12
|
||||
|
||||
FANTOM_BASE_URL=https://rpc.testnet.fantom.network
|
||||
FANTOM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
|
@ -52,6 +55,9 @@ KARURA_REQUESTS_PER_MINUTE=12
|
|||
KLAYTN_BASE_URL=https://api.baobab.klaytn.net:8651
|
||||
KLAYTN_REQUESTS_PER_MINUTE=12
|
||||
|
||||
KUJIRA_BASE_URL=https://kujira-testnet-rpc.polkachu.com
|
||||
KUJIRA_REQUESTS_PER_MINUTE=12
|
||||
|
||||
MOONBEAM_BASE_URL=https://rpc.api.moonbase.moonbeam.network
|
||||
MOONBEAM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ CELO_REQUESTS_PER_MINUTE=12
|
|||
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth
|
||||
ETHEREUM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
EVMOS_BASE_URL=https://tm.evmos.lava.build
|
||||
EVMOS_REQUESTS_PER_MINUTE=12
|
||||
|
||||
FANTOM_BASE_URL=https://rpc.ankr.com/fantom
|
||||
FANTOM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
|
@ -54,6 +57,9 @@ KARURA_REQUESTS_PER_MINUTE=12
|
|||
KLAYTN_BASE_URL=https://klaytn-mainnet-rpc.allthatnode.com:8551
|
||||
KLAYTN_REQUESTS_PER_MINUTE=12
|
||||
|
||||
KUJIRA_BASE_URL=https://kujira-rpc.ibs.team
|
||||
KUJIRA_REQUESTS_PER_MINUTE=12
|
||||
|
||||
MOONBEAM_BASE_URL=https://rpc.api.moonbeam.network
|
||||
MOONBEAM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ CELO_REQUESTS_PER_MINUTE=12
|
|||
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth_goerli
|
||||
ETHEREUM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
EVMOS_BASE_URL=https://evmos-testnet-rpc.polkachu.com
|
||||
EVMOS_REQUESTS_PER_MINUTE=12
|
||||
|
||||
FANTOM_BASE_URL=https://rpc.testnet.fantom.network
|
||||
FANTOM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
|
@ -52,6 +55,9 @@ KARURA_REQUESTS_PER_MINUTE=12
|
|||
KLAYTN_BASE_URL=https://api.baobab.klaytn.net:8651
|
||||
KLAYTN_REQUESTS_PER_MINUTE=12
|
||||
|
||||
KUJIRA_BASE_URL=https://kujira-testnet-rpc.polkachu.com
|
||||
KUJIRA_REQUESTS_PER_MINUTE=12
|
||||
|
||||
MOONBEAM_BASE_URL=https://rpc.api.moonbase.moonbeam.network
|
||||
MOONBEAM_REQUESTS_PER_MINUTE=12
|
||||
|
||||
|
|
|
@ -100,6 +100,10 @@ spec:
|
|||
value: {{ .ETHEREUM_BASE_URL }}
|
||||
- name: ETHEREUM_REQUESTS_PER_MINUTE
|
||||
value: "{{ .ETHEREUM_REQUESTS_PER_MINUTE }}"
|
||||
- name: EVMOS_BASE_URL
|
||||
value: {{ .EVMOS_BASE_URL }}
|
||||
- name: EVMOS_REQUESTS_PER_MINUTE
|
||||
value: "{{ .EVMOS_REQUESTS_PER_MINUTE }}"
|
||||
- name: FANTOM_BASE_URL
|
||||
value: {{ .FANTOM_BASE_URL }}
|
||||
- name: FANTOM_REQUESTS_PER_MINUTE
|
||||
|
@ -116,6 +120,10 @@ spec:
|
|||
value: {{ .KLAYTN_BASE_URL }}
|
||||
- name: KLAYTN_REQUESTS_PER_MINUTE
|
||||
value: "{{ .KLAYTN_REQUESTS_PER_MINUTE }}"
|
||||
- name: KUJIRA_BASE_URL
|
||||
value: {{ .KUJIRA_BASE_URL }}
|
||||
- name: KUJIRA_REQUESTS_PER_MINUTE
|
||||
value: "{{ .KUJIRA_REQUESTS_PER_MINUTE }}"
|
||||
- name: MOONBEAM_BASE_URL
|
||||
value: {{ .MOONBEAM_BASE_URL }}
|
||||
- name: MOONBEAM_REQUESTS_PER_MINUTE
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
||||
|
@ -13,6 +14,10 @@ import (
|
|||
type apiWormchain struct {
|
||||
osmosisUrl string
|
||||
osmosisRateLimiter *time.Ticker
|
||||
kujiraUrl string
|
||||
kujiraRateLimiter *time.Ticker
|
||||
evmosUrl string
|
||||
evmosRateLimiter *time.Ticker
|
||||
p2pNetwork string
|
||||
}
|
||||
|
||||
|
@ -127,8 +132,6 @@ func fetchWormchainDetail(ctx context.Context, baseUrl string, rateLimiter *time
|
|||
|
||||
}
|
||||
|
||||
const 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'`
|
||||
|
||||
type osmosisRequest struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
ID int `json:"id"`
|
||||
|
@ -174,14 +177,8 @@ type osmosisTx struct {
|
|||
txHash string
|
||||
}
|
||||
|
||||
type WorchainAttributeTxDetail struct {
|
||||
OriginChainID sdk.ChainID `bson:"originChainId"`
|
||||
OriginTxHash string `bson:"originTxHash"`
|
||||
OriginAddress string `bson:"originAddress"`
|
||||
}
|
||||
|
||||
func fetchOsmosisDetail(ctx context.Context, baseUrl string, rateLimiter *time.Ticker, sequence, timestamp, srcChannel, dstChannel string) (*osmosisTx, 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",
|
||||
|
@ -201,6 +198,162 @@ func fetchOsmosisDetail(ctx context.Context, baseUrl string, rateLimiter *time.T
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var kReponse kujiraResponse
|
||||
err = json.Unmarshal(response, &kReponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(kReponse.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 &osmosisTx{txHash: kReponse.Result.Txs[0].Hash}, nil
|
||||
}
|
||||
|
||||
type evmosRequest 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 evmosResponse 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 evmosTx struct {
|
||||
txHash string
|
||||
}
|
||||
|
||||
func fetchEvmosDetail(ctx context.Context, baseUrl string, rateLimiter *time.Ticker, sequence, timestamp, srcChannel, dstChannel string) (*evmosTx, 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 := evmosRequest{
|
||||
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 eReponse evmosResponse
|
||||
err = json.Unmarshal(response, &eReponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(eReponse.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 &evmosTx{txHash: strings.ToLower(eReponse.Result.Txs[0].Hash)}, nil
|
||||
}
|
||||
|
||||
type kujiraRequest 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 kujiraResponse 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 kujiraTx struct {
|
||||
txHash string
|
||||
}
|
||||
|
||||
func fetchKujiraDetail(ctx context.Context, baseUrl string, rateLimiter *time.Ticker, sequence, timestamp, srcChannel, dstChannel string) (*kujiraTx, 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 := kujiraRequest{
|
||||
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 oReponse osmosisResponse
|
||||
err = json.Unmarshal(response, &oReponse)
|
||||
if err != nil {
|
||||
|
@ -210,7 +363,13 @@ func fetchOsmosisDetail(ctx context.Context, baseUrl string, rateLimiter *time.T
|
|||
if len(oReponse.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 &osmosisTx{txHash: oReponse.Result.Txs[0].Hash}, nil
|
||||
return &kujiraTx{txHash: strings.ToLower(oReponse.Result.Txs[0].Hash)}, nil
|
||||
}
|
||||
|
||||
type WorchainAttributeTxDetail struct {
|
||||
OriginChainID sdk.ChainID `bson:"originChainId"`
|
||||
OriginTxHash string `bson:"originTxHash"`
|
||||
OriginAddress string `bson:"originAddress"`
|
||||
}
|
||||
|
||||
func (a *apiWormchain) fetchWormchainTx(
|
||||
|
@ -247,6 +406,46 @@ func (a *apiWormchain) fetchWormchainTx(
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Verify if this transaction is from kujira by wormchain
|
||||
if a.isKujiraTx(wormchainTx) {
|
||||
kujiraTx, err := fetchKujiraDetail(ctx, a.kujiraUrl, a.kujiraRateLimiter, 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: ChainIDKujira,
|
||||
OriginTxHash: kujiraTx.txHash,
|
||||
OriginAddress: wormchainTx.sender,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Verify if this transaction is from evmos by wormchain
|
||||
if a.isEvmosTx(wormchainTx) {
|
||||
evmosTx, err := fetchEvmosDetail(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: ChainIDEvmos,
|
||||
OriginTxHash: evmosTx.txHash,
|
||||
OriginAddress: wormchainTx.sender,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &TxDetail{
|
||||
NativeTxHash: txHash,
|
||||
From: wormchainTx.receiver,
|
||||
|
@ -262,3 +461,25 @@ func (a *apiWormchain) isOsmosisTx(tx *worchainTx) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *apiWormchain) isKujiraTx(tx *worchainTx) bool {
|
||||
if a.p2pNetwork == domain.P2pMainNet {
|
||||
return tx.srcChannel == "channel-113" && tx.dstChannel == "channel-9"
|
||||
}
|
||||
// Pending get channels for testnet
|
||||
// if a.p2pNetwork == domain.P2pTestNet {
|
||||
// return tx.srcChannel == "" && tx.dstChannel == ""
|
||||
// }
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *apiWormchain) isEvmosTx(tx *worchainTx) bool {
|
||||
if a.p2pNetwork == domain.P2pMainNet {
|
||||
return tx.srcChannel == "channel-94" && tx.dstChannel == "channel-5"
|
||||
}
|
||||
// Pending get channels for testnet
|
||||
// if a.p2pNetwork == domain.P2pTestNet {
|
||||
// return tx.srcChannel == "" && tx.dstChannel == ""
|
||||
// }
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ var (
|
|||
|
||||
// WARNING: The following chain IDs are not supported by the wormhole-sdk:
|
||||
const ChainIDOsmosis sdk.ChainID = 20
|
||||
const ChainIDEvmos sdk.ChainID = 4001
|
||||
const ChainIDKujira sdk.ChainID = 4002
|
||||
|
||||
type WormchainTxDetail struct {
|
||||
}
|
||||
|
@ -156,6 +158,10 @@ func FetchTx(
|
|||
apiWormchain := &apiWormchain{
|
||||
osmosisUrl: cfg.OsmosisBaseUrl,
|
||||
osmosisRateLimiter: rateLimiter,
|
||||
evmosUrl: cfg.EvmosBaseUrl,
|
||||
evmosRateLimiter: rateLimiter,
|
||||
kujiraUrl: cfg.KujiraBaseUrl,
|
||||
kujiraRateLimiter: rateLimiter,
|
||||
p2pNetwork: p2pNetwork,
|
||||
}
|
||||
fetchFunc = apiWormchain.fetchWormchainTx
|
||||
|
|
|
@ -80,6 +80,8 @@ type RpcProviderSettings struct {
|
|||
CeloRequestsPerMinute 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"`
|
||||
EvmosRequestsPerMinute uint16 `split_words:"true" required:"true"`
|
||||
FantomBaseUrl string `split_words:"true" required:"true"`
|
||||
FantomRequestsPerMinute uint16 `split_words:"true" required:"true"`
|
||||
InjectiveBaseUrl string `split_words:"true" required:"true"`
|
||||
|
@ -88,6 +90,8 @@ type RpcProviderSettings struct {
|
|||
KaruraRequestsPerMinute uint16 `split_words:"true" required:"true"`
|
||||
KlaytnBaseUrl string `split_words:"true" required:"true"`
|
||||
KlaytnRequestsPerMinute uint16 `split_words:"true" required:"true"`
|
||||
KujiraBaseUrl string `split_words:"true" required:"true"`
|
||||
KujiraRequestsPerMinute uint16 `split_words:"true" required:"true"`
|
||||
MoonbeamBaseUrl string `split_words:"true" required:"true"`
|
||||
MoonbeamRequestsPerMinute uint16 `split_words:"true" required:"true"`
|
||||
OasisBaseUrl string `split_words:"true" required:"true"`
|
||||
|
|
Loading…
Reference in New Issue