153 lines
3.5 KiB
Go
153 lines
3.5 KiB
Go
package token
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/wormhole-foundation/wormhole-explorer/common/client/parser"
|
|
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
|
sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
var ErrUnknownToken = errors.New("token is unknown")
|
|
|
|
type TransferredToken struct {
|
|
AppId string
|
|
FromChain sdk.ChainID
|
|
ToChain sdk.ChainID
|
|
TokenAddress sdk.Address
|
|
TokenChain sdk.ChainID
|
|
Amount *big.Int
|
|
}
|
|
|
|
func (t *TransferredToken) Clone() *TransferredToken {
|
|
if t == nil {
|
|
return nil
|
|
}
|
|
var amount *big.Int
|
|
if t.Amount != nil {
|
|
amount = new(big.Int).Set(t.Amount)
|
|
}
|
|
return &TransferredToken{
|
|
AppId: t.AppId,
|
|
FromChain: t.FromChain,
|
|
ToChain: t.ToChain,
|
|
TokenAddress: t.TokenAddress,
|
|
TokenChain: t.TokenChain,
|
|
Amount: amount,
|
|
}
|
|
}
|
|
|
|
type GetTransferredTokenByVaa func(context.Context, *sdk.VAA) (*TransferredToken, error)
|
|
|
|
type TokenResolver struct {
|
|
client parser.ParserVAAAPIClient
|
|
logger *zap.Logger
|
|
}
|
|
|
|
func NewTokenResolver(client parser.ParserVAAAPIClient, logger *zap.Logger) *TokenResolver {
|
|
return &TokenResolver{
|
|
client: client,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
func (r *TokenResolver) GetTransferredTokenByVaa(ctx context.Context, vaa *sdk.VAA) (*TransferredToken, error) {
|
|
|
|
// Ignore PythNet VAAs
|
|
if vaa.EmitterChain == sdk.ChainIDPythNet {
|
|
return nil, nil
|
|
}
|
|
|
|
// Decode the VAA payload
|
|
payload, err := sdk.DecodeTransferPayloadHdr(vaa.Payload)
|
|
if err == nil && payload.OriginChain != sdk.ChainIDUnset {
|
|
return &TransferredToken{
|
|
AppId: domain.AppIdPortalTokenBridge,
|
|
FromChain: vaa.EmitterChain,
|
|
ToChain: payload.TargetChain,
|
|
TokenAddress: payload.OriginAddress,
|
|
TokenChain: payload.OriginChain,
|
|
Amount: payload.Amount,
|
|
}, nil
|
|
|
|
}
|
|
|
|
// Parse the VAA with standarized properties
|
|
result, err := r.client.ParseVaaWithStandarizedProperties(vaa)
|
|
if err != nil {
|
|
r.logger.Error("Parsing vaa with standarized properties",
|
|
zap.String("vaaId", vaa.MessageID()),
|
|
zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
if result == nil {
|
|
r.logger.Error("VAA with standarized properties is empty",
|
|
zap.String("vaaId", vaa.MessageID()),
|
|
zap.Error(err))
|
|
return nil, nil
|
|
}
|
|
|
|
token, err := createToken(result.StandardizedProperties, vaa.EmitterChain)
|
|
if err != nil {
|
|
r.logger.Debug("Creating transferred token",
|
|
zap.String("vaaId", vaa.MessageID()),
|
|
zap.Error(err))
|
|
return nil, ErrUnknownToken
|
|
}
|
|
|
|
return token, err
|
|
}
|
|
|
|
func createToken(s parser.StandardizedProperties, emitterChain sdk.ChainID) (*TransferredToken, error) {
|
|
|
|
if s.TokenChain.String() == sdk.ChainIDUnset.String() {
|
|
return nil, errors.New("tokenChain is unset")
|
|
}
|
|
|
|
if s.ToChain.String() == sdk.ChainIDUnset.String() {
|
|
return nil, errors.New("toChain is unset")
|
|
}
|
|
|
|
if emitterChain.String() == sdk.ChainIDUnset.String() {
|
|
return nil, errors.New("emitterChain is unset")
|
|
}
|
|
|
|
if s.TokenAddress == "" {
|
|
return nil, errors.New("tokenAddress is empty")
|
|
}
|
|
|
|
if s.Amount == "" {
|
|
return nil, errors.New("amount is empty")
|
|
}
|
|
|
|
address, err := sdk.StringToAddress(s.TokenAddress)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
n := new(big.Int)
|
|
n, ok := n.SetString(s.Amount, 10)
|
|
if !ok {
|
|
return nil, fmt.Errorf("amount [%s] is not a number", s.Amount)
|
|
}
|
|
|
|
appId := domain.AppIdUnkonwn
|
|
if len(s.AppIds) > 0 {
|
|
appId = s.AppIds[0]
|
|
}
|
|
|
|
return &TransferredToken{
|
|
AppId: appId,
|
|
FromChain: emitterChain,
|
|
ToChain: s.ToChain,
|
|
TokenAddress: address,
|
|
TokenChain: s.TokenChain,
|
|
Amount: n,
|
|
}, nil
|
|
}
|