126 lines
3.3 KiB
Go
126 lines
3.3 KiB
Go
package chains
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/wormhole-foundation/wormhole-explorer/common/pool"
|
|
"github.com/wormhole-foundation/wormhole-explorer/txtracker/internal/metrics"
|
|
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type seiTx struct {
|
|
TxHash string
|
|
Sender string
|
|
}
|
|
|
|
func seiTxSearchExtractor(tx *cosmosTxSearchResponse, logs []cosmosLogWrapperResponse) (*seiTx, error) {
|
|
var sender string
|
|
for _, l := range logs {
|
|
for _, e := range l.Events {
|
|
if e.Type == "message" {
|
|
for _, attr := range e.Attributes {
|
|
if attr.Key == "sender" {
|
|
sender = attr.Value
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return &seiTx{TxHash: tx.Result.Txs[0].Hash, Sender: sender}, nil
|
|
}
|
|
|
|
type apiSei struct {
|
|
p2pNetwork string
|
|
wormchainPool *pool.Pool
|
|
}
|
|
|
|
func fetchSeiDetail(ctx context.Context, baseUrl string, sequence, timestamp, srcChannel, dstChannel string) (*seiTx, error) {
|
|
params := &cosmosTxSearchParams{Sequence: sequence, Timestamp: timestamp, SrcChannel: srcChannel, DstChannel: dstChannel}
|
|
return fetchTxSearch[seiTx](ctx, baseUrl, params, seiTxSearchExtractor)
|
|
}
|
|
|
|
func (a *apiSei) FetchSeiTx(
|
|
ctx context.Context,
|
|
pool *pool.Pool,
|
|
txHash string,
|
|
metrics metrics.Metrics,
|
|
logger *zap.Logger,
|
|
) (*TxDetail, error) {
|
|
txHash = txHashLowerCaseWith0x(txHash)
|
|
|
|
// Get the wormchain rpcs sorted by availability.
|
|
wormchainRpcs := a.wormchainPool.GetItems()
|
|
if len(wormchainRpcs) == 0 {
|
|
return nil, errors.New("wormchain rpc pool is empty")
|
|
}
|
|
|
|
// Fetch the wormchain transaction
|
|
var wormchainTx *wormchainTx
|
|
var err error
|
|
for _, rpc := range wormchainRpcs {
|
|
// wait for the rpc to be available
|
|
rpc.Wait(ctx)
|
|
wormchainTx, err = fetchWormchainDetail(ctx, rpc.Id, txHash)
|
|
if err != nil {
|
|
metrics.IncCallRpcError(uint16(vaa.ChainIDWormchain), rpc.Description)
|
|
logger.Debug("Failed to fetch transaction from wormchain", zap.String("url", rpc.Id), zap.Error(err))
|
|
continue
|
|
}
|
|
metrics.IncCallRpcSuccess(uint16(vaa.ChainIDWormchain), rpc.Description)
|
|
break
|
|
}
|
|
|
|
// If the transaction is not found, return an error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if wormchainTx == nil {
|
|
return nil, ErrTransactionNotFound
|
|
}
|
|
|
|
// Get the sei rpcs sorted by availability.
|
|
seiRpcs := pool.GetItems()
|
|
if len(seiRpcs) == 0 {
|
|
return nil, errors.New("sei rpc pool is empty")
|
|
}
|
|
|
|
// Fetch the sei transaction
|
|
var seiTx *seiTx
|
|
for _, rpc := range seiRpcs {
|
|
// wait for the rpc to be available
|
|
rpc.Wait(ctx)
|
|
seiTx, err = fetchSeiDetail(ctx, rpc.Id, wormchainTx.sequence, wormchainTx.timestamp, wormchainTx.srcChannel, wormchainTx.dstChannel)
|
|
if err != nil {
|
|
metrics.IncCallRpcError(uint16(vaa.ChainIDSei), rpc.Description)
|
|
logger.Debug("Failed to fetch transaction from sei", zap.String("url", rpc.Id), zap.Error(err))
|
|
continue
|
|
}
|
|
metrics.IncCallRpcSuccess(uint16(vaa.ChainIDSei), rpc.Description)
|
|
break
|
|
}
|
|
|
|
// If the transaction is not found, return an error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if seiTx == nil {
|
|
return nil, ErrTransactionNotFound
|
|
}
|
|
|
|
return &TxDetail{
|
|
NativeTxHash: txHash,
|
|
From: wormchainTx.receiver,
|
|
Attribute: &AttributeTxDetail{
|
|
Type: "wormchain-gateway",
|
|
Value: &WorchainAttributeTxDetail{
|
|
OriginChainID: vaa.ChainIDSei,
|
|
OriginTxHash: seiTx.TxHash,
|
|
OriginAddress: seiTx.Sender,
|
|
},
|
|
},
|
|
}, nil
|
|
}
|