github.com/wormhole-foundation/wormhole-explorer/common@v0.0.0-20240604151348-09585b5b97c5/domain/tokens.go (about)

     1  package domain
     2  
     3  import (
     4  	"fmt"
     5  
     6  	sdk "github.com/wormhole-foundation/wormhole/sdk/vaa"
     7  )
     8  
     9  // Symbol identifies a publicly traded token (i.e. "ETH" for Ethereum, "ALGO" for Algorand, etc.)
    10  type Symbol string
    11  
    12  func (s Symbol) String() string {
    13  	return string(s)
    14  }
    15  
    16  // TokenMetadata contains information about a token supported by Portal Token Bridge.
    17  type TokenMetadata struct {
    18  	TokenChain   sdk.ChainID
    19  	TokenAddress string
    20  	// Symbol is the name that crypto exchanges use to list the underlying asset represented by this token.
    21  	// For example, the underlying symbol of the token "USDCso (USDC minted on Solana)" is "USDC".
    22  	Symbol      Symbol
    23  	CoingeckoID string
    24  	Decimals    int64
    25  }
    26  
    27  type TokenProvider struct {
    28  	p2pNetwork                 string
    29  	tokenMetadata              []TokenMetadata
    30  	tokenMetadataByContractID  map[string]*TokenMetadata
    31  	tokenMetadataByCoingeckoID map[string]*TokenMetadata
    32  }
    33  
    34  func (t *TokenMetadata) GetTokenID() string {
    35  	return fmt.Sprintf("%d/%s", t.TokenChain, t.TokenAddress)
    36  }
    37  
    38  func makeContractID(tokenChain sdk.ChainID, tokenAddress string) string {
    39  	return fmt.Sprintf("%d-%s", tokenChain, tokenAddress)
    40  }
    41  
    42  func NewTokenProvider(p2pNetwork string) *TokenProvider {
    43  	var tokenMetadata []TokenMetadata
    44  
    45  	switch p2pNetwork {
    46  	case P2pMainNet:
    47  		tokenMetadata = mainnetTokenList()
    48  	case P2pTestNet:
    49  		tokenMetadata = manualTestnetTokenList()
    50  	default:
    51  		panic(fmt.Sprintf("unknown p2p network: %s", p2pNetwork))
    52  	}
    53  
    54  	tokenMetadataByContractID := make(map[string]*TokenMetadata)
    55  	tokenMetadataByCoingeckoID := make(map[string]*TokenMetadata)
    56  
    57  	for i := range tokenMetadata {
    58  		// populate the map `tokenMetadataByCoingeckoID`
    59  		coingeckoID := tokenMetadata[i].CoingeckoID
    60  		if coingeckoID != "" {
    61  			tokenMetadataByCoingeckoID[coingeckoID] = &tokenMetadata[i]
    62  		}
    63  
    64  		// populate the map `tokenMetadataByContractID`
    65  		contractID := makeContractID(tokenMetadata[i].TokenChain, tokenMetadata[i].TokenAddress)
    66  		if contractID != "" {
    67  			tokenMetadataByContractID[contractID] = &tokenMetadata[i]
    68  		}
    69  	}
    70  	return &TokenProvider{
    71  		p2pNetwork:                 p2pNetwork,
    72  		tokenMetadata:              tokenMetadata,
    73  		tokenMetadataByContractID:  tokenMetadataByContractID,
    74  		tokenMetadataByCoingeckoID: tokenMetadataByCoingeckoID,
    75  	}
    76  }
    77  
    78  // GetAllTokens returns a list of all tokens that exist in the database.
    79  //
    80  // The caller must not modify the `[]TokenMetadata` returned.
    81  func (t *TokenProvider) GetAllTokens() []TokenMetadata {
    82  	return t.tokenMetadata
    83  }
    84  
    85  // GetAllCoingeckoIDs returns a list of all coingecko IDs that exist in the database.
    86  func (t *TokenProvider) GetAllCoingeckoIDs() []string {
    87  
    88  	// use a map to remove duplicates
    89  	uniqueIDs := make(map[string]bool, len(t.tokenMetadata))
    90  	for i := range t.tokenMetadata {
    91  		uniqueIDs[t.tokenMetadata[i].CoingeckoID] = true
    92  	}
    93  
    94  	// collect keys into a slice
    95  	ids := make([]string, 0, len(uniqueIDs))
    96  	for k := range uniqueIDs {
    97  		ids = append(ids, k)
    98  	}
    99  
   100  	return ids
   101  }
   102  
   103  // GetTokenByCoingeckoID returns information about a token identified by its coingecko ID.
   104  //
   105  // The caller must not modify the `*TokenMetadata` returned.
   106  func (t *TokenProvider) GetTokenByCoingeckoID(coingeckoID string) (*TokenMetadata, bool) {
   107  
   108  	result, ok := t.tokenMetadataByCoingeckoID[coingeckoID]
   109  	if !ok {
   110  		return nil, false
   111  	}
   112  
   113  	return result, true
   114  }
   115  
   116  // GetTokenByAddress returns information about a token identified by its original mint address.
   117  //
   118  // The caller must not modify the `*TokenMetadata` returned.
   119  func (t *TokenProvider) GetTokenByAddress(tokenChain sdk.ChainID, tokenAddress string) (*TokenMetadata, bool) {
   120  
   121  	key := makeContractID(tokenChain, tokenAddress)
   122  
   123  	result, ok := t.tokenMetadataByContractID[key]
   124  	if !ok {
   125  		return nil, false
   126  	}
   127  
   128  	return result, true
   129  }
   130  
   131  func (t *TokenProvider) GetP2pNewtork() string {
   132  	return t.p2pNetwork
   133  }