wormhole-explorer/contract-watcher/watcher/evm.go

165 lines
4.0 KiB
Go
Raw Normal View History

package watcher
import (
"context"
"encoding/hex"
"strconv"
"strings"
"time"
Add endpoint `GET /api/v1/transactions` (#388) ### Summary Tracking issue: https://github.com/wormhole-foundation/wormhole-explorer/issues/385 This pull request implements a new endpoint, `GET /api/v1/transactions`, which will be consumed by the wormhole explorer UI. The endpoint returns a paginated list of transactions, in which each element contains a brief overview of the transaction (ID, txHash, status, etc.). It exposes offset-based pagination via the parameters `page` and `pageSize`. Also, results can be obtained for a specific address by using the `address` query parameter. The response model looks like this: ```json { "transactions": [ { "id": "1/5ec18c34b47c63d17ab43b07b9b2319ea5ee2d163bce2e467000174e238c8e7f/12965", "timestamp": "2023-06-08T19:30:19Z", "txHash": "a302c4ab2d6b9a6003951d2e91f8fdbb83cfa20f6ffb588b95ef0290aab37066", "originChain": 1, "status": "ongoing" }, { "id": "22/0000000000000000000000000000000000000000000000000000000000000001/18308", "timestamp": "2023-06-08T19:17:14Z", "txHash": "00000000000000000000000000000000000000000000000000000000000047e7", "originChain": 22, "destinationAddress": "0x00000000000000000000000067e8a40816a983fbe3294aaebd0cc2391815b86b", "destinationChain": 5, "tokenAmount": "0.12", "usdAmount": "0.12012", "symbol": "USDC", "status": "completed" }, ... ] } ``` ### Limitations of the current implementation 1. Doesn't return the total number of results (this may result in a performance issue when we filter by address) 2. Can only filter by receiver address (we don't have sender information in the database yet)
2023-06-12 07:43:48 -07:00
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/config"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/storage"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/support"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
"go.uber.org/zap"
)
const (
//Transaction status
TxStatusSuccess = "0x1"
TxStatusFailReverted = "0x0"
)
type EVMParams struct {
ChainID vaa.ChainID
Blockchain string
SizeBlocks uint8
WaitSeconds uint16
InitialBlock int64
MethodsByAddress map[string][]config.BlockchainMethod
}
type EVMAddressesParams struct {
ChainID vaa.ChainID
Blockchain string
SizeBlocks uint8
WaitSeconds uint16
InitialBlock int64
}
type EvmGetStatusFunc func() (string, error)
type EvmTransaction struct {
Hash string
From string
To string
Status EvmGetStatusFunc
BlockNumber string
BlockTimestamp string
Input string
}
// get gloabal transaction status from evm blockchain status code.
func getTxStatus(status string) string {
switch status {
case TxStatusSuccess:
Add endpoint `GET /api/v1/transactions` (#388) ### Summary Tracking issue: https://github.com/wormhole-foundation/wormhole-explorer/issues/385 This pull request implements a new endpoint, `GET /api/v1/transactions`, which will be consumed by the wormhole explorer UI. The endpoint returns a paginated list of transactions, in which each element contains a brief overview of the transaction (ID, txHash, status, etc.). It exposes offset-based pagination via the parameters `page` and `pageSize`. Also, results can be obtained for a specific address by using the `address` query parameter. The response model looks like this: ```json { "transactions": [ { "id": "1/5ec18c34b47c63d17ab43b07b9b2319ea5ee2d163bce2e467000174e238c8e7f/12965", "timestamp": "2023-06-08T19:30:19Z", "txHash": "a302c4ab2d6b9a6003951d2e91f8fdbb83cfa20f6ffb588b95ef0290aab37066", "originChain": 1, "status": "ongoing" }, { "id": "22/0000000000000000000000000000000000000000000000000000000000000001/18308", "timestamp": "2023-06-08T19:17:14Z", "txHash": "00000000000000000000000000000000000000000000000000000000000047e7", "originChain": 22, "destinationAddress": "0x00000000000000000000000067e8a40816a983fbe3294aaebd0cc2391815b86b", "destinationChain": 5, "tokenAmount": "0.12", "usdAmount": "0.12012", "symbol": "USDC", "status": "completed" }, ... ] } ``` ### Limitations of the current implementation 1. Doesn't return the total number of results (this may result in a performance issue when we filter by address) 2. Can only filter by receiver address (we don't have sender information in the database yet)
2023-06-12 07:43:48 -07:00
return domain.DstTxStatusConfirmed
case TxStatusFailReverted:
Add endpoint `GET /api/v1/transactions` (#388) ### Summary Tracking issue: https://github.com/wormhole-foundation/wormhole-explorer/issues/385 This pull request implements a new endpoint, `GET /api/v1/transactions`, which will be consumed by the wormhole explorer UI. The endpoint returns a paginated list of transactions, in which each element contains a brief overview of the transaction (ID, txHash, status, etc.). It exposes offset-based pagination via the parameters `page` and `pageSize`. Also, results can be obtained for a specific address by using the `address` query parameter. The response model looks like this: ```json { "transactions": [ { "id": "1/5ec18c34b47c63d17ab43b07b9b2319ea5ee2d163bce2e467000174e238c8e7f/12965", "timestamp": "2023-06-08T19:30:19Z", "txHash": "a302c4ab2d6b9a6003951d2e91f8fdbb83cfa20f6ffb588b95ef0290aab37066", "originChain": 1, "status": "ongoing" }, { "id": "22/0000000000000000000000000000000000000000000000000000000000000001/18308", "timestamp": "2023-06-08T19:17:14Z", "txHash": "00000000000000000000000000000000000000000000000000000000000047e7", "originChain": 22, "destinationAddress": "0x00000000000000000000000067e8a40816a983fbe3294aaebd0cc2391815b86b", "destinationChain": 5, "tokenAmount": "0.12", "usdAmount": "0.12012", "symbol": "USDC", "status": "completed" }, ... ] } ``` ### Limitations of the current implementation 1. Doesn't return the total number of results (this may result in a performance issue when we filter by address) 2. Can only filter by receiver address (we don't have sender information in the database yet)
2023-06-12 07:43:48 -07:00
return domain.DstTxStatusFailedToProcess
default:
Add endpoint `GET /api/v1/transactions` (#388) ### Summary Tracking issue: https://github.com/wormhole-foundation/wormhole-explorer/issues/385 This pull request implements a new endpoint, `GET /api/v1/transactions`, which will be consumed by the wormhole explorer UI. The endpoint returns a paginated list of transactions, in which each element contains a brief overview of the transaction (ID, txHash, status, etc.). It exposes offset-based pagination via the parameters `page` and `pageSize`. Also, results can be obtained for a specific address by using the `address` query parameter. The response model looks like this: ```json { "transactions": [ { "id": "1/5ec18c34b47c63d17ab43b07b9b2319ea5ee2d163bce2e467000174e238c8e7f/12965", "timestamp": "2023-06-08T19:30:19Z", "txHash": "a302c4ab2d6b9a6003951d2e91f8fdbb83cfa20f6ffb588b95ef0290aab37066", "originChain": 1, "status": "ongoing" }, { "id": "22/0000000000000000000000000000000000000000000000000000000000000001/18308", "timestamp": "2023-06-08T19:17:14Z", "txHash": "00000000000000000000000000000000000000000000000000000000000047e7", "originChain": 22, "destinationAddress": "0x00000000000000000000000067e8a40816a983fbe3294aaebd0cc2391815b86b", "destinationChain": 5, "tokenAmount": "0.12", "usdAmount": "0.12012", "symbol": "USDC", "status": "completed" }, ... ] } ``` ### Limitations of the current implementation 1. Doesn't return the total number of results (this may result in a performance issue when we filter by address) 2. Can only filter by receiver address (we don't have sender information in the database yet)
2023-06-12 07:43:48 -07:00
return domain.DstTxStatusUnkonwn
}
}
// get method ID from transaction input
func getMethodIDByInput(input string) string {
if len(input) < 10 {
return config.MethodUnkown
}
return input[0:10]
}
// get the input and extract the method signature and VAA
func parseInput(input string) (*vaa.VAA, error) {
// remove the first 64 characters plus 0x
input = input[138:]
vaaBytes, err := hex.DecodeString(input)
if err != nil {
return nil, err
}
vaa, err := vaa.Unmarshal(vaaBytes)
if err != nil {
return nil, err
}
return vaa, nil
}
func getBlockNumber(s string, logger *zap.Logger) string {
value, err := strconv.ParseInt(support.Remove0x(s), 16, 64)
if err != nil {
logger.Error("cannot convert to int", zap.Error(err))
return s
}
return strconv.FormatInt(value, 10)
}
func getTimestamp(s string, logger *zap.Logger) *time.Time {
value, err := strconv.ParseInt(support.Remove0x(s), 16, 64)
if err != nil {
logger.Error("cannot convert to timestamp", zap.Error(err))
return nil
}
tm := time.Unix(value, 0)
return &tm
}
func processTransaction(ctx context.Context, chainID vaa.ChainID, tx *EvmTransaction, methodsByAddress map[string][]config.BlockchainMethod, repository *storage.Repository, logger *zap.Logger) {
// get methodID from the transaction.
txMethod := getMethodIDByInput(tx.Input)
log := logger.With(
zap.String("txHash", tx.Hash),
zap.String("method", txMethod),
zap.String("block", tx.BlockNumber))
log.Debug("new tx")
// get methods by address.
methods, ok := methodsByAddress[strings.ToLower(tx.To)]
if !ok {
log.Debug("method unkown")
return
}
for _, method := range methods {
if method.ID == txMethod {
// get vaa from transaction input
vaa, err := parseInput(tx.Input)
if err != nil {
log.Error("cannot parse VAA", zap.Error(err))
return
}
// get evm blockchain status code
txStatusCode, err := tx.Status()
if err != nil {
log.Error("cannot get tx status", zap.Error(err))
return
}
updatedAt := time.Now()
globalTx := storage.TransactionUpdate{
ID: vaa.MessageID(),
Destination: storage.DestinationTx{
ChainID: chainID,
Status: getTxStatus(txStatusCode),
Method: method.Name,
TxHash: support.Remove0x(tx.Hash),
To: tx.To,
From: tx.From,
BlockNumber: getBlockNumber(tx.BlockNumber, log),
Timestamp: getTimestamp(tx.BlockTimestamp, log),
UpdatedAt: &updatedAt,
},
}
// update global transaction and check if it should be updated.
updateGlobalTransaction(ctx, globalTx, repository, log)
break
}
}
}