package domain import ( "fmt" 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 { TokenChain sdk.ChainID TokenAddress string // Symbol is the name that crypto exchanges use to list the underlying asset represented by this token. // For example, the underlying symbol of the token "USDCso (USDC minted on Solana)" is "USDC". Symbol Symbol CoingeckoID string Decimals int64 } type TokenProvider struct { p2pNetwork string tokenMetadata []TokenMetadata tokenMetadataByContractID map[string]*TokenMetadata tokenMetadataByCoingeckoID map[string]*TokenMetadata } func (t *TokenMetadata) GetTokenID() string { return fmt.Sprintf("%d/%s", t.TokenChain, t.TokenAddress) } func makeContractID(tokenChain sdk.ChainID, tokenAddress string) string { return fmt.Sprintf("%d-%s", tokenChain, tokenAddress) } func NewTokenProvider(p2pNetwork string) *TokenProvider { var tokenMetadata []TokenMetadata switch p2pNetwork { case P2pMainNet: tokenMetadata = generatedMainnetTokenList() case P2pTestNet: tokenMetadata = manualTestnetTokenList() default: panic(fmt.Sprintf("unknown p2p network: %s", p2pNetwork)) } tokenMetadataByContractID := make(map[string]*TokenMetadata) tokenMetadataByCoingeckoID := make(map[string]*TokenMetadata) 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] } } return &TokenProvider{ p2pNetwork: p2pNetwork, tokenMetadata: tokenMetadata, tokenMetadataByContractID: tokenMetadataByContractID, tokenMetadataByCoingeckoID: tokenMetadataByCoingeckoID, } } // GetAllTokens returns a list of all tokens that exist in the database. // // The caller must not modify the `[]TokenMetadata` returned. func (t *TokenProvider) GetAllTokens() []TokenMetadata { return t.tokenMetadata } // GetAllCoingeckoIDs returns a list of all coingecko IDs that exist in the database. func (t *TokenProvider) GetAllCoingeckoIDs() []string { // use a map to remove duplicates uniqueIDs := make(map[string]bool, len(t.tokenMetadata)) for i := range t.tokenMetadata { uniqueIDs[t.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 (t *TokenProvider) GetTokenByCoingeckoID(coingeckoID string) (*TokenMetadata, bool) { result, ok := t.tokenMetadataByCoingeckoID[coingeckoID] if !ok { return nil, false } return result, true } // GetTokenByAddress returns information about a token identified by its original mint address. // // The caller must not modify the `*TokenMetadata` returned. func (t *TokenProvider) GetTokenByAddress(tokenChain sdk.ChainID, tokenAddress string) (*TokenMetadata, bool) { key := makeContractID(tokenChain, tokenAddress) result, ok := t.tokenMetadataByContractID[key] if !ok { return nil, false } return result, true } func (t *TokenProvider) GetP2pNewtork() string { return t.p2pNetwork }