2023-03-14 11:49:10 -07:00
|
|
|
package chains
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
|
|
|
|
|
|
"github.com/wormhole-foundation/wormhole-explorer/txtracker/config"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ankrGetTransactionByHashParams struct {
|
|
|
|
TransactionHash string `json:"transactionHash"`
|
|
|
|
DecodeLogs bool `json:"decodeLogs"`
|
|
|
|
DecodeTxData bool `json:"decodeTxData"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type ankrGetTransactionsByHashResponse struct {
|
|
|
|
Transactions []ankrTransaction `json:"transactions"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type ankrTransaction struct {
|
|
|
|
From string `json:"from"`
|
|
|
|
To string `json:"to"`
|
|
|
|
Timestamp string `json:"timestamp"`
|
|
|
|
Logs []ankrLog `json:"logs"`
|
|
|
|
Status string `json:"status"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type ankrLog struct {
|
|
|
|
Event ankrEvent `json:"event"`
|
|
|
|
Topics []string `json:"topics"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type ankrEvent struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Inputs []ankrEventInput `json:"inputs"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type ankrEventInput struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
Size uint64 `json:"size"`
|
|
|
|
ValueDecoded string `json:"valueDecoded"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func ankrFetchTx(
|
|
|
|
ctx context.Context,
|
2023-03-20 12:36:19 -07:00
|
|
|
cfg *config.RpcProviderSettings,
|
2023-03-14 11:49:10 -07:00
|
|
|
txHash string,
|
|
|
|
) (*TxDetail, error) {
|
|
|
|
|
|
|
|
// build RPC URL
|
|
|
|
url := cfg.AnkrBaseUrl
|
|
|
|
if cfg.AnkrApiKey != "" {
|
|
|
|
url += "/" + cfg.AnkrApiKey
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize RPC client
|
|
|
|
client, err := rpc.DialContext(ctx, url)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to initialize RPC client: %w", err)
|
|
|
|
}
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
// query transaction data
|
|
|
|
args := &ankrGetTransactionByHashParams{
|
|
|
|
TransactionHash: "0x" + txHash,
|
|
|
|
DecodeLogs: true,
|
|
|
|
DecodeTxData: true,
|
|
|
|
}
|
|
|
|
var reply ankrGetTransactionsByHashResponse
|
|
|
|
err = client.CallContext(ctx, &reply, "ankr_getTransactionsByHash", args)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get tx by hash: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure we got exactly one transaction
|
|
|
|
if len(reply.Transactions) == 0 {
|
|
|
|
return nil, ErrTransactionNotFound
|
|
|
|
} else if len(reply.Transactions) > 1 {
|
|
|
|
return nil, fmt.Errorf("expected one transaction for txid=%s, but found %d", txHash, len(reply.Transactions))
|
|
|
|
}
|
|
|
|
|
|
|
|
// parse transaction timestamp
|
2023-03-27 12:14:12 -07:00
|
|
|
timestamp, err := timestampFromHex(reply.Transactions[0].Timestamp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to parse transaction timestamp: %w", err)
|
2023-03-14 11:49:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// build results and return
|
|
|
|
txDetail := &TxDetail{
|
|
|
|
Signer: strings.ToLower(reply.Transactions[0].From),
|
|
|
|
Timestamp: timestamp,
|
|
|
|
NativeTxHash: fmt.Sprintf("0x%s", strings.ToLower(txHash)),
|
|
|
|
}
|
|
|
|
return txDetail, nil
|
|
|
|
}
|