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:
agodnic 2023-05-08 17:51:18 -03:00 committed by GitHub
parent e2f32c2883
commit a31d59822d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 487 additions and 133 deletions

View File

@ -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)

View File

@ -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()
`

View File

@ -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

View File

@ -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
}

View File

@ -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",
},
}

View File

@ -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{}
}

View File

@ -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
}