Add definitions to token dictionary (#292)
### Summary In order to compute volume metrics for each token, we need metadata about the token that is not present in the VAAs (e.g.: decimals, symbol). That information is statically defined in `common/domain/tokenbridge.go`. This pull request adds the most relevant tokens (i.e.: the tokens that contribute the most volume) to the existing definitions. It is very likely that more token definitions will be added in the future as needed. The token metadata that was previously defined in the `notional` package (symbols, coingecko IDs) was also moved to `common/domain/tokenbridge.go`. Tracking issue https://github.com/wormhole-foundation/wormhole-explorer/issues/281
This commit is contained in:
parent
e2f32c2883
commit
a31d59822d
|
@ -133,9 +133,9 @@ func (m *Metric) volumeMeasurement(ctx context.Context, vaa *sdk.VAA) error {
|
|||
// Get the token metadata
|
||||
//
|
||||
// This is complementary data about the token that is not present in the VAA itself.
|
||||
tokenMeta, ok := domain.GetTokenMetadata(payload.OriginChain, "0x"+payload.OriginAddress.String())
|
||||
tokenMeta, ok := domain.GetTokenByAddress(payload.OriginChain, payload.OriginAddress.String())
|
||||
if !ok {
|
||||
m.logger.Warn("found no token metadata for VAA",
|
||||
m.logger.Debug("found no token metadata for VAA",
|
||||
zap.String("vaaId", vaa.MessageID()),
|
||||
zap.String("tokenAddress", payload.OriginAddress.String()),
|
||||
zap.Uint16("tokenChain", uint16(payload.OriginChain)),
|
||||
|
@ -183,17 +183,31 @@ func (m *Metric) volumeMeasurement(ctx context.Context, vaa *sdk.VAA) error {
|
|||
zap.String("amount", amount.String()),
|
||||
zap.String("notional", notionalBigInt.String()),
|
||||
zap.String("volume", volume.String()),
|
||||
zap.String("underlyingSymbol", tokenMeta.UnderlyingSymbol.String()),
|
||||
)
|
||||
|
||||
// Create a data point with volume-related fields
|
||||
//
|
||||
// We're converting big integers to int64 because influxdb doesn't support bigint/numeric types.
|
||||
point := influxdb2.NewPointWithMeasurement(measurement).
|
||||
AddTag("chain_source_id", fmt.Sprintf("%d", payload.OriginChain)).
|
||||
AddTag("chain_destination_id", fmt.Sprintf("%d", payload.TargetChain)).
|
||||
// This is always set to the portal token bridge app ID, but we may have other apps in the future
|
||||
AddTag("app_id", domain.AppIdPortalTokenBridge).
|
||||
AddTag("emitter_chain", fmt.Sprintf("%d", vaa.EmitterChain)).
|
||||
// Receiver address
|
||||
AddTag("destination_address", payload.TargetAddress.String()).
|
||||
// Receiver chain
|
||||
AddTag("destination_chain", fmt.Sprintf("%d", payload.TargetChain)).
|
||||
// Original mint address
|
||||
AddTag("token_address", payload.OriginAddress.String()).
|
||||
// Original mint chain
|
||||
AddTag("token_chain", fmt.Sprintf("%d", payload.OriginChain)).
|
||||
// Amount of tokens transferred, integer, 8 decimals of precision
|
||||
AddField("amount", amount.Int64()).
|
||||
// Token price at the time the VAA was processed, integer, 8 decimals of precision
|
||||
//
|
||||
// TODO: We should use the price at the time the VAA was emitted instead.
|
||||
AddField("notional", notionalBigInt.Int64()).
|
||||
// Volume in USD, integer, 8 decimals of precision
|
||||
AddField("volume", volume.Int64()).
|
||||
SetTime(vaa.Timestamp)
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ from(bucket: "%s")
|
|||
|> range(start: -24h)
|
||||
|> filter(fn: (r) => r._measurement == "vaa_volume")
|
||||
|> filter(fn:(r) => r._field == "volume")
|
||||
|> drop(columns: ["_measurement", "app_id", "chain_destination_id", "chain_source_id", "symbol"])
|
||||
|> drop(columns: ["_measurement", "app_id", "destination_address", "destination_chain", "token_address", "token_chain"])
|
||||
|> sum(column: "_value")
|
||||
|> toString()
|
||||
`
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -25,7 +26,7 @@ var (
|
|||
|
||||
// NotionalLocalCacheReadable is the interface for notional local cache.
|
||||
type NotionalLocalCacheReadable interface {
|
||||
Get(symbol string) (PriceData, error)
|
||||
Get(symbol domain.Symbol) (PriceData, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
|
@ -132,7 +133,7 @@ func (c *NotionalCache) Close() error {
|
|||
}
|
||||
|
||||
// Get notional cache value.
|
||||
func (c *NotionalCache) Get(symbol string) (PriceData, error) {
|
||||
func (c *NotionalCache) Get(symbol domain.Symbol) (PriceData, error) {
|
||||
var notional PriceData
|
||||
|
||||
// get notional cache key
|
||||
|
@ -149,7 +150,7 @@ func (c *NotionalCache) Get(symbol string) (PriceData, error) {
|
|||
if !ok {
|
||||
c.logger.Error("invalid notional cache field",
|
||||
zap.Any("field", field),
|
||||
zap.String("symbol", symbol))
|
||||
zap.String("symbol", symbol.String()))
|
||||
return notional, ErrInvalidCacheField
|
||||
}
|
||||
return notional, nil
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package notional
|
||||
|
||||
import "github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
||||
|
||||
// DummyNotionalCache is a dummy notional cache.
|
||||
type DummyNotionalCache struct {
|
||||
}
|
||||
|
@ -10,7 +12,7 @@ func NewDummyNotionalCache() *DummyNotionalCache {
|
|||
}
|
||||
|
||||
// Get get notional cache value.
|
||||
func (c *DummyNotionalCache) Get(symbol string) (PriceData, error) {
|
||||
func (c *DummyNotionalCache) Get(symbol domain.Symbol) (PriceData, error) {
|
||||
return PriceData{}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -6,63 +6,488 @@ import (
|
|||
sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
)
|
||||
|
||||
// Symbol identifies a publicly traded token (i.e. "ETH" for Ethereum, "ALGO" for Algorand, etc.)
|
||||
type Symbol string
|
||||
|
||||
func (s Symbol) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// TokenMetadata contains information about a token supported by Portal Token Bridge.
|
||||
type TokenMetadata struct {
|
||||
// UnderlyingSymbol is the name that crypto exchanges use to list the underlying asset represented by this token.
|
||||
// For example, the underlying symbol of the token "WFTM (wrapped fantom)" is "FTM".
|
||||
UnderlyingSymbol string
|
||||
UnderlyingSymbol Symbol
|
||||
Decimals uint8
|
||||
CoingeckoID string
|
||||
TokenChain sdk.ChainID
|
||||
TokenAddress string
|
||||
}
|
||||
|
||||
// GetTokenMetadata returns information about a token identified by the pair (tokenChain, tokenAddr).
|
||||
func GetTokenMetadata(tokenChain sdk.ChainID, tokenAddr string) (*TokenMetadata, bool) {
|
||||
var (
|
||||
tokenMetadataByContractID = make(map[string]*TokenMetadata, len(tokenMetadata))
|
||||
tokenMetadataByCoingeckoID = make(map[string]*TokenMetadata, len(tokenMetadata))
|
||||
)
|
||||
|
||||
key := fmt.Sprintf("%d-%s", tokenChain, tokenAddr)
|
||||
func init() {
|
||||
|
||||
result, ok := tokenMetadata[key]
|
||||
for i := range tokenMetadata {
|
||||
|
||||
// populate the map `tokenMetadataByCoingeckoID`
|
||||
coingeckoID := tokenMetadata[i].CoingeckoID
|
||||
if coingeckoID != "" {
|
||||
tokenMetadataByCoingeckoID[coingeckoID] = &tokenMetadata[i]
|
||||
}
|
||||
|
||||
// populate the map `tokenMetadataByContractID`
|
||||
contractID := makeContractID(tokenMetadata[i].TokenChain, tokenMetadata[i].TokenAddress)
|
||||
if contractID != "" {
|
||||
tokenMetadataByContractID[contractID] = &tokenMetadata[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeContractID(tokenChain sdk.ChainID, tokenAddress string) string {
|
||||
return fmt.Sprintf("%d-%s", tokenChain, tokenAddress)
|
||||
}
|
||||
|
||||
// GetAllCoingeckoIDs returns a list of all coingecko IDs that exist in the database.
|
||||
func GetAllCoingeckoIDs() []string {
|
||||
|
||||
// use a map to remove duplicates
|
||||
uniqueIDs := make(map[string]bool, len(tokenMetadata))
|
||||
for i := range tokenMetadata {
|
||||
uniqueIDs[tokenMetadata[i].CoingeckoID] = true
|
||||
}
|
||||
|
||||
// collect keys into a slice
|
||||
ids := make([]string, 0, len(uniqueIDs))
|
||||
for k := range uniqueIDs {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
// GetTokenByCoingeckoID returns information about a token identified by its coingecko ID.
|
||||
//
|
||||
// The caller must not modify the `*TokenMetadata` returned.
|
||||
func GetTokenByCoingeckoID(coingeckoID string) (*TokenMetadata, bool) {
|
||||
|
||||
result, ok := tokenMetadataByCoingeckoID[coingeckoID]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// The variable `result` is a copy of the value in the map,
|
||||
// so we can safely return it without worrying about it being modified.
|
||||
return &result, true
|
||||
return result, true
|
||||
}
|
||||
|
||||
// tokenMetadata contains information about some of the tokens supported by Portal Token Bridge.
|
||||
// GetTokenByAddress returns information about a token identified by its original mint address.
|
||||
//
|
||||
// The map is indexed by "<tokenChain>-<tokenAddress>", which you can find on Token Bridge transfer payloads.
|
||||
var tokenMetadata = map[string]TokenMetadata{
|
||||
// The caller must not modify the `*TokenMetadata` returned.
|
||||
func GetTokenByAddress(tokenChain sdk.ChainID, tokenAddress string) (*TokenMetadata, bool) {
|
||||
|
||||
key := makeContractID(tokenChain, tokenAddress)
|
||||
|
||||
result, ok := tokenMetadataByContractID[key]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return result, true
|
||||
}
|
||||
|
||||
// tokenMetadata contains information about the most relevant tokens supported by the Token Bridge.
|
||||
var tokenMetadata = []TokenMetadata{
|
||||
// SOL (Portal)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/1/ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5/289384?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDSolana,
|
||||
TokenAddress: "069b8857feab8184fb687f634618c035dac439dc1aeb3b5598a0f00000000001",
|
||||
UnderlyingSymbol: "SOL",
|
||||
Decimals: 9,
|
||||
CoingeckoID: "solana",
|
||||
},
|
||||
// DUST Protocol
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/1/ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5/289670?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDSolana,
|
||||
TokenAddress: "b953b5f8dd5457a2a0f0d41903409785b9d84d4045614faa4f505ee132dcd769",
|
||||
UnderlyingSymbol: "DUST",
|
||||
Decimals: 9,
|
||||
CoingeckoID: "dust-protocol",
|
||||
},
|
||||
// USDCso - USD Coin (Portal from Solana)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/1/ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5/289386?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDSolana,
|
||||
TokenAddress: "c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d61",
|
||||
UnderlyingSymbol: "USDC",
|
||||
Decimals: 6,
|
||||
CoingeckoID: "usd-coin",
|
||||
},
|
||||
// USDTso - Tether USD (Portal from Solana)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/1/ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5/289373?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDSolana,
|
||||
TokenAddress: "ce010e60afedb22717bd63192f54145a3f965a33bb82d2c7029eb2ce1e208264",
|
||||
UnderlyingSymbol: "USDT",
|
||||
Decimals: 6,
|
||||
CoingeckoID: "tether",
|
||||
},
|
||||
{
|
||||
// BRZ - Brazilian Digital
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/1/ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5/289681?parsedPayload=true
|
||||
TokenChain: sdk.ChainIDSolana,
|
||||
TokenAddress: "dd40a2f6f423e4c3990a83eac3d9d9c1fe625b36cbc5e4a6d553544552a867ee",
|
||||
UnderlyingSymbol: "BRZ",
|
||||
Decimals: 4,
|
||||
CoingeckoID: "brz",
|
||||
},
|
||||
// xHashtag
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/6/0000000000000000000000000e082f06ff657d94310cb8ce8b0d9a04541d8052/94898?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDSolana,
|
||||
TokenAddress: "45a5161476cc9df6ef8583b581a3111b4416ebcea65f4eca5bb961124c3399df",
|
||||
UnderlyingSymbol: "XTAG",
|
||||
Decimals: 6,
|
||||
CoingeckoID: "xhashtag",
|
||||
},
|
||||
// Zebec Protocol
|
||||
//
|
||||
// Examples
|
||||
// * https://api.wormscan.io/api/v1/vaas/1/ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5/290406?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDSolana,
|
||||
TokenAddress: "0e167d0db0259fb83bca338947ce42fe2c34b803285c7e99b26874bd83bac0a8",
|
||||
UnderlyingSymbol: "ZBC",
|
||||
Decimals: 8,
|
||||
CoingeckoID: "zebec-protocol",
|
||||
},
|
||||
// USDCet - USDCoin (Portal from Ethereum)
|
||||
//
|
||||
// Examples:
|
||||
// * 21/ccceeb29348f71bdd22ffef43a2a19c1f5b5e17c5cca5411529120182672ade5/922
|
||||
{
|
||||
TokenChain: sdk.ChainIDEthereum,
|
||||
TokenAddress: "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
||||
UnderlyingSymbol: "USDC",
|
||||
Decimals: 6,
|
||||
CoingeckoID: "usd-coin",
|
||||
},
|
||||
// ETH - Ether (Portal)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.staging.wormscan.io/api/v1/vaas/1/ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5/288088?parsedPayload=true
|
||||
"2-0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": {
|
||||
// * https://api.wormscan.io/api/v1/vaas/1/ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5/288088?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDEthereum,
|
||||
TokenAddress: "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
||||
UnderlyingSymbol: "ETH",
|
||||
Decimals: 8,
|
||||
CoingeckoID: "ethereum",
|
||||
},
|
||||
// UST (Wormhole)
|
||||
// USDTet - Tether USD (Portal from Ethereum)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.staging.wormscan.io/api/v1/vaas/2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/111492?parsedPayload=true
|
||||
"3-0x0100000000000000000000000000000000000000000000000000000075757364": {
|
||||
// * https://api.wormscan.io/api/v1/vaas/2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/112361?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDEthereum,
|
||||
TokenAddress: "000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7",
|
||||
UnderlyingSymbol: "USDT",
|
||||
Decimals: 6,
|
||||
CoingeckoID: "tether",
|
||||
},
|
||||
// XCAD
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/112812?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDEthereum,
|
||||
TokenAddress: "0000000000000000000000007659ce147d0e714454073a5dd7003544234b6aa0",
|
||||
UnderlyingSymbol: "XCAD",
|
||||
Decimals: 9,
|
||||
CoingeckoID: "xcad-network",
|
||||
},
|
||||
// ETHIX
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/108181?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDEthereum,
|
||||
TokenAddress: "000000000000000000000000fd09911130e6930bf87f2b0554c44f400bd80d3e",
|
||||
UnderlyingSymbol: "ETHIX",
|
||||
Decimals: 8,
|
||||
CoingeckoID: "ethichub",
|
||||
},
|
||||
// SDEX
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/112815?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDEthereum,
|
||||
TokenAddress: "0000000000000000000000005de8ab7e27f6e7a1fff3e5b337584aa43961beef",
|
||||
UnderlyingSymbol: "SDEX",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "smardex",
|
||||
},
|
||||
// ORION - Orion Money
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/3/0000000000000000000000007cf7b764e38a0a5e967972c1df77d432510564e2/258681?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDEthereum,
|
||||
TokenAddress: "000000000000000000000000727f064a78dc734d33eec18d5370aef32ffd46e4",
|
||||
UnderlyingSymbol: "ORION",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "orion-money",
|
||||
},
|
||||
// SUSHI
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/112824?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDEthereum,
|
||||
TokenAddress: "0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe2",
|
||||
UnderlyingSymbol: "SUSHI",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "sushi",
|
||||
},
|
||||
{
|
||||
// LUNC - Terra Luna Classic
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/4/000000000000000000000000b6f6d86a8f9879a9c87f643768d9efc38c1da6e7/243784?parsedPayload=true
|
||||
TokenChain: sdk.ChainIDTerra,
|
||||
TokenAddress: "010000000000000000000000000000000000000000000000000000756c756e61",
|
||||
UnderlyingSymbol: "LUNC",
|
||||
CoingeckoID: "terra-luna",
|
||||
Decimals: 6,
|
||||
},
|
||||
// UST (Wormhole - Solana)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/111492?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDTerra,
|
||||
TokenAddress: "0100000000000000000000000000000000000000000000000000000075757364",
|
||||
UnderlyingSymbol: "UST",
|
||||
Decimals: 8,
|
||||
CoingeckoID: "terrausd-wormhole",
|
||||
},
|
||||
// Binance-Peg BSC-USD
|
||||
// USDTbs - Tether USD (Portal from BSC)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.staging.wormscan.io/api/v1/vaas/4/000000000000000000000000b6f6d86a8f9879a9c87f643768d9efc38c1da6e7/242342?parsedPayload=true
|
||||
"4-0x00000000000000000000000055d398326f99059ff775485246999027b3197955": {
|
||||
// * https://api.wormscan.io/api/v1/vaas/4/000000000000000000000000b6f6d86a8f9879a9c87f643768d9efc38c1da6e7/242342?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDBSC,
|
||||
TokenAddress: "00000000000000000000000055d398326f99059ff775485246999027b3197955",
|
||||
UnderlyingSymbol: "USDT",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "tether",
|
||||
},
|
||||
// USDCbs - USD Coin (Portal from BSC)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/4/000000000000000000000000b6f6d86a8f9879a9c87f643768d9efc38c1da6e7/243491?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDBSC,
|
||||
TokenAddress: "0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d",
|
||||
UnderlyingSymbol: "USDC",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "usd-coin",
|
||||
},
|
||||
// BNB - Binance Coin (Portal)
|
||||
//
|
||||
// Examples:
|
||||
// * 21/ccceeb29348f71bdd22ffef43a2a19c1f5b5e17c5cca5411529120182672ade5/910
|
||||
{
|
||||
TokenChain: sdk.ChainIDBSC,
|
||||
TokenAddress: "000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
|
||||
UnderlyingSymbol: "BNB",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "binancecoin",
|
||||
},
|
||||
// WOM - Wombat exchange
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/4/000000000000000000000000b6f6d86a8f9879a9c87f643768d9efc38c1da6e7/243788?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDBSC,
|
||||
TokenAddress: "000000000000000000000000ad6742a35fb341a9cc6ad674738dd8da98b94fb1",
|
||||
UnderlyingSymbol: "WOM",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "wombat-exchange",
|
||||
},
|
||||
// BUSDbs - Binance USD (Portal from BSC)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/4/000000000000000000000000b6f6d86a8f9879a9c87f643768d9efc38c1da6e7/243489?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDBSC,
|
||||
TokenAddress: "000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d56",
|
||||
UnderlyingSymbol: "BUSD",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "binance-usd",
|
||||
},
|
||||
// MagicCraft
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/4/000000000000000000000000b6f6d86a8f9879a9c87f643768d9efc38c1da6e7/244486?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDBSC,
|
||||
TokenAddress: "",
|
||||
UnderlyingSymbol: "MCRT",
|
||||
Decimals: 8,
|
||||
CoingeckoID: "magiccraft",
|
||||
},
|
||||
// USDCpo - USD Coin (PoS) (Portal from Polygon)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/1/ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5/289376?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDPolygon,
|
||||
TokenAddress: "0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174",
|
||||
UnderlyingSymbol: "USDC",
|
||||
Decimals: 6,
|
||||
CoingeckoID: "usd-coin",
|
||||
},
|
||||
// USDTpo - Tether USD (PoS) (Portal from Polygon)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/5/0000000000000000000000005a58505a96d1dbf8df91cb21b54419fc36e93fde/100225?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDPolygon,
|
||||
TokenAddress: "000000000000000000000000c2132d05d31c914a87c6611c10748aeb04b58e8f",
|
||||
UnderlyingSymbol: "USDT",
|
||||
Decimals: 6,
|
||||
CoingeckoID: "tether",
|
||||
},
|
||||
// MATICpo - MATIC (Portal from Polygon)
|
||||
//
|
||||
// Examples:
|
||||
// * 21/ccceeb29348f71bdd22ffef43a2a19c1f5b5e17c5cca5411529120182672ade5/913
|
||||
{
|
||||
TokenChain: sdk.ChainIDPolygon,
|
||||
TokenAddress: "0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270",
|
||||
UnderlyingSymbol: "MATIC",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "matic-network",
|
||||
},
|
||||
// AVAX (Portal)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/6/0000000000000000000000000e082f06ff657d94310cb8ce8b0d9a04541d8052/94692?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDAvalanche,
|
||||
TokenAddress: "000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7",
|
||||
UnderlyingSymbol: "AVAX",
|
||||
Decimals: 18,
|
||||
CoingeckoID: "avalanche-2",
|
||||
},
|
||||
// USDCav - USD Coin (Portal from Avalanche)
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/6/0000000000000000000000000e082f06ff657d94310cb8ce8b0d9a04541d8052/94690?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDAvalanche,
|
||||
TokenAddress: "000000000000000000000000b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e",
|
||||
UnderlyingSymbol: "USDC",
|
||||
Decimals: 6,
|
||||
CoingeckoID: "usd-coin",
|
||||
},
|
||||
// WFTM - Wrapped Fantom
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.staging.wormscan.io/api/v1/vaas/10/0000000000000000000000007c9fc5741288cdfdd83ceb07f3ea7e22618d79d2/25144?parsedPayload=true
|
||||
"10-0x00000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c83": {
|
||||
// * https://api.wormscan.io/api/v1/vaas/10/0000000000000000000000007c9fc5741288cdfdd83ceb07f3ea7e22618d79d2/25144?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDFantom,
|
||||
TokenAddress: "00000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c83",
|
||||
UnderlyingSymbol: "FTM",
|
||||
Decimals: 8,
|
||||
CoingeckoID: "fantom",
|
||||
},
|
||||
// SUI
|
||||
//
|
||||
// Examples:
|
||||
// * 21/ccceeb29348f71bdd22ffef43a2a19c1f5b5e17c5cca5411529120182672ade5/1247
|
||||
{
|
||||
TokenChain: sdk.ChainIDSui,
|
||||
TokenAddress: "9258181f5ceac8dbffb7030890243caed69a9599d2886d957a9cb7656af3bdb3",
|
||||
UnderlyingSymbol: "SUI",
|
||||
Decimals: 9,
|
||||
CoingeckoID: "sui",
|
||||
},
|
||||
{
|
||||
//TODO find the ContractAddress, decimals and an example VAA for this token.
|
||||
TokenChain: sdk.ChainIDAcala,
|
||||
UnderlyingSymbol: "ACA",
|
||||
CoingeckoID: "acala",
|
||||
},
|
||||
{
|
||||
//TODO find the ContractAddress, decimals and an example VAA for this token.
|
||||
TokenChain: sdk.ChainIDAlgorand,
|
||||
UnderlyingSymbol: "ALGO",
|
||||
CoingeckoID: "algorand",
|
||||
},
|
||||
{
|
||||
//TODO find the ContractAddress, decimals and an example VAA for this token.
|
||||
TokenChain: sdk.ChainIDAptos,
|
||||
UnderlyingSymbol: "APT",
|
||||
CoingeckoID: "aptos",
|
||||
},
|
||||
// USD Coin
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/5/0000000000000000000000005a58505a96d1dbf8df91cb21b54419fc36e93fde/101667?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDAptos,
|
||||
TokenAddress: "6155e0a106aeb3b0944388613027aee11c84921969ff775727e8046b17b17154",
|
||||
UnderlyingSymbol: "USDC",
|
||||
Decimals: 6,
|
||||
CoingeckoID: "usd-coin",
|
||||
},
|
||||
{
|
||||
// WGLMR
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/16/000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92/5897?parsedPayload=true
|
||||
TokenChain: sdk.ChainIDMoonbeam,
|
||||
TokenAddress: "000000000000000000000000acc15dc74880c9944775448304b263d191c6077f",
|
||||
UnderlyingSymbol: "WGLMR",
|
||||
Decimals: 8,
|
||||
CoingeckoID: "moonbeam",
|
||||
},
|
||||
// WETH - moonbeam
|
||||
//
|
||||
// Examples:
|
||||
// * https://api.wormscan.io/api/v1/vaas/16/000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92/5898?parsedPayload=true
|
||||
{
|
||||
TokenChain: sdk.ChainIDMoonbeam,
|
||||
TokenAddress: "00000000000000000000000030d2a9f5fdf90ace8c17952cbb4ee48a55d916a7",
|
||||
UnderlyingSymbol: "WETH",
|
||||
Decimals: 8,
|
||||
CoingeckoID: "weth",
|
||||
},
|
||||
{
|
||||
//TODO find missing data for this token
|
||||
// aUST
|
||||
// ContractAddress: "000000000000000000000000b8ae5604d7858eaa46197b19494b595b586e466c",
|
||||
},
|
||||
{
|
||||
//TODO find missing data for this token
|
||||
// WBNB
|
||||
// ContractAddress: "000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -55,40 +55,11 @@ func (c *CoingeckoAPI) GetNotionalUSD(ids []string) (map[string]NotionalUSD, err
|
|||
|
||||
// GetChainIDs returns the coingecko chain ids for the given p2p network.
|
||||
func GetChainIDs(p2pNetwork string) []string {
|
||||
|
||||
if p2pNetwork == domain.P2pMainNet {
|
||||
return []string{
|
||||
"solana",
|
||||
"ethereum",
|
||||
"terra-luna",
|
||||
"binancecoin",
|
||||
"matic-network",
|
||||
"avalanche-2",
|
||||
"oasis-network",
|
||||
"algorand",
|
||||
"aurora",
|
||||
"fantom",
|
||||
"karura",
|
||||
"acala",
|
||||
"klay-token",
|
||||
"celo",
|
||||
"near",
|
||||
"moonbeam",
|
||||
"neon",
|
||||
"terra-luna-2",
|
||||
"injective-protocol",
|
||||
"aptos",
|
||||
"sui",
|
||||
"arbitrum",
|
||||
"optimism",
|
||||
"xpla",
|
||||
"bitcoin",
|
||||
"base-protocol",
|
||||
"tether",
|
||||
"usd-coin",
|
||||
"binance-usd",
|
||||
"terrausd-wormhole",
|
||||
}
|
||||
return domain.GetAllCoingeckoIDs()
|
||||
}
|
||||
|
||||
// TODO: define chains ids for testnet.
|
||||
return []string{}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,11 @@ import (
|
|||
|
||||
"github.com/go-redis/redis"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/common/client/cache/notional"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/jobs/internal/coingecko"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Symbol string
|
||||
|
||||
// NotionalJob is the job to get the notional value of assets.
|
||||
type NotionalJob struct {
|
||||
coingeckoAPI *coingecko.CoingeckoAPI
|
||||
|
@ -35,6 +34,7 @@ func NewNotionalJob(api *coingecko.CoingeckoAPI, cacheClient *redis.Client, p2pN
|
|||
|
||||
// Run runs the notional job.
|
||||
func (j *NotionalJob) Run() error {
|
||||
|
||||
// get chains coingecko ids by p2p network.
|
||||
chainIDs := coingecko.GetChainIDs(j.p2pNetwork)
|
||||
if len(chainIDs) == 0 {
|
||||
|
@ -73,7 +73,7 @@ func (j *NotionalJob) Run() error {
|
|||
}
|
||||
|
||||
// updateNotionalCache updates the notional value of assets in cache.
|
||||
func (j *NotionalJob) updateNotionalCache(notionals map[Symbol]notional.PriceData) error {
|
||||
func (j *NotionalJob) updateNotionalCache(notionals map[domain.Symbol]notional.PriceData) error {
|
||||
|
||||
for chainID, n := range notionals {
|
||||
key := fmt.Sprintf(notional.KeyFormatString, chainID)
|
||||
|
@ -89,9 +89,9 @@ func (j *NotionalJob) updateNotionalCache(notionals map[Symbol]notional.PriceDat
|
|||
// convertToSymbols converts the coingecko response into a symbol map
|
||||
//
|
||||
// The returned map has symbols as keys, and price data as the values.
|
||||
func convertToSymbols(m map[string]coingecko.NotionalUSD) map[Symbol]notional.PriceData {
|
||||
func convertToSymbols(m map[string]coingecko.NotionalUSD) map[domain.Symbol]notional.PriceData {
|
||||
|
||||
w := make(map[Symbol]notional.PriceData, len(m))
|
||||
w := make(map[domain.Symbol]notional.PriceData, len(m))
|
||||
now := time.Now()
|
||||
|
||||
for k, v := range m {
|
||||
|
@ -101,74 +101,15 @@ func convertToSymbols(m map[string]coingecko.NotionalUSD) map[Symbol]notional.Pr
|
|||
continue
|
||||
}
|
||||
|
||||
var symbol Symbol
|
||||
|
||||
switch k {
|
||||
case "solana":
|
||||
symbol = "SOL"
|
||||
case "ethereum":
|
||||
symbol = "ETH"
|
||||
case "terra-luna":
|
||||
symbol = "LUNC"
|
||||
case "binancecoin":
|
||||
symbol = "BNB"
|
||||
case "matic-network":
|
||||
symbol = "MATIC"
|
||||
case "avalanche-2":
|
||||
symbol = "AVAX"
|
||||
case "oasis-network":
|
||||
symbol = "ROSE"
|
||||
case "algorand":
|
||||
symbol = "ALGO"
|
||||
case "aurora":
|
||||
symbol = "AURORA"
|
||||
case "fantom":
|
||||
symbol = "FTM"
|
||||
case "karura":
|
||||
symbol = "KAR"
|
||||
case "acala":
|
||||
symbol = "ACA"
|
||||
case "klay-token":
|
||||
symbol = "KLAY"
|
||||
case "celo":
|
||||
symbol = "CELO"
|
||||
case "near":
|
||||
symbol = "NEAR"
|
||||
case "moonbeam":
|
||||
symbol = "GLMR"
|
||||
case "neon":
|
||||
symbol = "NEON"
|
||||
case "terra-luna-2":
|
||||
symbol = "LUNA"
|
||||
case "injective-protocol":
|
||||
symbol = "INJ"
|
||||
case "aptos":
|
||||
symbol = "APT"
|
||||
case "sui":
|
||||
symbol = "SUI"
|
||||
case "arbitrum":
|
||||
symbol = "ARB"
|
||||
case "optimism":
|
||||
symbol = "OP"
|
||||
case "xpla":
|
||||
symbol = "XPLA"
|
||||
case "bitcoin":
|
||||
symbol = "BTC"
|
||||
case "base-protocol":
|
||||
symbol = "BASE"
|
||||
case "tether":
|
||||
symbol = "USDT"
|
||||
case "usd-coin":
|
||||
symbol = "USDC"
|
||||
case "binance-usd":
|
||||
symbol = "BUSD"
|
||||
case "terrausd-wormhole":
|
||||
symbol = "UST"
|
||||
// Translate coingecko IDs into their associated ticker symbols
|
||||
tokenMeta, ok := domain.GetTokenByCoingeckoID(k)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if symbol != "" {
|
||||
w[symbol] = notional.PriceData{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||
}
|
||||
// Set price data for the current symbol
|
||||
w[tokenMeta.UnderlyingSymbol] = notional.PriceData{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||
}
|
||||
|
||||
return w
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue