From 9ad3aac1d66ba6f0cb12e07be5897da84dde250a Mon Sep 17 00:00:00 2001 From: Satish Ravi Date: Fri, 29 Sep 2023 12:22:16 -0700 Subject: [PATCH 1/5] feat(tokens): add more fields to metadata --- src/data/mainnet/celo-tokens-info.json | 59 +++++++++++++------ src/data/mainnet/ethereum-tokens-info.json | 8 ++- .../testnet/celo-alfajores-tokens-info.json | 29 ++++++--- .../testnet/ethereum-sepolia-tokens-info.json | 8 ++- src/index.test.ts | 4 +- src/schemas.test.ts | 37 +++++++++++- src/schemas/tokens-info.ts | 29 ++++++--- src/tokens-info.ts | 14 ++++- src/types.ts | 10 ++++ 9 files changed, 156 insertions(+), 42 deletions(-) diff --git a/src/data/mainnet/celo-tokens-info.json b/src/data/mainnet/celo-tokens-info.json index b34e5b79..1f9c0f72 100644 --- a/src/data/mainnet/celo-tokens-info.json +++ b/src/data/mainnet/celo-tokens-info.json @@ -4,7 +4,8 @@ "decimals": 18, "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/POOF.png", "name": "PoofCash", - "symbol": "POOF" + "symbol": "POOF", + "infoUrl": "https://www.coingecko.com/en/coins/poofcash" }, { "address": "0xc668583dcbdc9ae6fa3ce46462758188adfdfc24", @@ -20,7 +21,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/UBE.png", "name": "Ubeswap", "symbol": "UBE", - "isSwappable": true + "isSwappable": true, + "infoUrl": "https://www.coingecko.com/en/coins/ubeswap" }, { "address": "0x035ee610693a29cb77fd6efbeb9d9d278703e145", @@ -68,7 +70,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/MOO.png", "name": "Moola", "symbol": "MOO", - "isSwappable": true + "isSwappable": true, + "infoUrl": "https://www.coingecko.com/en/coins/moola-market" }, { "address": "0x1a8dbe5958c597a744ba51763abebd3355996c3e", @@ -91,7 +94,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ARI.png", "name": "Ari Swap", "symbol": "ARI", - "minimumAppVersionToSwap": "1.60.0" + "minimumAppVersionToSwap": "1.60.0", + "infoUrl": "https://www.coingecko.com/en/coins/ari-swap" }, { "address": "0x218c3c3d49d0e7b37aff0d8bb079de36ae61a4c0", @@ -180,7 +184,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/PACT.png", "name": "impactMarket", "symbol": "PACT", - "minimumAppVersionToSwap": "1.60.0" + "minimumAppVersionToSwap": "1.60.0", + "infoUrl": "https://www.coingecko.com/en/coins/impactmarket" }, { "address": "0x471ece3750da237f93b8e339c536989b8978a438", @@ -190,7 +195,9 @@ "name": "Celo", "symbol": "CELO", "isSwappable": true, - "isNative": true + "isNative": true, + "isZeroState": true, + "infoUrl": "https://www.coingecko.com/en/coins/celo" }, { "address": "0x47264ae1fc0c8e6418ebe78630718e11a07346a8", @@ -233,7 +240,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/mCELOxOLD.png", "name": "Moola CELO AToken", "symbol": "mCELO", - "pegTo": "0x471ece3750da237f93b8e339c536989b8978a438" + "pegTo": "0x471ece3750da237f93b8e339c536989b8978a438", + "infoUrl": "https://www.coingecko.com/en/coins/moola-celo-atoken" }, { "address": "0x73a210637f6f6b7005512677ba6b3c96bb4aa44b", @@ -249,7 +257,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/SOURCE.png", "name": "Source", "symbol": "SOURCE", - "minimumAppVersionToSwap": "1.60.0" + "minimumAppVersionToSwap": "1.60.0", + "infoUrl": "https://www.coingecko.com/en/coins/resource-protocol" }, { "address": "0x765de816845861e75a25fca122bb6898b8b1282a", @@ -259,7 +268,10 @@ "name": "Celo Dollar", "symbol": "cUSD", "isSupercharged": true, - "isSwappable": true + "isSwappable": true, + "isZeroState": true, + "hidePriceDelta": true, + "infoUrl": "https://www.coingecko.com/en/coins/celo-dollar" }, { "address": "0x7c2bf103daac9c082a0e53ad40bb9f3f7f799af7", @@ -274,7 +286,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/mCELO.png", "name": "Moola interest bearing CELO", "symbol": "mCELO", - "isSwappable": true + "isSwappable": true, + "infoUrl": "https://www.coingecko.com/en/coins/mcelo" }, { "address": "0x8427bd503dd3169ccc9aff7326c15258bc305478", @@ -300,7 +313,8 @@ "symbol": "mCUSD", "pegTo": "0x765de816845861e75a25fca122bb6898b8b1282a", "isSupercharged": true, - "isSwappable": true + "isSwappable": true, + "infoUrl": "https://www.coingecko.com/en/coins/moola-celo-dollars" }, { "address": "0x94140c2ea9d208d8476ca4e3045254169791c59e", @@ -308,7 +322,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/PREMIO.png", "name": "PREMIO", "symbol": "PREMIO", - "minimumAppVersionToSwap": "1.60.0" + "minimumAppVersionToSwap": "1.60.0", + "infoUrl": "https://www.coingecko.com/en/coins/premio" }, { "address": "0xa649325aa7c5093d12d6f98eb4378deae68ce23f", @@ -384,7 +399,9 @@ "name": "Celo Euro", "symbol": "cEUR", "isSupercharged": true, - "isSwappable": true + "isSwappable": true, + "hidePriceDelta": true, + "infoUrl": "https://www.coingecko.com/en/coins/celo-euro" }, { "address": "0xd90bbdf5904cb7d275c41f897495109b9a5ada58", @@ -400,7 +417,8 @@ "symbol": "mCEUR", "pegTo": "0xd8763cba276a3738e6de85b4b3bf5fded6d6ca73", "isSupercharged": true, - "isSwappable": true + "isSwappable": true, + "infoUrl": "https://www.coingecko.com/en/coins/mceur" }, { "address": "0xe685d21b7b0fc7a248a6a8e03b8db22d013aa2ee", @@ -408,7 +426,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/IMMO.png", "name": "Immortal", "symbol": "IMMO", - "minimumAppVersionToSwap": "1.60.0" + "minimumAppVersionToSwap": "1.60.0", + "infoUrl": "https://www.coingecko.com/en/coins/immortaldao" }, { "address": "0xe74abf23e1fdf7acbec2f3a30a772ef77f1601e1", @@ -425,7 +444,9 @@ "name": "Celo Brazilian Real", "symbol": "cREAL", "isSupercharged": true, - "isSwappable": true + "isSwappable": true, + "hidePriceDelta": true, + "infoUrl": "https://www.coingecko.com/en/coins/celo-real-creal" }, { "address": "0xe919f65739c26a42616b7b8eedc6b5524d1e3ac4", @@ -448,7 +469,8 @@ "symbol": "mCREAL", "isSupercharged": true, "pegTo": "0xe8537a3d056da446677b9e9d6c5db704eaab4787", - "isSwappable": true + "isSwappable": true, + "infoUrl": "https://www.coingecko.com/en/coins/moola-interest-bearing-creal" }, { "address": "0x9995cc8f20db5896943afc8ee0ba463259c931ed", @@ -465,7 +487,8 @@ "name": "Plastik", "symbol": "PLASTIK", "isSwappable": false, - "minimumAppVersionToSwap": "1.60.0" + "minimumAppVersionToSwap": "1.60.0", + "infoUrl": "https://www.coingecko.com/en/coins/plastiks" }, { "address": "0x8a1639098644a229d08f441ea45a63ae050ee018", diff --git a/src/data/mainnet/ethereum-tokens-info.json b/src/data/mainnet/ethereum-tokens-info.json index 1c582f49..7975140e 100644 --- a/src/data/mainnet/ethereum-tokens-info.json +++ b/src/data/mainnet/ethereum-tokens-info.json @@ -4,13 +4,17 @@ "symbol": "ETH", "decimals": 18, "isNative": true, - "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png" + "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png", + "isZeroState": true, + "infoUrl": "https://www.coingecko.com/en/coins/ethereum" }, { "name": "USD Coin", "symbol": "USDC", "decimals": 6, "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", - "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/USDC.png" + "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/USDC.png", + "hidePriceDelta": true, + "infoUrl": "https://www.coingecko.com/en/coins/usdc" } ] diff --git a/src/data/testnet/celo-alfajores-tokens-info.json b/src/data/testnet/celo-alfajores-tokens-info.json index 8966f582..415ddfe6 100644 --- a/src/data/testnet/celo-alfajores-tokens-info.json +++ b/src/data/testnet/celo-alfajores-tokens-info.json @@ -4,7 +4,8 @@ "decimals": 18, "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/UBE.png", "name": "Ubeswap", - "symbol": "UBE" + "symbol": "UBE", + "infoUrl": "https://www.coingecko.com/en/coins/ubeswap" }, { "address": "0x048f47d358ec521a6cf384461d674750a3cb58c8", @@ -20,7 +21,9 @@ "isCoreToken": true, "name": "Celo Euro", "symbol": "cEUR", - "isSupercharged": true + "isSupercharged": true, + "hidePriceDelta": true, + "infoUrl": "https://www.coingecko.com/en/coins/celo-euro" }, { "address": "0x123ed050805e0998ebef43671327139224218e50", @@ -111,7 +114,10 @@ "isCoreToken": true, "name": "Celo Dollar", "symbol": "cUSD", - "isSupercharged": true + "isSupercharged": true, + "isZeroState": true, + "hidePriceDelta": true, + "infoUrl": "https://www.coingecko.com/en/coins/celo-dollar" }, { "address": "0x8d0b8633c6c3d5c1eafb767b3eaf0723e49c9c98", @@ -174,7 +180,9 @@ "isCoreToken": true, "name": "Celo Real", "symbol": "cREAL", - "isSupercharged": true + "isSupercharged": true, + "hidePriceDelta": true, + "infoUrl": "https://www.coingecko.com/en/coins/celo-real-creal" }, { "address": "0xf194afdf50b03e69bd7d057c1aa9e10c9954e4c9", @@ -183,7 +191,9 @@ "isCoreToken": true, "name": "Celo", "symbol": "CELO", - "isNative": true + "isNative": true, + "isZeroState": true, + "infoUrl": "https://www.coingecko.com/en/coins/celo" }, { "address": "0x3a0ea4e0806805527c750ab9b34382642448468d", @@ -191,7 +201,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/mcUSD.png", "name": "Moola interest bearing CUSD", "symbol": "mCUSD", - "isSupercharged": true + "isSupercharged": true, + "infoUrl": "https://www.coingecko.com/en/coins/moola-celo-dollars" }, { "address": "0x0d9b4311657003251d1efa085e74f761185f271c", @@ -199,7 +210,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/mcEUR.png", "name": "Moola interest bearing CEUR", "symbol": "mCEUR", - "isSupercharged": true + "isSupercharged": true, + "infoUrl": "https://www.coingecko.com/en/coins/mceur" }, { "address": "0x3d0eda535ca4b15c739d46761d24e42e37664ad7", @@ -207,7 +219,8 @@ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/mcREAL.png", "name": "Moola interest bearing CREAL", "symbol": "mCREAL", - "isSupercharged": true + "isSupercharged": true, + "infoUrl": "https://www.coingecko.com/en/coins/moola-interest-bearing-creal" }, { "address": "0x4620d7a5f58f77eee69a38afdaa8f2ffb10b42b6", diff --git a/src/data/testnet/ethereum-sepolia-tokens-info.json b/src/data/testnet/ethereum-sepolia-tokens-info.json index d3f40b24..ad1ad86c 100644 --- a/src/data/testnet/ethereum-sepolia-tokens-info.json +++ b/src/data/testnet/ethereum-sepolia-tokens-info.json @@ -4,13 +4,17 @@ "symbol": "ETH", "decimals": 18, "isNative": true, - "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png" + "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png", + "isZeroState": true, + "infoUrl": "https://www.coingecko.com/en/coins/ethereum" }, { "name": "USD Coin", "symbol": "USDC", "decimals": 6, "address": "0x8267cf9254734c6eb452a7bb9aaf97b392258b21", - "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/USDC.png" + "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/USDC.png", + "hidePriceDelta": true, + "infoUrl": "https://www.coingecko.com/en/coins/usdc" } ] diff --git a/src/index.test.ts b/src/index.test.ts index ac63ba88..8af605dd 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,6 +1,6 @@ import { _getTokensInfoHttpFunction } from './index' import { loadCloudFunctionConfig } from './config' -import { NetworkId } from './types' +import { NetworkId, NetworkName } from './types' import { getTokensInfoByNetworkIds } from './tokens-info' import mocked = jest.mocked @@ -25,6 +25,7 @@ describe('index', () => { imageUrl: 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png', tokenId: 'ethereum-mainnet:native', + networkName: NetworkName.Ethereum, }, 'celo-mainnet:native': { address: '0x471ece3750da237f93b8e339c536989b8978a438', @@ -37,6 +38,7 @@ describe('index', () => { isNative: true, networkId: NetworkId['celo-mainnet'], tokenId: 'celo-mainnet:native', + networkName: NetworkName.Celo, }, } mocked(getTokensInfoByNetworkIds).mockReturnValue(mockTokensInfo) diff --git a/src/schemas.test.ts b/src/schemas.test.ts index 1b828478..bb232fe1 100644 --- a/src/schemas.test.ts +++ b/src/schemas.test.ts @@ -1,6 +1,6 @@ import { getCeloRTDBMetadata } from './index' import { getTokensInfoByNetworkIds } from './tokens-info' -import { NetworkId, TokenInfo } from './types' +import { NetworkId, NetworkName, TokenInfo } from './types' import { TokenInfoSchemaProcessed, RTDBAddressToTokenInfoSchema, @@ -17,7 +17,7 @@ function validateWithSchema(value: any, schema: Joi.Schema) { describe('Schema validation', () => { describe('Joi sanity checks', () => { - describe('TokenInfoSchema', () => { + describe('TokenInfoSchemaJSON', () => { it('forbids CELO to not have an address', () => { const validationResult = validateWithSchema( { @@ -54,6 +54,39 @@ describe('Schema validation', () => { expect(validationResult.error).toBeDefined() }) }) + describe('TokenInfoSchemaProcessed', () => { + it('forbids native tokens to have networkIconUrl', () => { + const validationResult = validateWithSchema( + { + name: 'New native token', + symbol: 'XYZ', + decimals: 18, + isNative: true, + networkId: NetworkId['celo-alfajores'], + networkName: NetworkName.Celo, + tokenId: 'some-token', + networkIconUrl: 'https://some-icon', + }, + TokenInfoSchemaProcessed, + ) + expect(validationResult.error).toBeDefined() + }) + it('requires non-native tokens to have networkIconUrl', () => { + const validationResult = validateWithSchema( + { + name: 'New native token', + symbol: 'XYZ', + decimals: 18, + networkId: NetworkId['celo-alfajores'], + networkName: NetworkName.Celo, + tokenId: 'some-token', + address: '0x471ece3750da237f93b8e339c536989b8978a438', + }, + TokenInfoSchemaProcessed, + ) + expect(validationResult.error).toBeDefined() + }) + }) describe('RTDBAddressToTokenInfoSchema', () => { it('forbids pegging to phantom address', () => { const validationResult = validateWithSchema( diff --git a/src/schemas/tokens-info.ts b/src/schemas/tokens-info.ts index 8d63646c..12a130fb 100644 --- a/src/schemas/tokens-info.ts +++ b/src/schemas/tokens-info.ts @@ -4,7 +4,7 @@ import { URL } from 'url' import path from 'path' import AddressSchema from './address-schema' import semver from 'semver' -import { NetworkId } from '../types' +import { NetworkId, NetworkName } from '../types' export const checkMatchingAsset = (value: string) => { const url = new URL(value) @@ -27,15 +27,17 @@ const checkMinVersion: CustomValidator = (value) => { } } +const imageUrlSchema = Joi.string() + // For now only allow assets within this repo + .pattern( + /^https:\/\/raw.githubusercontent.com\/valora-inc\/address-metadata\/main\/assets\/tokens\/[^/]+\.png$/, + ) + .uri() + .custom(checkMatchingAsset, 'has a matching asset') + const BaseTokenInfoSchema = Joi.object({ address: AddressSchema, - imageUrl: Joi.string() - // For now only allow assets within this repo - .pattern( - /^https:\/\/raw.githubusercontent.com\/valora-inc\/address-metadata\/main\/assets\/tokens\/[^/]+\.png$/, - ) - .uri() - .custom(checkMatchingAsset, 'has a matching asset'), + imageUrl: imageUrlSchema, name: Joi.string().required(), decimals: Joi.number().required(), symbol: Joi.string().required(), @@ -52,12 +54,23 @@ const BaseTokenInfoSchema = Joi.object({ .pattern(/^\d+\.\d+\.\d+$/) .custom(checkMinVersion, 'has a valid version'), isNative: Joi.boolean(), + infoUrl: Joi.string() + .uri() + .pattern(/^https:\/\/www.coingecko.com\/en\/coins/), + isZeroState: Joi.boolean(), + hidePriceDelta: Joi.boolean(), }) const ProcessedTokenInfoSchema = BaseTokenInfoSchema.concat( Joi.object({ networkId: Joi.valid(...Object.values(NetworkId)).required(), tokenId: Joi.string().required(), + networkName: Joi.valid(...Object.values(NetworkName)).required(), + networkIconUrl: Joi.alternatives().conditional('isNative', { + is: true, + then: Joi.forbidden(), + otherwise: imageUrlSchema.required(), + }), }), ) diff --git a/src/tokens-info.ts b/src/tokens-info.ts index 3847fa5d..118dae46 100644 --- a/src/tokens-info.ts +++ b/src/tokens-info.ts @@ -1,4 +1,4 @@ -import { NetworkId, TokenInfo, TokenInfoJSON } from './types' +import { NetworkId, NetworkName, TokenInfo, TokenInfoJSON } from './types' import CeloMainnetTokensInfo from './data/mainnet/celo-tokens-info.json' import CeloAlfajoresTokensInfo from './data/testnet/celo-alfajores-tokens-info.json' import EthereumMainnetTokensInfo from './data/mainnet/ethereum-tokens-info.json' @@ -11,6 +11,13 @@ const networkIdToTokensInfo: Record = { [NetworkId['ethereum-sepolia']]: EthereumSepoliaTokensInfo, } +const networkIdToNetworkName: Record = { + [NetworkId['celo-mainnet']]: NetworkName.Celo, + [NetworkId['celo-alfajores']]: NetworkName.Celo, + [NetworkId['ethereum-mainnet']]: NetworkName.Ethereum, + [NetworkId['ethereum-sepolia']]: NetworkName.Ethereum, +} + export function getTokenId( { isNative, address }: Partial, networkId: NetworkId, @@ -23,12 +30,17 @@ export function getTokensInfoByNetworkIds(networkIds: NetworkId[]): { } { const output: { [tokenId: string]: TokenInfo } = {} for (const networkId of networkIds) { + const nativeImageUrl = networkIdToTokensInfo[networkId].find( + (tokenInfo) => tokenInfo.isNative, + )?.imageUrl for (const tokenInfo of networkIdToTokensInfo[networkId]) { const tokenId = getTokenId(tokenInfo, networkId) output[tokenId] = { ...tokenInfo, networkId, tokenId, + networkName: networkIdToNetworkName[networkId], + networkIconUrl: tokenInfo.isNative ? undefined : nativeImageUrl, } } } diff --git a/src/types.ts b/src/types.ts index 9d0def56..addad56f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -41,12 +41,17 @@ export interface TokenInfoJSON { pegTo?: string isSupercharged?: boolean bridge?: string + hidePriceDelta?: boolean + isZeroState?: boolean + infoUrl?: string } // The token info type after a small amount of processing which is used in the cloud function export interface TokenInfo extends TokenInfoJSON { networkId: NetworkId tokenId: string + networkName: NetworkName + networkIconUrl?: string } export enum NetworkId { @@ -61,3 +66,8 @@ export type Environment = 'mainnet' | 'testnet' export type ValoraGcloudProject = | 'celo-mobile-alfajores' | 'celo-mobile-mainnet' + +export enum NetworkName { + Celo = 'Celo', + Ethereum = 'Ethereum', +} From 06a380db44bc40a53dc882d5d62ede0c63ce3e43 Mon Sep 17 00:00:00 2001 From: Satish Ravi Date: Fri, 29 Sep 2023 15:31:05 -0700 Subject: [PATCH 2/5] feedback --- README.md | 19 ++++++++++++------- src/data/mainnet/celo-tokens-info.json | 13 ++++++++++--- src/data/mainnet/ethereum-tokens-info.json | 2 +- .../testnet/celo-alfajores-tokens-info.json | 13 ++++++++++--- .../testnet/ethereum-sepolia-tokens-info.json | 2 +- src/index.test.ts | 4 +--- src/schemas.test.ts | 4 +--- src/schemas/tokens-info.ts | 7 ++++--- src/tokens-info.ts | 10 +--------- src/types.ts | 8 +------- 10 files changed, 42 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 8e320a86..2c1822a5 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,18 @@ To add a new ERC20 token you need to follow these steps: ### ERC20 token info -| Property | Description | -| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `address` | The lower-case address of the ERC20 token contract. | -| `decimals` | The number of decimals used by the ERC20 token. | -| `imageUrl` | The logo to display for the ERC20 token. It must be a 256 x 256 PNG. Add the image to the [assets/tokens](assets/tokens) folder and use the following format: `https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/{image}.png` | -| `name` | The name to display for the ERC20 token. | -| `symbol` | The short symbol to display for the ERC20 token. | +| Property | Description | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `address` | The lower-case address of the ERC20 token contract. | +| `decimals` | The number of decimals used by the ERC20 token. | +| `imageUrl` | The logo to display for the ERC20 token. It must be a 256 x 256 PNG. Add the image to the [assets/tokens](assets/tokens) folder and use the following format: `https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/{image}.png` | +| `name` | The name to display for the ERC20 token. | +| `symbol` | The short symbol to display for the ERC20 token. | +| `isStableCoin` | Whether the token is a stable coin and the price is not expected to change | +| `isZeroState` | Whether the token is displayed even if the balance is zero | +| `isCashInEligible` | Whether the token is eligible for cash-ins | +| `isCashOutEligible` | Whether the token is eligible for cash-outs | +| `infoUrl` | The coingecko url for the token | ## Generic Use diff --git a/src/data/mainnet/celo-tokens-info.json b/src/data/mainnet/celo-tokens-info.json index 1f9c0f72..fd10cf05 100644 --- a/src/data/mainnet/celo-tokens-info.json +++ b/src/data/mainnet/celo-tokens-info.json @@ -197,6 +197,8 @@ "isSwappable": true, "isNative": true, "isZeroState": true, + "isCashInEligible": true, + "isCashOutEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo" }, { @@ -269,8 +271,10 @@ "symbol": "cUSD", "isSupercharged": true, "isSwappable": true, + "isStableCoin": true, "isZeroState": true, - "hidePriceDelta": true, + "isCashInEligible": true, + "isCashOutEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo-dollar" }, { @@ -400,7 +404,9 @@ "symbol": "cEUR", "isSupercharged": true, "isSwappable": true, - "hidePriceDelta": true, + "isStableCoin": true, + "isCashInEligible": true, + "isCashOutEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo-euro" }, { @@ -445,7 +451,8 @@ "symbol": "cREAL", "isSupercharged": true, "isSwappable": true, - "hidePriceDelta": true, + "isStableCoin": true, + "isCashInEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo-real-creal" }, { diff --git a/src/data/mainnet/ethereum-tokens-info.json b/src/data/mainnet/ethereum-tokens-info.json index 7975140e..2b6ca075 100644 --- a/src/data/mainnet/ethereum-tokens-info.json +++ b/src/data/mainnet/ethereum-tokens-info.json @@ -14,7 +14,7 @@ "decimals": 6, "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/USDC.png", - "hidePriceDelta": true, + "isStableCoin": true, "infoUrl": "https://www.coingecko.com/en/coins/usdc" } ] diff --git a/src/data/testnet/celo-alfajores-tokens-info.json b/src/data/testnet/celo-alfajores-tokens-info.json index 415ddfe6..b19b4dae 100644 --- a/src/data/testnet/celo-alfajores-tokens-info.json +++ b/src/data/testnet/celo-alfajores-tokens-info.json @@ -22,7 +22,9 @@ "name": "Celo Euro", "symbol": "cEUR", "isSupercharged": true, - "hidePriceDelta": true, + "isStableCoin": true, + "isCashInEligible": true, + "isCashOutEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo-euro" }, { @@ -116,7 +118,9 @@ "symbol": "cUSD", "isSupercharged": true, "isZeroState": true, - "hidePriceDelta": true, + "isStableCoin": true, + "isCashInEligible": true, + "isCashOutEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo-dollar" }, { @@ -181,7 +185,8 @@ "name": "Celo Real", "symbol": "cREAL", "isSupercharged": true, - "hidePriceDelta": true, + "isStableCoin": true, + "isCashInEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo-real-creal" }, { @@ -193,6 +198,8 @@ "symbol": "CELO", "isNative": true, "isZeroState": true, + "isCashInEligible": true, + "isCashOutEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo" }, { diff --git a/src/data/testnet/ethereum-sepolia-tokens-info.json b/src/data/testnet/ethereum-sepolia-tokens-info.json index ad1ad86c..d60182bb 100644 --- a/src/data/testnet/ethereum-sepolia-tokens-info.json +++ b/src/data/testnet/ethereum-sepolia-tokens-info.json @@ -14,7 +14,7 @@ "decimals": 6, "address": "0x8267cf9254734c6eb452a7bb9aaf97b392258b21", "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/USDC.png", - "hidePriceDelta": true, + "isStableCoin": true, "infoUrl": "https://www.coingecko.com/en/coins/usdc" } ] diff --git a/src/index.test.ts b/src/index.test.ts index 8af605dd..ac63ba88 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,6 +1,6 @@ import { _getTokensInfoHttpFunction } from './index' import { loadCloudFunctionConfig } from './config' -import { NetworkId, NetworkName } from './types' +import { NetworkId } from './types' import { getTokensInfoByNetworkIds } from './tokens-info' import mocked = jest.mocked @@ -25,7 +25,6 @@ describe('index', () => { imageUrl: 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png', tokenId: 'ethereum-mainnet:native', - networkName: NetworkName.Ethereum, }, 'celo-mainnet:native': { address: '0x471ece3750da237f93b8e339c536989b8978a438', @@ -38,7 +37,6 @@ describe('index', () => { isNative: true, networkId: NetworkId['celo-mainnet'], tokenId: 'celo-mainnet:native', - networkName: NetworkName.Celo, }, } mocked(getTokensInfoByNetworkIds).mockReturnValue(mockTokensInfo) diff --git a/src/schemas.test.ts b/src/schemas.test.ts index bb232fe1..ce318efe 100644 --- a/src/schemas.test.ts +++ b/src/schemas.test.ts @@ -1,6 +1,6 @@ import { getCeloRTDBMetadata } from './index' import { getTokensInfoByNetworkIds } from './tokens-info' -import { NetworkId, NetworkName, TokenInfo } from './types' +import { NetworkId, TokenInfo } from './types' import { TokenInfoSchemaProcessed, RTDBAddressToTokenInfoSchema, @@ -63,7 +63,6 @@ describe('Schema validation', () => { decimals: 18, isNative: true, networkId: NetworkId['celo-alfajores'], - networkName: NetworkName.Celo, tokenId: 'some-token', networkIconUrl: 'https://some-icon', }, @@ -78,7 +77,6 @@ describe('Schema validation', () => { symbol: 'XYZ', decimals: 18, networkId: NetworkId['celo-alfajores'], - networkName: NetworkName.Celo, tokenId: 'some-token', address: '0x471ece3750da237f93b8e339c536989b8978a438', }, diff --git a/src/schemas/tokens-info.ts b/src/schemas/tokens-info.ts index 12a130fb..8bc076f7 100644 --- a/src/schemas/tokens-info.ts +++ b/src/schemas/tokens-info.ts @@ -4,7 +4,7 @@ import { URL } from 'url' import path from 'path' import AddressSchema from './address-schema' import semver from 'semver' -import { NetworkId, NetworkName } from '../types' +import { NetworkId } from '../types' export const checkMatchingAsset = (value: string) => { const url = new URL(value) @@ -58,14 +58,15 @@ const BaseTokenInfoSchema = Joi.object({ .uri() .pattern(/^https:\/\/www.coingecko.com\/en\/coins/), isZeroState: Joi.boolean(), - hidePriceDelta: Joi.boolean(), + isStableCoin: Joi.boolean(), + isCashInEligible: Joi.boolean(), + isCashOutEligible: Joi.boolean(), }) const ProcessedTokenInfoSchema = BaseTokenInfoSchema.concat( Joi.object({ networkId: Joi.valid(...Object.values(NetworkId)).required(), tokenId: Joi.string().required(), - networkName: Joi.valid(...Object.values(NetworkName)).required(), networkIconUrl: Joi.alternatives().conditional('isNative', { is: true, then: Joi.forbidden(), diff --git a/src/tokens-info.ts b/src/tokens-info.ts index 118dae46..0a44c696 100644 --- a/src/tokens-info.ts +++ b/src/tokens-info.ts @@ -1,4 +1,4 @@ -import { NetworkId, NetworkName, TokenInfo, TokenInfoJSON } from './types' +import { NetworkId, TokenInfo, TokenInfoJSON } from './types' import CeloMainnetTokensInfo from './data/mainnet/celo-tokens-info.json' import CeloAlfajoresTokensInfo from './data/testnet/celo-alfajores-tokens-info.json' import EthereumMainnetTokensInfo from './data/mainnet/ethereum-tokens-info.json' @@ -11,13 +11,6 @@ const networkIdToTokensInfo: Record = { [NetworkId['ethereum-sepolia']]: EthereumSepoliaTokensInfo, } -const networkIdToNetworkName: Record = { - [NetworkId['celo-mainnet']]: NetworkName.Celo, - [NetworkId['celo-alfajores']]: NetworkName.Celo, - [NetworkId['ethereum-mainnet']]: NetworkName.Ethereum, - [NetworkId['ethereum-sepolia']]: NetworkName.Ethereum, -} - export function getTokenId( { isNative, address }: Partial, networkId: NetworkId, @@ -39,7 +32,6 @@ export function getTokensInfoByNetworkIds(networkIds: NetworkId[]): { ...tokenInfo, networkId, tokenId, - networkName: networkIdToNetworkName[networkId], networkIconUrl: tokenInfo.isNative ? undefined : nativeImageUrl, } } diff --git a/src/types.ts b/src/types.ts index addad56f..e12822be 100644 --- a/src/types.ts +++ b/src/types.ts @@ -41,7 +41,7 @@ export interface TokenInfoJSON { pegTo?: string isSupercharged?: boolean bridge?: string - hidePriceDelta?: boolean + isStableCoin?: boolean isZeroState?: boolean infoUrl?: string } @@ -50,7 +50,6 @@ export interface TokenInfoJSON { export interface TokenInfo extends TokenInfoJSON { networkId: NetworkId tokenId: string - networkName: NetworkName networkIconUrl?: string } @@ -66,8 +65,3 @@ export type Environment = 'mainnet' | 'testnet' export type ValoraGcloudProject = | 'celo-mobile-alfajores' | 'celo-mobile-mainnet' - -export enum NetworkName { - Celo = 'Celo', - Ethereum = 'Ethereum', -} From 16290d5c20a8f25c71b47ab6534ddbe8fc71111f Mon Sep 17 00:00:00 2001 From: Satish Ravi Date: Fri, 29 Sep 2023 16:26:30 -0700 Subject: [PATCH 3/5] add cico fields to types --- src/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types.ts b/src/types.ts index e12822be..a8e7e70c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -43,6 +43,8 @@ export interface TokenInfoJSON { bridge?: string isStableCoin?: boolean isZeroState?: boolean + isCashInEligible?: boolean + isCashOutEligible?: boolean infoUrl?: string } From 86bbac3be4ec3cc30ea4d95d1ecb425a53d9b82b Mon Sep 17 00:00:00 2001 From: Satish Ravi Date: Mon, 2 Oct 2023 10:26:37 -0700 Subject: [PATCH 4/5] feedback --- README.md | 19 +++++++------------ src/data/mainnet/celo-tokens-info.json | 4 ++-- src/data/mainnet/ethereum-tokens-info.json | 2 +- .../testnet/celo-alfajores-tokens-info.json | 4 ++-- .../testnet/ethereum-sepolia-tokens-info.json | 2 +- src/schemas/tokens-info.ts | 2 +- src/types.ts | 10 +++++----- 7 files changed, 19 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 2c1822a5..8e320a86 100644 --- a/README.md +++ b/README.md @@ -18,18 +18,13 @@ To add a new ERC20 token you need to follow these steps: ### ERC20 token info -| Property | Description | -| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `address` | The lower-case address of the ERC20 token contract. | -| `decimals` | The number of decimals used by the ERC20 token. | -| `imageUrl` | The logo to display for the ERC20 token. It must be a 256 x 256 PNG. Add the image to the [assets/tokens](assets/tokens) folder and use the following format: `https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/{image}.png` | -| `name` | The name to display for the ERC20 token. | -| `symbol` | The short symbol to display for the ERC20 token. | -| `isStableCoin` | Whether the token is a stable coin and the price is not expected to change | -| `isZeroState` | Whether the token is displayed even if the balance is zero | -| `isCashInEligible` | Whether the token is eligible for cash-ins | -| `isCashOutEligible` | Whether the token is eligible for cash-outs | -| `infoUrl` | The coingecko url for the token | +| Property | Description | +| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `address` | The lower-case address of the ERC20 token contract. | +| `decimals` | The number of decimals used by the ERC20 token. | +| `imageUrl` | The logo to display for the ERC20 token. It must be a 256 x 256 PNG. Add the image to the [assets/tokens](assets/tokens) folder and use the following format: `https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/{image}.png` | +| `name` | The name to display for the ERC20 token. | +| `symbol` | The short symbol to display for the ERC20 token. | ## Generic Use diff --git a/src/data/mainnet/celo-tokens-info.json b/src/data/mainnet/celo-tokens-info.json index fd10cf05..05a570ca 100644 --- a/src/data/mainnet/celo-tokens-info.json +++ b/src/data/mainnet/celo-tokens-info.json @@ -196,7 +196,7 @@ "symbol": "CELO", "isSwappable": true, "isNative": true, - "isZeroState": true, + "showZeroBalance": true, "isCashInEligible": true, "isCashOutEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo" @@ -272,7 +272,7 @@ "isSupercharged": true, "isSwappable": true, "isStableCoin": true, - "isZeroState": true, + "showZeroBalance": true, "isCashInEligible": true, "isCashOutEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo-dollar" diff --git a/src/data/mainnet/ethereum-tokens-info.json b/src/data/mainnet/ethereum-tokens-info.json index 2b6ca075..008aed30 100644 --- a/src/data/mainnet/ethereum-tokens-info.json +++ b/src/data/mainnet/ethereum-tokens-info.json @@ -5,7 +5,7 @@ "decimals": 18, "isNative": true, "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png", - "isZeroState": true, + "showZeroBalance": true, "infoUrl": "https://www.coingecko.com/en/coins/ethereum" }, { diff --git a/src/data/testnet/celo-alfajores-tokens-info.json b/src/data/testnet/celo-alfajores-tokens-info.json index b19b4dae..d23d3d84 100644 --- a/src/data/testnet/celo-alfajores-tokens-info.json +++ b/src/data/testnet/celo-alfajores-tokens-info.json @@ -117,7 +117,7 @@ "name": "Celo Dollar", "symbol": "cUSD", "isSupercharged": true, - "isZeroState": true, + "showZeroBalance": true, "isStableCoin": true, "isCashInEligible": true, "isCashOutEligible": true, @@ -197,7 +197,7 @@ "name": "Celo", "symbol": "CELO", "isNative": true, - "isZeroState": true, + "showZeroBalance": true, "isCashInEligible": true, "isCashOutEligible": true, "infoUrl": "https://www.coingecko.com/en/coins/celo" diff --git a/src/data/testnet/ethereum-sepolia-tokens-info.json b/src/data/testnet/ethereum-sepolia-tokens-info.json index d60182bb..a52fb517 100644 --- a/src/data/testnet/ethereum-sepolia-tokens-info.json +++ b/src/data/testnet/ethereum-sepolia-tokens-info.json @@ -5,7 +5,7 @@ "decimals": 18, "isNative": true, "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png", - "isZeroState": true, + "showZeroBalance": true, "infoUrl": "https://www.coingecko.com/en/coins/ethereum" }, { diff --git a/src/schemas/tokens-info.ts b/src/schemas/tokens-info.ts index 8bc076f7..1db43151 100644 --- a/src/schemas/tokens-info.ts +++ b/src/schemas/tokens-info.ts @@ -57,7 +57,7 @@ const BaseTokenInfoSchema = Joi.object({ infoUrl: Joi.string() .uri() .pattern(/^https:\/\/www.coingecko.com\/en\/coins/), - isZeroState: Joi.boolean(), + showZeroBalance: Joi.boolean(), isStableCoin: Joi.boolean(), isCashInEligible: Joi.boolean(), isCashOutEligible: Joi.boolean(), diff --git a/src/types.ts b/src/types.ts index a8e7e70c..5bf4bf10 100644 --- a/src/types.ts +++ b/src/types.ts @@ -41,11 +41,11 @@ export interface TokenInfoJSON { pegTo?: string isSupercharged?: boolean bridge?: string - isStableCoin?: boolean - isZeroState?: boolean - isCashInEligible?: boolean - isCashOutEligible?: boolean - infoUrl?: string + isStableCoin?: boolean // Whether the token is a stable coin and the price is not expected to change + showZeroBalance?: boolean // Whether the token is displayed even if the balance is zero + isCashInEligible?: boolean // Whether the token can be cashed in + isCashOutEligible?: boolean // Whether the token can be cashed in + infoUrl?: string // The coingecko url for the token } // The token info type after a small amount of processing which is used in the cloud function From ea47d90439140de53f0719fbb1cb365a75714807 Mon Sep 17 00:00:00 2001 From: Satish Ravi Date: Mon, 2 Oct 2023 10:28:24 -0700 Subject: [PATCH 5/5] update docs --- src/types.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/types.ts b/src/types.ts index 5bf4bf10..6fb17c57 100644 --- a/src/types.ts +++ b/src/types.ts @@ -41,11 +41,11 @@ export interface TokenInfoJSON { pegTo?: string isSupercharged?: boolean bridge?: string - isStableCoin?: boolean // Whether the token is a stable coin and the price is not expected to change - showZeroBalance?: boolean // Whether the token is displayed even if the balance is zero - isCashInEligible?: boolean // Whether the token can be cashed in - isCashOutEligible?: boolean // Whether the token can be cashed in - infoUrl?: string // The coingecko url for the token + isStableCoin?: boolean // used to show / hide price delta on token details + showZeroBalance?: boolean + isCashInEligible?: boolean + isCashOutEligible?: boolean + infoUrl?: string // The coingecko url } // The token info type after a small amount of processing which is used in the cloud function