From 8d9a18fd6634f589892f5cd0f2cc02b72683f623 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 17:40:12 +0200 Subject: [PATCH 01/24] chore(ui): Add tmp dir to .gitignore --- apps/ui/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/ui/.gitignore b/apps/ui/.gitignore index 567609b12..34761e9cf 100644 --- a/apps/ui/.gitignore +++ b/apps/ui/.gitignore @@ -1 +1,2 @@ build/ +tmp/ From 9bd7ba9d541345549adcbfc84510954cec21b9d7 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 17:41:00 +0200 Subject: [PATCH 02/24] chore(ui): Add ts-node and csv-parse dev dependencies --- apps/ui/package.json | 2 ++ yarn.lock | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/apps/ui/package.json b/apps/ui/package.json index a87d9fba5..4a848ea2d 100644 --- a/apps/ui/package.json +++ b/apps/ui/package.json @@ -113,6 +113,7 @@ "@types/react-dom": "^17.0.0", "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^5.38.1", + "csv-parse": "^5.3.1", "eslint": "^8.18.0", "eslint-config-prettier": "^8.5.0", "eslint-config-react-app": "^7.0.1", @@ -129,6 +130,7 @@ "jsonc-eslint-parser": "^2.1.0", "prettier": "^2.7.1", "storybook-preset-craco": "^0.0.6", + "ts-node": "^10.9.1", "typescript": "~4.8.4", "webpack": "4.44.2" } diff --git a/yarn.lock b/yarn.lock index 7f1ecd27d..851b20be7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7991,6 +7991,7 @@ __metadata: "@typescript-eslint/parser": ^5.38.1 bn.js: ^5.2.1 classnames: ^2.3.1 + csv-parse: ^5.3.1 decimal.js: ^10.3.1 dexie: ^3.2.2 escape-string-regexp: ^5.0.0 @@ -8025,6 +8026,7 @@ __metadata: react-router-dom: ^6.3.0 react-scripts: 4.0.3 storybook-preset-craco: ^0.0.6 + ts-node: ^10.9.1 typescript: ~4.8.4 use-deep-compare: ^1.1.0 wasm-loader: ^1.3.0 @@ -14515,6 +14517,13 @@ __metadata: languageName: node linkType: hard +"csv-parse@npm:^5.3.1": + version: 5.3.1 + resolution: "csv-parse@npm:5.3.1" + checksum: 18acfe5295d13632ab4bcebf285b9cb4e1450d8843946882b42f313d8ae3b606e508594d29bb17a1ca4864ff7da7d1b8ad060caa0495266c433bace1c663b745 + languageName: node + linkType: hard + "csv-stringify@npm:^6.2.0": version: 6.2.0 resolution: "csv-stringify@npm:6.2.0" From 1cfb445bb39532c2ef0cfac2355db3193c1fcca4 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 17:42:01 +0200 Subject: [PATCH 03/24] feat(ui): Add Wormhole token data scraper --- apps/ui/scripts/processWormholeTokenData.ts | 182 ++++++++++++++++++++ apps/ui/scripts/scrapeWormholeTokenData.sh | 12 ++ apps/ui/tsconfig.json | 7 +- 3 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 apps/ui/scripts/processWormholeTokenData.ts create mode 100755 apps/ui/scripts/scrapeWormholeTokenData.sh diff --git a/apps/ui/scripts/processWormholeTokenData.ts b/apps/ui/scripts/processWormholeTokenData.ts new file mode 100644 index 000000000..132d86f27 --- /dev/null +++ b/apps/ui/scripts/processWormholeTokenData.ts @@ -0,0 +1,182 @@ +import { CHAINS, ChainId } from "@certusone/wormhole-sdk"; +import fs from "fs"; +import { parse } from "csv-parse"; + +type Source = + | "sol" + | "eth" + | "bsc" + | "terra" + | "matic" + | "avax" + | "oasis" + | "algorand" + | "ftm" + | "aurora" + | "karura" + | "acala" + | "klaytn" + | "celo" + | "near" + | "moonbeam" + | "terra2"; + +interface WrappedDetails { + readonly solAddress: string; + readonly solDecimals: string; + readonly ethAddress: string; + readonly ethDecimals: string; + readonly bscAddress: string; + readonly bscDecimals: string; + readonly terraAddress: string; + readonly terraDecimals: string; + readonly maticAddress: string; + readonly maticDecimals: string; + readonly avaxAddress: string; + readonly avaxDecimals: string; + readonly oasisAddress: string; + readonly oasisDecimals: string; + readonly algorandAddress: string; + readonly algorandDecimals: string; + readonly ftmAddress: string; + readonly ftmDecimals: string; + readonly auroraAddress: string; + readonly auroraDecimals: string; + readonly karuraAddress: string; + readonly karuraDecimals: string; + readonly acalaAddress: string; + readonly acalaDecimals: string; + readonly klaytnAddress: string; + readonly klaytnDecimals: string; + readonly celoAddress: string; + readonly celoDecimals: string; + readonly nearAddress: string; + readonly nearDecimals: string; + readonly moonbeamAddress: string; + readonly moonbeamDecimals: string; + readonly terra2Address: string; + readonly terra2Decimals: string; +} + +interface CsvRecord extends WrappedDetails { + readonly source: Source; + readonly symbol: string; + readonly name: string; + readonly sourceAddress: string; + readonly sourceDecimals: string; + readonly coingeckoId: string; + readonly logo: string; +} + +interface WormholeTokenDetails { + readonly chainId: ChainId; + readonly address: string; + readonly decimals: number; +} + +interface WormholeToken { + readonly symbol: string; + readonly displayName: string; + readonly logo: string; + readonly coinGeckoId: string; + readonly nativeDetails: WormholeTokenDetails; + readonly wrappedDetails: readonly WormholeTokenDetails[]; +} + +const sourceToChainId: Record = { + sol: CHAINS.solana, + eth: CHAINS.ethereum, + bsc: CHAINS.bsc, + terra: CHAINS.terra, + matic: CHAINS.polygon, + avax: CHAINS.avalanche, + oasis: CHAINS.oasis, + algorand: CHAINS.algorand, + ftm: CHAINS.fantom, + aurora: CHAINS.aurora, + karura: CHAINS.karura, + acala: CHAINS.acala, + klaytn: CHAINS.klaytn, + celo: CHAINS.celo, + near: CHAINS.near, + moonbeam: CHAINS.moonbeam, + terra2: CHAINS.terra2, +}; + +const processWrappedDetails = ( + wrappedDetails: WrappedDetails, +): readonly WormholeTokenDetails[] => + Object.entries(sourceToChainId).reduce( + (accumulator: readonly WormholeTokenDetails[], [source, chainId]) => { + const address: string = + wrappedDetails[`${source}Address` as keyof WrappedDetails]; + const decimals: string = + wrappedDetails[`${source}Decimals` as keyof WrappedDetails]; + if (!address || !decimals) { + return accumulator; + } + return [ + ...accumulator, + { + chainId, + address, + decimals: parseInt(decimals, 10), + }, + ]; + }, + [], + ); + +const processRecord = ({ + source, + symbol, + name, + logo, + coingeckoId, + sourceAddress, + sourceDecimals, + ...wrappedDetails +}: CsvRecord): WormholeToken => ({ + symbol, + displayName: name, + logo, + coinGeckoId: coingeckoId, + nativeDetails: { + chainId: sourceToChainId[source], + address: sourceAddress, + decimals: parseInt(sourceDecimals, 10), + }, + wrappedDetails: processWrappedDetails(wrappedDetails), +}); + +const main = async () => { + const processedRecords: WormholeToken[] = []; + const parser = fs + .createReadStream(`${__dirname}/../tmp/wormholeTokenData.csv`) + .pipe( + parse({ + bom: true, + columns: true, + }), + ); + + for await (const record of parser) { + const processedRecord = processRecord(record); + if (Object.keys(processedRecord.wrappedDetails).length > 0) { + processedRecords.push(processedRecord); + } + } + + return new Promise((resolve) => { + fs.writeFile( + `${__dirname}/../src/config/wormholeTokens.json`, + JSON.stringify(processedRecords), + resolve, + ); + }); +}; + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/apps/ui/scripts/scrapeWormholeTokenData.sh b/apps/ui/scripts/scrapeWormholeTokenData.sh new file mode 100755 index 000000000..663247a0c --- /dev/null +++ b/apps/ui/scripts/scrapeWormholeTokenData.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -o errexit -o nounset -o pipefail +command -v shellcheck >/dev/null && shellcheck "$0" + +TMP_FILE="./tmp/wormholeTokenData.csv" + +mkdir -p tmp +wget -O "$TMP_FILE" "https://raw.githubusercontent.com/certusone/wormhole-token-list/main/content/by_source.csv" + +yarn ts-node --esm ./scripts/processWormholeTokenData.ts + +rm "$TMP_FILE" diff --git a/apps/ui/tsconfig.json b/apps/ui/tsconfig.json index 155e517d6..4fccb0f50 100644 --- a/apps/ui/tsconfig.json +++ b/apps/ui/tsconfig.json @@ -8,5 +8,10 @@ "noEmit": true, "typeRoots": ["./node_modules/@types", "./src/types"] }, - "include": ["src/"] + "include": ["src/"], + "ts-node": { + "compilerOptions": { + "module": "commonjs" + } + } } From e04cce9858107e8b099e5735804a8e5f2d364bf3 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 17:56:53 +0200 Subject: [PATCH 04/24] feat(ui): Add scraped Wormhole token data --- apps/ui/src/config/index.ts | 1 + apps/ui/src/config/wormholeTokens.json | 1 + 2 files changed, 2 insertions(+) create mode 100644 apps/ui/src/config/wormholeTokens.json diff --git a/apps/ui/src/config/index.ts b/apps/ui/src/config/index.ts index 14ddfff90..21eec3032 100644 --- a/apps/ui/src/config/index.ts +++ b/apps/ui/src/config/index.ts @@ -18,6 +18,7 @@ export * from "./pools"; export * from "./tokens"; export * from "./utils"; export * from "./wormhole"; +export { default as wormholeTokens } from "./wormholeTokens.json"; export interface Config { readonly ecosystems: ReadonlyRecord; diff --git a/apps/ui/src/config/wormholeTokens.json b/apps/ui/src/config/wormholeTokens.json new file mode 100644 index 000000000..520368be5 --- /dev/null +++ b/apps/ui/src/config/wormholeTokens.json @@ -0,0 +1 @@ +[{"symbol":"RAY","displayName":"Raydium (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R/logo.png","coinGeckoId":"raydium","nativeDetails":{"chainId":1,"address":"4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0xE617dd80c621a5072bD8cBa65E9d76c07327004d","decimals":6},{"chainId":4,"address":"0x13b6A55662f6591f8B8408Af1C73B017E32eEdB8","decimals":6},{"chainId":3,"address":"terra1ht5sepn28z999jx33sdduuxm9acthad507jg9q","decimals":6}]},{"symbol":"SBR","displayName":"Saber (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1/logo.svg","coinGeckoId":"saber","nativeDetails":{"chainId":1,"address":"Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1","decimals":6},"wrappedDetails":[{"chainId":4,"address":"0x75344E5693ed5ecAdF4f292fFeb866c2cF8afCF1","decimals":6},{"chainId":3,"address":"terra17h82zsq6q8x5tsgm5ugcx4gytw3axguvzt4pkc","decimals":6}]},{"symbol":"SOL","displayName":"SOL (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png","coinGeckoId":"solana","nativeDetails":{"chainId":1,"address":"So11111111111111111111111111111111111111112","decimals":9},"wrappedDetails":[{"chainId":2,"address":"0xD31a59c85aE9D8edEFeC411D448f90841571b89c","decimals":9},{"chainId":4,"address":"0xfA54fF1a158B5189Ebba6ae130CEd6bbd3aEA76e","decimals":9},{"chainId":3,"address":"terra190tqwgqx7s8qrknz6kckct7v607cu068gfujpk","decimals":8},{"chainId":5,"address":"0xd93f7e271cb87c23aaa73edc008a79646d1f9912","decimals":9},{"chainId":6,"address":"0xFE6B19286885a4F7F55AdAD09C3Cd1f906D2478F","decimals":9},{"chainId":7,"address":"0xd17dDAC91670274F7ba1590a06EcA0f2FD2b12bc","decimals":9},{"chainId":10,"address":"0xd99021C2A33e4Cf243010539c9e9b7c52E0236c1","decimals":9}]},{"symbol":"SRMso","displayName":"Serum (Portal from Solana)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png","coinGeckoId":"serum","nativeDetails":{"chainId":1,"address":"SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0xE3ADAA4fb7c92AB833Ee08B3561D9c434aA2A3eE","decimals":6},{"chainId":4,"address":"0x12BeffdCEcb547640DC30e1495E4B9cdc21922b4","decimals":6},{"chainId":3,"address":"terra1dkam9wd5yvaswv4yq3n2aqd4wm5j8n82qc0c7c","decimals":6}]},{"symbol":"USDCso","displayName":"USD Coin (Portal from Solana)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":1,"address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0x41f7B8b9b897276b7AAE926a9016935280b44E97","decimals":6},{"chainId":4,"address":"0x91Ca579B0D47E5cfD5D0862c21D5659d39C8eCf0","decimals":6},{"chainId":3,"address":"terra1e6mq63y64zcxz8xyu5van4tgkhemj3r86yvgu4","decimals":6},{"chainId":5,"address":"0x576cf361711cd940cd9c397bb98c4c896cbd38de","decimals":6},{"chainId":6,"address":"0x0950Fc1AD509358dAeaD5eB8020a3c7d8b43b9DA","decimals":6},{"chainId":7,"address":"0x1d1149a53deB36F2836Ae7877c9176413aDfA4A8","decimals":6},{"chainId":10,"address":"0xb8398DA4FB3BC4306B9D9d9d13d9573e7d0E299f","decimals":6},{"chainId":9,"address":"0xDd1DaFedeBa5F9851C4F4a2876E0f3aF3c774B1A","decimals":6}]},{"symbol":"USDTso","displayName":"Tether USD (Portal from Solana)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg","coinGeckoId":"tether","nativeDetails":{"chainId":1,"address":"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0x1CDD2EaB61112697626F7b4bB0e23Da4FeBF7B7C","decimals":6},{"chainId":4,"address":"0x49d5cC521F75e13fa8eb4E89E9D381352C897c96","decimals":6},{"chainId":3,"address":"terra1hd9n65snaluvf7en0p4hqzse9eqecejz2k8rl5","decimals":6},{"chainId":5,"address":"0x3553f861dec0257bada9f8ed268bf0d74e45e89c","decimals":6},{"chainId":6,"address":"0xF0FF231e3F1A50F83136717f287ADAB862f89431","decimals":6},{"chainId":7,"address":"0x24285C5232ce3858F00bacb950Cae1f59d1b2704","decimals":6},{"chainId":9,"address":"0xd80890AFDBd7148456D8Ee358eF9127F0F8c7faf","decimals":6}]},{"symbol":"XTAG","displayName":"XTAG Token (Portal)","logo":"https://raw.githubusercontent.com/sudomon/wormhole-token-list/main/src/logogen/base/xtag.png","coinGeckoId":"xhashtag","nativeDetails":{"chainId":1,"address":"5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp","decimals":6},"wrappedDetails":[{"chainId":6,"address":"0xa608d79c5f695c0d4c0e773a4938b57e18e0fc57","decimals":6}]},{"symbol":"ZBC","displayName":"Zebec Protocol","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF/logo.png","coinGeckoId":"zebec-protocol","nativeDetails":{"chainId":1,"address":"zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF","decimals":9},"wrappedDetails":[{"chainId":4,"address":"0x6D1054C3102E842314e250b9e9C4Be327b8DaaE2","decimals":9}]},{"symbol":"mSOL","displayName":"Marinade staked SOL (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So/logo.png","coinGeckoId":"marinade-staked-sol","nativeDetails":{"chainId":1,"address":"mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So","decimals":9},"wrappedDetails":[{"chainId":2,"address":"0x756bFb452cFE36A5Bc82e4F5f4261A89a18c242b","decimals":9},{"chainId":3,"address":"terra1qvlpf2v0zmru3gtex40sqq02wxp39x3cjh359y","decimals":8},{"chainId":7,"address":"0x5E11A4f64D3B9fA042dB9e1AA918F735038FdfD8","decimals":9}]},{"symbol":"1INCH","displayName":"1INCH Token (Portal)","logo":"","coinGeckoId":"1inch","nativeDetails":{"chainId":2,"address":"0x111111111117dC0aa78b770fA6A738034120C302","decimals":18},"wrappedDetails":[{"chainId":1,"address":"AjkPkq3nsyDe1yKcbyZT7N4aK4Evv9om9tzhQD3wsRC","decimals":8}]},{"symbol":"1SOL","displayName":"1sol.io (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF/logo.png","coinGeckoId":"1sol","nativeDetails":{"chainId":2,"address":"0x009178997aff09a67d4caccfeb897fb79d036214","decimals":18},"wrappedDetails":[{"chainId":1,"address":"4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF","decimals":8}]},{"symbol":"AAVE","displayName":"Aave Token (Portal)","logo":"","coinGeckoId":"aave","nativeDetails":{"chainId":2,"address":"0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3vAs4D1WE6Na4tCgt4BApgFfENbm8WY7q4cSPD1yM4Cg","decimals":8}]},{"symbol":"AKRO","displayName":"Akropolis (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/G3h8NZgJozk9crme2me6sKDJuSQ12mNCtvC9NbSWqGuk/logo.png","coinGeckoId":"akropolis","nativeDetails":{"chainId":2,"address":"0x8ab7404063ec4dbcfd4598215992dc3f8ec853d7","decimals":18},"wrappedDetails":[{"chainId":1,"address":"12uHjozDVgyGWeLqQ8DMCRbig8amW5VmvZu3FdMMdcaG","decimals":8}]},{"symbol":"ALEPH","displayName":"Aleph.im (Portal)","logo":"","coinGeckoId":"aleph-im","nativeDetails":{"chainId":2,"address":"0x27702a26126e0b3702af63ee09ac4d1a084ef628","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3UCMiSnkcnkPE1pgQ5ggPCBv6dXgVUy16TmMUe1WpG9x","decimals":8}]},{"symbol":"ALICE","displayName":"My Neighbor Alice (Portal)","logo":"","coinGeckoId":"my-neighbor-alice","nativeDetails":{"chainId":2,"address":"0xac51066d7bec65dc4589368da368b212745d63e8","decimals":6},"wrappedDetails":[{"chainId":1,"address":"9ARQsBfAn65q522cEqSJuse3cLhA31jgWDBGQHeiq7Mg","decimals":8}]},{"symbol":"AMP","displayName":"Amp (Portal)","logo":"","coinGeckoId":"amp","nativeDetails":{"chainId":2,"address":"0xff20817765cb7f73d4bde2e66e067e58d11095c2","decimals":18},"wrappedDetails":[{"chainId":1,"address":"D559HwgjYGDYsXpmFUKxhFTEwutvS9sya1kXiyCVogCV","decimals":8}]},{"symbol":"AMPL","displayName":"Ampleforth (Portal)","logo":"","coinGeckoId":"ampleforth","nativeDetails":{"chainId":2,"address":"0xd46ba6d942050d489dbd938a2c909a5d5039a161","decimals":9},"wrappedDetails":[{"chainId":1,"address":"EHKQvJGu48ydKA4d3RivrkNyTJTkSdoS32UafxSX1yak","decimals":8}]},{"symbol":"ANKR","displayName":"Ankr (Portal)","logo":"","coinGeckoId":"ankr","nativeDetails":{"chainId":2,"address":"0x8290333cef9e6d528dd5618fb97a76f268f3edd4","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Gq2norJ1kBemBp3mPfkgAUMhMMmnFmY4zEyi26tRcxFB","decimals":8}]},{"symbol":"AUDIO","displayName":"Audius (Portal)","logo":"","coinGeckoId":"audius","nativeDetails":{"chainId":2,"address":"0x18aaa7115705e8be94bffebde57af9bfc265b998","decimals":18},"wrappedDetails":[{"chainId":1,"address":"9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM","decimals":8},{"chainId":3,"address":"terra1nc6flp57m5hsr6y5y8aexzszy43ksr0drdr8rp","decimals":8}]},{"symbol":"AXSet","displayName":"Axie Infinity Shard (Portal from Ethereum)","logo":"https://etherscan.io/token/images/axieinfinityshard_32.png","coinGeckoId":"axie-infinity","nativeDetails":{"chainId":2,"address":"0xbb0e17ef65f82ab018d8edd776e8dd940327b28b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HysWcbHiYY9888pHbaqhwLYZQeZrcQMXKQWRqS7zcPK5","decimals":8},{"chainId":4,"address":"0x556b60c53fbC1518Ad17E03d52E47368dD4d81B3","decimals":18}]},{"symbol":"BAT","displayName":"Basic Attention Token (Portal)","logo":"","coinGeckoId":"basic-attention-token","nativeDetails":{"chainId":2,"address":"0x0d8775f648430679a709e98d2b0cb6250d2887ef","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EPeUFDgHRxs9xxEPVaL6kfGQvCon7jmAWKVUHuux1Tpz","decimals":8},{"chainId":4,"address":"0x31C78f583ed0288D67b2b80Dc5C443Bc3b15C661","decimals":18},{"chainId":3,"address":"terra1apxgj5agkkfdm2tprwvykug0qtahxvfmugnhx2","decimals":8}]},{"symbol":"BNT","displayName":"Bancor Network Token (Portal)","logo":"","coinGeckoId":"bancor-network","nativeDetails":{"chainId":2,"address":"0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EDVVEYW4fPJ6vKw5LZXRGUSPzxoHrv6eWvTqhCr8oShs","decimals":8}]},{"symbol":"BUSDet","displayName":"Binance USD (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX/logo.png","coinGeckoId":"binance-usd","nativeDetails":{"chainId":2,"address":"0x4fabb145d64652a948d72533023f6e7a623c7c53","decimals":18},"wrappedDetails":[{"chainId":1,"address":"33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX","decimals":8},{"chainId":4,"address":"0x035de3679E692C471072d1A09bEb9298fBB2BD31","decimals":18}]},{"symbol":"CEL","displayName":"Celsius (Portal)","logo":"","coinGeckoId":"celsius-network","nativeDetails":{"chainId":2,"address":"0xaaaebe6fe48e54f431b0c390cfaf0b017d09d42d","decimals":4},"wrappedDetails":[{"chainId":1,"address":"nRtfwU9G82CSHhHGJNxFhtn7FLvWP2rqvQvje1WtL69","decimals":4}]},{"symbol":"CHZ","displayName":"Chiliz (Portal)","logo":"","coinGeckoId":"chiliz","nativeDetails":{"chainId":2,"address":"0x3506424f91fd33084466f402d5d97f05f8e3b4af","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5TtSKAamFq88grN1QGrEaZ1AjjyciqnCya1aiMhAgFvG","decimals":8}]},{"symbol":"COMP","displayName":"Compound (Portal)","logo":"","coinGeckoId":"compound","nativeDetails":{"chainId":2,"address":"0xc00e94cb662c3520282e6f5717214004a7f26888","decimals":18},"wrappedDetails":[{"chainId":1,"address":"AwEauVaTMQRB71WeDnwf1DWSBxaMKjEPuxyLr1uixFom","decimals":8}]},{"symbol":"CREAM","displayName":"Cream (Portal)","logo":"","coinGeckoId":"cream","nativeDetails":{"chainId":2,"address":"0x2ba592f78db6436527729929aaf6c908497cb200","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HihxL2iM6L6P1oqoSeiixdJ3PhPYNxvSKH9A2dDqLVDH","decimals":8}]},{"symbol":"CRO","displayName":"Crypto.com Coin (Portal)","logo":"","coinGeckoId":"crypto-com-coin","nativeDetails":{"chainId":2,"address":"0xa0b73e1ff0b80914ab6fe0444e65848c4c34450b","decimals":8},"wrappedDetails":[{"chainId":1,"address":"DvjMYMVeXgKxaixGKpzQThLoG98nc7HSU7eanzsdCboA","decimals":8}]},{"symbol":"CRV","displayName":"Curve DAO Token (Portal)","logo":"","coinGeckoId":"curve-dao-token","nativeDetails":{"chainId":2,"address":"0xd533a949740bb3306d119cc777fa900ba034cd52","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7gjNiPun3AzEazTZoFEjZgcBMeuaXdpjHq2raZTmTrfs","decimals":8}]},{"symbol":"CVX","displayName":"Convex Finance (Portal)","logo":"","coinGeckoId":"convex-finance","nativeDetails":{"chainId":2,"address":"0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"BLvmrccP4g1B6SpiVvmQrLUDya1nZ4B2D1nm9jzKF7sz","decimals":8}]},{"symbol":"DAI","displayName":"DAI (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png","coinGeckoId":"dai","nativeDetails":{"chainId":2,"address":"0x6b175474e89094c44da98b954eedeac495271d0f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o","decimals":8},{"chainId":4,"address":"0x3413a030EF81a3dD5a302F4B4D11d911e12ed337","decimals":18},{"chainId":3,"address":"terra1zmclyfepfmqvfqflu8r3lv6f75trmg05z7xq95","decimals":8}]},{"symbol":"DYDX","displayName":"dYdX (Portal)","logo":"https://etherscan.io/token/images/dydx2_32.png","coinGeckoId":"dydx","nativeDetails":{"chainId":2,"address":"0x92d6c1e31e14520e676a687f0a93788b716beff5","decimals":18},"wrappedDetails":[{"chainId":1,"address":"4Hx6Bj56eGyw8EJrrheM6LBQAvVYRikYCWsALeTrwyRU","decimals":8}]},{"symbol":"ELON","displayName":"Dogelon Mars (Portal)","logo":"","coinGeckoId":"dogelon-mars","nativeDetails":{"chainId":2,"address":"0x761d38e5ddf6ccf6cf7c55759d5210750b5d60f3","decimals":18},"wrappedDetails":[{"chainId":1,"address":"6nKUU36URHkewHg5GGGAgxs6szkE4VTioGUT5txQqJFU","decimals":8}]},{"symbol":"ENJ","displayName":"EnjinCoin (Portal)","logo":"","coinGeckoId":"enjin","nativeDetails":{"chainId":2,"address":"0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EXExWvT6VyYxEjFzF5BrUxt5GZMPVZnd48y3iWrRefMq","decimals":8}]},{"symbol":"ENS","displayName":"Ethereum Name Service (Portal)","logo":"","coinGeckoId":"ethereum-name-service","nativeDetails":{"chainId":2,"address":"0xc18360217d8f7ab5e7c516566761ea12ce7f9d72","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CLQsDGoGibdNPnVCFp8BAsN2unvyvb41Jd5USYwAnzAg","decimals":8}]},{"symbol":"ETH","displayName":"Ether (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs/logo.png","coinGeckoId":"ether","nativeDetails":{"chainId":2,"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs","decimals":8},{"chainId":4,"address":"0x4DB5a66E937A9F4473fA95b1cAF1d1E1D62E29EA","decimals":18},{"chainId":3,"address":"terra14tl83xcwqjy0ken9peu4pjjuu755lrry2uy25r","decimals":8},{"chainId":5,"address":"0x11CD37bb86F65419713f30673A480EA33c826872","decimals":18},{"chainId":6,"address":"0x8b82A291F83ca07Af22120ABa21632088fC92931","decimals":18},{"chainId":7,"address":"0x3223f17957Ba502cbe71401D55A0DB26E5F7c68F","decimals":18},{"chainId":9,"address":"0x811Cc0d762eA72aC72385d93b98a97263AE37E4C","decimals":18},{"chainId":14,"address":"0x66803FB87aBd4aaC3cbB3fAd7C3aa01f6F3FB207","decimals":18}]},{"symbol":"ETHIX","displayName":"Ethix (Portal)","logo":"https://raw.githubusercontent.com/ethichub/wormhole-token-list/main/src/logogen/base/ETHIX.png","coinGeckoId":"ethichub","nativeDetails":{"chainId":2,"address":"0xFd09911130e6930Bf87F2B0554c44F400bD80D3e","decimals":18},"wrappedDetails":[{"chainId":14,"address":"0x9995cc8F20Db5896943Afc8eE0ba463259c931ed","decimals":18}]},{"symbol":"FRAX","displayName":"Frax (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp/logo.png","coinGeckoId":"frax","nativeDetails":{"chainId":2,"address":"0x853d955acef822db058eb8505911ed77f175b99e","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp","decimals":8}]},{"symbol":"FRONT","displayName":"Frontier (Portal)","logo":"","coinGeckoId":"frontier","nativeDetails":{"chainId":2,"address":"0xf8c3527cc04340b208c854e985240c02f7b7793f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"A9ik2NrpKRRG2snyTjofZQcTuav9yH3mNVHLsLiDQmYt","decimals":8}]},{"symbol":"FTMet","displayName":"Fantom (Portal from Ethereum)","logo":"","coinGeckoId":"fantom","nativeDetails":{"chainId":2,"address":"0x4e15361fd6b4bb609fa63c81a2be19d873717870","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8gC27rQF4NEDYfyf5aS8ZmQJUum5gufowKGYRRba4ENN","decimals":8}]},{"symbol":"FTT","displayName":"FTX Token (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv/logo.png","coinGeckoId":"ftx-token","nativeDetails":{"chainId":2,"address":"0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv","decimals":8},{"chainId":4,"address":"0x49BA054B9664e99ac335667a917c63bB94332E84","decimals":18}]},{"symbol":"FXS","displayName":"Frax Share (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/6LX8BhMQ4Sy2otmAWj7Y5sKd9YTVVUgfMsBzT6B9W7ct/logo.png","coinGeckoId":"frax-share","nativeDetails":{"chainId":2,"address":"0x3432b6a60d23ca0dfca7761b7ab56459d9c964d0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"6LX8BhMQ4Sy2otmAWj7Y5sKd9YTVVUgfMsBzT6B9W7ct","decimals":8}]},{"symbol":"GALA","displayName":"Gala (Portal)","logo":"","coinGeckoId":"gala","nativeDetails":{"chainId":2,"address":"0x15d4c048f83bd7e37d49ea4c83a07267ec4203da","decimals":8},"wrappedDetails":[{"chainId":1,"address":"AuGz22orMknxQHTVGwAu7e3dJikTJKgcjFwMNDikEKmF","decimals":8}]},{"symbol":"GRT","displayName":"Graph Token (Portal)","logo":"","coinGeckoId":"the-graph","nativeDetails":{"chainId":2,"address":"0xc944E90C64B2c07662A292be6244BDf05Cda44a7","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HGsLG4PnZ28L8A4R5nPqKgZd86zUUdmfnkTRnuFJ5dAX","decimals":8}]},{"symbol":"GT","displayName":"GateToken (Portal)","logo":"","coinGeckoId":"gatetoken","nativeDetails":{"chainId":2,"address":"0xe66747a101bff2dba3697199dcce5b743b454759","decimals":18},"wrappedDetails":[{"chainId":1,"address":"ABAq2R9gSpDDGguQxBk4u13s4ZYW6zbwKVBx15mCMG8","decimals":8}]},{"symbol":"HBTC","displayName":"Huobi BTC (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8/logo.png","coinGeckoId":"huobi-btc","nativeDetails":{"chainId":2,"address":"0x0316eb71485b0ab14103307bf65a021042c6d380","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8","decimals":8}]},{"symbol":"HGET","displayName":"Hedget (Portal)","logo":"","coinGeckoId":"hedget","nativeDetails":{"chainId":2,"address":"0x7968bc6a03017ea2de509aaa816f163db0f35148","decimals":6},"wrappedDetails":[{"chainId":1,"address":"2ueY1bLcPHfuFzEJq7yN1V2Wrpu8nkun9xG2TVCE1mhD","decimals":8}]},{"symbol":"HUSD","displayName":"HUSD Stablecoin (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw/logo.png","coinGeckoId":"husd","nativeDetails":{"chainId":2,"address":"0xdf574c24545e5ffecb9a659c229253d4111d87e1","decimals":8},"wrappedDetails":[{"chainId":1,"address":"7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw","decimals":8}]},{"symbol":"HXRO","displayName":"Hxro (Portal)","logo":"","coinGeckoId":"hxro","nativeDetails":{"chainId":2,"address":"0x4bd70556ae3f8a6ec6c4080a0c327b24325438f3","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HxhWkVpk5NS4Ltg5nij2G671CKXFRKPK8vy271Ub4uEK","decimals":8}]},{"symbol":"ICE","displayName":"PopsicleToken (Portal)","logo":"","coinGeckoId":"popsicle-finance","nativeDetails":{"chainId":2,"address":"0xf16e81dce15b08f326220742020379b855b87df9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"DiJut4U3CU8b3bRgwfyqtJMJ4wjzJHaX6hudamjH46Km","decimals":8}]},{"symbol":"ILV","displayName":"Illuvium (Portal)","logo":"","coinGeckoId":"illuvium","nativeDetails":{"chainId":2,"address":"0x767fe9edc9e0df98e07454847909b5e959d7ca0e","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8UJbtpsEubDVkY53rk7d61hNYKkvouicczB2XmuwiG4g","decimals":8}]},{"symbol":"KEEP","displayName":"Keep Network (Portal)","logo":"","coinGeckoId":"keep-network","nativeDetails":{"chainId":2,"address":"0x85eee30c52b0b379b046fb0f85f4f3dc3009afec","decimals":18},"wrappedDetails":[{"chainId":1,"address":"64L6o4G2H7Ln1vN7AHZsUMW4pbFciHyuwn4wUdSbcFxh","decimals":8}]},{"symbol":"KP3R","displayName":"Keep3rV1 (Portal)","logo":"","coinGeckoId":"keep3rv1","nativeDetails":{"chainId":2,"address":"0x1ceb5cb57c4d4e2b2433641b95dd330a33185a44","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3a2VW9t5N6p4baMW3M6yLH1UJ9imMt7VsyUk6ouXPVLq","decimals":8}]},{"symbol":"LDO","displayName":"Lido DAO (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p/logo.png","coinGeckoId":"lido-dao","nativeDetails":{"chainId":2,"address":"0x5a98fcbea516cf06857215779fd812ca3bef1b32","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p","decimals":8},{"chainId":4,"address":"0x986854779804799C1d68867F5E03e601E781e41b","decimals":18},{"chainId":3,"address":"terra1jxypgnfa07j6w92wazzyskhreq2ey2a5crgt6z","decimals":8}]},{"symbol":"LINK","displayName":"Chainlink (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2wpTofQ8SkACrkZWrZDjXPitYa8AwWgX8AfxdeBRRVLX/logo.png","coinGeckoId":"chainlink","nativeDetails":{"chainId":2,"address":"0x514910771af9ca656af840dff83e8264ecf986ca","decimals":18},"wrappedDetails":[{"chainId":1,"address":"2wpTofQ8SkACrkZWrZDjXPitYa8AwWgX8AfxdeBRRVLX","decimals":8},{"chainId":3,"address":"terra12dfv3f0e6m22z6cnhfn3nxk2en3z3zeqy6ctym","decimals":8}]},{"symbol":"LRC","displayName":"Loopring (Portal)","logo":"","coinGeckoId":"loopring","nativeDetails":{"chainId":2,"address":"0xbbbbca6a901c926f240b89eacb641d8aec7aeafd","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HCTVFTzHL21a1dPzKxAUeWwqbE8QMUyvgChFDL4XYoi1","decimals":8}]},{"symbol":"LUA","displayName":"LuaSwap (Portal)","logo":"","coinGeckoId":"luaswap","nativeDetails":{"chainId":2,"address":"0xb1f66997a5760428d3a87d68b90bfe0ae64121cc","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5Wc4U1ZoQRzF4tPdqKQzBwRSjYe8vEf3EvZMuXgtKUW6","decimals":8}]},{"symbol":"MANA","displayName":"Decentraland (Portal)","logo":"https://assets.coingecko.com/coins/images/878/thumb/decentraland-mana.png","coinGeckoId":"decentraland","nativeDetails":{"chainId":2,"address":"0x0F5D2fB29fb7d3CFeE444a200298f468908cC942","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7dgHoN8wBZCc5wbnQ2C47TDnBMAxG4Q5L3KjP67z8kNi","decimals":8}]},{"symbol":"MATH","displayName":"MATH Token (Portal)","logo":"","coinGeckoId":"math","nativeDetails":{"chainId":2,"address":"0x08d967bb0134f2d07f7cfb6e246680c53927dd30","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CaGa7pddFXS65Gznqwp42kBhkJQdceoFVT7AQYo8Jr8Q","decimals":8}]},{"symbol":"MATICet","displayName":"MATIC (Portal from Ethereum)","logo":"","coinGeckoId":"polygon","nativeDetails":{"chainId":2,"address":"0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"C7NNPWuZCNjZBfW5p6JvGsR8pUdsRpEdP1ZAhnoDwj7h","decimals":8}]},{"symbol":"MIMet","displayName":"Magic Internet Money (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HRQke5DKdDo3jV7wnomyiM8AA3EzkVnxMDdo2FQ5XUe1/logo.png","coinGeckoId":"magic-internet-money","nativeDetails":{"chainId":2,"address":"0x99d8a9c45b2eca8864373a26d1459e3dff1e17f3","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HRQke5DKdDo3jV7wnomyiM8AA3EzkVnxMDdo2FQ5XUe1","decimals":8},{"chainId":3,"address":"terra15a9dr3a2a2lj5fclrw35xxg9yuxg0d908wpf2y","decimals":8}]},{"symbol":"NXM","displayName":"Nexus Mutual (Portal)","logo":"","coinGeckoId":"nexus-mutual","nativeDetails":{"chainId":2,"address":"0xd7c49cee7e9188cca6ad8ff264c1da2e69d4cf3b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Aqs5ydqKXEK2cjotDXxHmk8N9PknqQ5q4ZED4ymY1eeh","decimals":8}]},{"symbol":"ORION","displayName":"Orion Money (Portal)","logo":"https://assets.coingecko.com/coins/images/18630/small/YtrqPIWc.png","coinGeckoId":"orion-money","nativeDetails":{"chainId":2,"address":"0x727f064a78dc734d33eec18d5370aef32ffd46e4","decimals":18},"wrappedDetails":[{"chainId":4,"address":"0x3dcB18569425930954feb191122e574b87F66abd","decimals":18},{"chainId":3,"address":"terra1mddcdx0ujx89f38gu7zspk2r2ffdl5enyz2u03","decimals":8},{"chainId":5,"address":"0x5E0294Af1732498C77F8dB015a2d52a76298542B","decimals":18}]},{"symbol":"PAXG","displayName":"Paxos Gold (Portal)","logo":"","coinGeckoId":"pax-gold","nativeDetails":{"chainId":2,"address":"0x45804880de22913dafe09f4980848ece6ecbaf78","decimals":18},"wrappedDetails":[{"chainId":1,"address":"C6oFsE8nXRDThzrMEQ5SxaNFGKoyyfWDDVPw37JKvPTe","decimals":8}]},{"symbol":"PEOPLE","displayName":"ConstitutionDAO (Portal)","logo":"","coinGeckoId":"constitutiondao","nativeDetails":{"chainId":2,"address":"0x7a58c0be72be218b41c608b7fe7c5bb630736c71","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CobcsUrt3p91FwvULYKorQejgsm5HoQdv5T8RUZ6PnLA","decimals":8}]},{"symbol":"PERP","displayName":"Perpetual Protocol (Portal)","logo":"","coinGeckoId":"perpetual-protocol","nativeDetails":{"chainId":2,"address":"0xbc396689893d065f41bc2c6ecbee5e0085233447","decimals":18},"wrappedDetails":[{"chainId":1,"address":"9BsnSWDPfbusseZfnXyZ3un14CyPMZYvsKjWY3Y8Gbqn","decimals":8}]},{"symbol":"RGT","displayName":"Rari Governance Token (Portal)","logo":"","coinGeckoId":"rari-governance-token","nativeDetails":{"chainId":2,"address":"0xd291e7a03283640fdc51b121ac401383a46cc623","decimals":18},"wrappedDetails":[{"chainId":1,"address":"ASk8bss7PoxfFVJfXnSJepj9KupTX15QaRnhdjs6DdYe","decimals":8}]},{"symbol":"RPL","displayName":"Rocket Pool (Portal)","logo":"","coinGeckoId":"rocket-pool","nativeDetails":{"chainId":2,"address":"0xd33526068d116ce69f19a9ee46f0bd304f21a51f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HUCyuyqESEUV4YWTKFvvB4JiQLqoovscTBpRXfGzW4Wx","decimals":8}]},{"symbol":"RSR","displayName":"Reserve Rights (Portal)","logo":"","coinGeckoId":"reserve-rights-token","nativeDetails":{"chainId":2,"address":"0x8762db106B2c2A0bccB3A80d1Ed41273552616E8","decimals":18},"wrappedDetails":[{"chainId":1,"address":"DkbE8U4gSRuGHcVMA1LwyZPYUjYbfEbjW8DMR3iSXBzr","decimals":8}]},{"symbol":"SAND","displayName":"The Sandbox (Portal)","logo":"https://gemini.com/images/currencies/icons/default/sand.svg","coinGeckoId":"the-sandbox","nativeDetails":{"chainId":2,"address":"0x3845badAde8e6dFF049820680d1F14bD3903a5d0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"49c7WuCZkQgc3M4qH8WuEUNXfgwupZf1xqWkDQ7gjRGt","decimals":8}]},{"symbol":"SD","displayName":"Stader SD (Portal)","logo":"https://raw.githubusercontent.com/stader-labs/assets/main/eth/SD.png","coinGeckoId":"stader","nativeDetails":{"chainId":2,"address":"0x30D20208d987713f46DFD34EF128Bb16C404D10f","decimals":18},"wrappedDetails":[{"chainId":3,"address":"terra1ustvnmngueq0p4jd7gfnutgvdc6ujpsjhsjd02","decimals":8}]},{"symbol":"SHIB","displayName":"Shiba Inu (Portal)","logo":"https://etherscan.io/token/images/shibatoken_32.png","coinGeckoId":"shiba-inu","nativeDetails":{"chainId":2,"address":"0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CiKu4eHsVrc1eueVQeHn7qhXTcVu95gSQmBpX4utjL9z","decimals":8},{"chainId":4,"address":"0xb1547683DA678f2e1F003A780143EC10Af8a832B","decimals":18},{"chainId":3,"address":"terra1huku2lecfjhq9d00k5a8dh73gw7dwe6vvuf2dd","decimals":8}]},{"symbol":"SLP","displayName":"Smooth Love Potion (Portal)","logo":"","coinGeckoId":"smooth-love-potion","nativeDetails":{"chainId":2,"address":"0xcc8fa225d80b9c7d42f96e9570156c65d6caaa25","decimals":0},"wrappedDetails":[{"chainId":1,"address":"4hpngEp1v3CXpeKB81Gw4sv7YvwUVRKvY3SGag9ND8Q4","decimals":8}]},{"symbol":"SNX","displayName":"Synthetix Network Token (Portal)","logo":"","coinGeckoId":"synthetix-network-token","nativeDetails":{"chainId":2,"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8cTNUtcV2ueC3royJ642uRnvTxorJAWLZc58gxAo7y56","decimals":8}]},{"symbol":"SOS","displayName":"OpenDAO (Portal)","logo":"","coinGeckoId":"opendao","nativeDetails":{"chainId":2,"address":"0x3b484b82567a09e2588a13d54d032153f0c0aee0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"6Q5fvsJ6kgAFmisgDqqyaFd9FURYzHf8MCUbpAUaGZnE","decimals":8}]},{"symbol":"SPELL","displayName":"Spell Token (Portal)","logo":"","coinGeckoId":"spell-token","nativeDetails":{"chainId":2,"address":"0x090185f2135308bad17527004364ebcc2d37e5f6","decimals":18},"wrappedDetails":[{"chainId":1,"address":"BCsFXYm81iqXyYmrLKgAp3AePcgLHnirb8FjTs6sjM7U","decimals":8}]},{"symbol":"SRMet","displayName":"Serum (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png","coinGeckoId":"serum","nativeDetails":{"chainId":2,"address":"0x476c5e26a75bd202a9683ffd34359c0cc15be0ff","decimals":6},"wrappedDetails":[{"chainId":1,"address":"xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG","decimals":6},{"chainId":4,"address":"0xd63CDf02853D759831550fAe7dF8FFfE0B317b39","decimals":6}]},{"symbol":"SUSHI","displayName":"SushiToken (Portal)","logo":"https://etherscan.io/token/images/sushitoken_32.png","coinGeckoId":"sushi","nativeDetails":{"chainId":2,"address":"0x6b3595068778dd592e39a122f4f5a5cf09c90fe2","decimals":18},"wrappedDetails":[{"chainId":1,"address":"ChVzxWRmrTeSgwd3Ui3UumcN8KX7VK3WaD4KGeSKpypj","decimals":8},{"chainId":4,"address":"0x3524fd7488fdb1F4723BBc22C9cbD1Bf89f46E3B","decimals":18},{"chainId":3,"address":"terra1csvuzlf92nyemu6tv25h0l79etpe8hz3h5vn4a","decimals":8}]},{"symbol":"SWAG","displayName":"SWAG Finance (Portal)","logo":"","coinGeckoId":"swag-finance","nativeDetails":{"chainId":2,"address":"0x87edffde3e14c7a66c9b9724747a1c5696b742e6","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5hcdG6NjQwiNhVa9bcyaaDsCyA1muPQ6WRzQwHfgeeKo","decimals":8}]},{"symbol":"SXP","displayName":"Swipe (Portal)","logo":"","coinGeckoId":"swipe","nativeDetails":{"chainId":2,"address":"0x8ce9137d39326ad0cd6491fb5cc0cba0e089b6a9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3CyiEDRehaGufzkpXJitCP5tvh7cNhRqd9rPBxZrgK5z","decimals":8}]},{"symbol":"TOKE","displayName":"Tokemak (Portal)","logo":"","coinGeckoId":"tokemak","nativeDetails":{"chainId":2,"address":"0x2e9d63788249371f1dfc918a52f8d799f4a38c94","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3EQ6LqLkiFcoxTeGEsHMFpSLWNVPe9yT7XPX2HYSFyxX","decimals":8}]},{"symbol":"TRIBE","displayName":"Tribe (Portal)","logo":"","coinGeckoId":"tribe","nativeDetails":{"chainId":2,"address":"0xc7283b66eb1eb5fb86327f08e1b5816b0720212b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"DPgNKZJAG2w1S6vfYHDBT62R4qrWWH5f45CnxtbQduZE","decimals":8}]},{"symbol":"UBXT","displayName":"UpBots (Portal)","logo":"","coinGeckoId":"upbots","nativeDetails":{"chainId":2,"address":"0x8564653879a18c560e7c0ea0e084c516c62f5653","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FTtXEUosNn6EKG2SQtfbGuYB4rBttreQQcoWn1YDsuTq","decimals":8}]},{"symbol":"UFO","displayName":"UFO Gaming (Portal)","logo":"","coinGeckoId":"ufo-gaming","nativeDetails":{"chainId":2,"address":"0x249e38ea4102d0cf8264d3701f1a0e39c4f2dc3b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"GWdkYFnXnSJAsCBvmsqFLiPPe2tpvXynZcJdxf11Fu3U","decimals":8}]},{"symbol":"UNI","displayName":"Uniswap (Portal)","logo":"https://etherscan.io/token/images/uniswap_32.png","coinGeckoId":"uniswap","nativeDetails":{"chainId":2,"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8FU95xFJhUUkyyCLU13HSzDLs7oC4QZdXQHL6SCeab36","decimals":8},{"chainId":3,"address":"terra1wyxkuy5jq545fn7xfn3enpvs5zg9f9dghf6gxf","decimals":8}]},{"symbol":"USDCet","displayName":"USD Coin (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":2,"address":"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48","decimals":6},"wrappedDetails":[{"chainId":1,"address":"A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM","decimals":6},{"chainId":4,"address":"0xB04906e95AB5D797aDA81508115611fee694c2b3","decimals":6},{"chainId":3,"address":"terra1pepwcav40nvj3kh60qqgrk8k07ydmc00xyat06","decimals":6},{"chainId":5,"address":"0x4318cb63a2b8edf2de971e2f17f77097e499459d","decimals":6},{"chainId":6,"address":"0xB24CA28D4e2742907115fECda335b40dbda07a4C","decimals":6},{"chainId":7,"address":"0xE8A638b3B7565Ee7c5eb9755E58552aFc87b94DD","decimals":6},{"chainId":10,"address":"0x2Ec752329c3EB419136ca5e4432Aa2CDb1eA23e6","decimals":6},{"chainId":14,"address":"0x37f750B7cC259A2f741AF45294f6a16572CF5cAd","decimals":6}]},{"symbol":"USDK","displayName":"USDK (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F/logo.png","coinGeckoId":"usdk","nativeDetails":{"chainId":2,"address":"0x1c48f86ae57291f7686349f12601910bd8d470bb","decimals":18},"wrappedDetails":[{"chainId":1,"address":"43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F","decimals":8}]},{"symbol":"USDTet","displayName":"Tether USD (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg","coinGeckoId":"tether","nativeDetails":{"chainId":2,"address":"0xdac17f958d2ee523a2206206994597c13d831ec7","decimals":6},"wrappedDetails":[{"chainId":1,"address":"Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1","decimals":6},{"chainId":4,"address":"0x524bC91Dc82d6b90EF29F76A3ECAaBAffFD490Bc","decimals":6},{"chainId":3,"address":"terra1ce06wkrdm4vl6t0hvc0g86rsy27pu8yadg3dva","decimals":6},{"chainId":5,"address":"0x9417669fBF23357D2774e9D421307bd5eA1006d2","decimals":6},{"chainId":7,"address":"0xdC19A122e268128B5eE20366299fc7b5b199C8e3","decimals":6}]},{"symbol":"WBTC","displayName":"Wrapped BTC (Portal)","logo":"https://etherscan.io/token/images/wbtc_28.png?v=1","coinGeckoId":"wrapped-bitcoin","nativeDetails":{"chainId":2,"address":"0x2260fac5e5542a773aa44fbcfedf7c193bc2c599","decimals":8},"wrappedDetails":[{"chainId":1,"address":"3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh","decimals":8},{"chainId":3,"address":"terra1aa7upykmmqqc63l924l5qfap8mrmx5rfdm0v55","decimals":8},{"chainId":5,"address":"0x5D49c278340655B56609FdF8976eb0612aF3a0C3","decimals":8},{"chainId":7,"address":"0xd43ce0aa2a29DCb75bDb83085703dc589DE6C7eb","decimals":8}]},{"symbol":"YFI","displayName":"yearn.finance (Portal)","logo":"","coinGeckoId":"yearn-finance","nativeDetails":{"chainId":2,"address":"0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e","decimals":18},"wrappedDetails":[{"chainId":1,"address":"BXZX2JRJFjvKazM1ibeDFxgAngKExb74MRXzXKvgikxX","decimals":8}]},{"symbol":"YGG","displayName":"Yield Guild Games (Portal)","logo":"","coinGeckoId":"yield-guild-games","nativeDetails":{"chainId":2,"address":"0x25f8087ead173b73d6e8b84329989a8eea16cf73","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EzZp7LRN1xwu3QsB2RJRrWwEGjJGsuWzuMCeQDB3NSPK","decimals":8}]},{"symbol":"ZRX","displayName":"0x (Portal)","logo":"","coinGeckoId":"0x","nativeDetails":{"chainId":2,"address":"0xe41d2489571d322189246dafa5ebde1f4699f498","decimals":18},"wrappedDetails":[{"chainId":1,"address":"GJa1VeEYLTRoHbaeqcxfzHmjGCGtZGF3CUqxv9znZZAY","decimals":8}]},{"symbol":"agEUR","displayName":"agEUR (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1/logo.svg","coinGeckoId":"ageur","nativeDetails":{"chainId":2,"address":"0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1","decimals":8}]},{"symbol":"bETH","displayName":"Lido bETH (Portal)","logo":"https://static.lido.fi/bETH/bETH.png","coinGeckoId":"anchor-beth-token","nativeDetails":{"chainId":2,"address":"0x707f9118e33a9b8998bea41dd0d46f38bb963fc8","decimals":18},"wrappedDetails":[{"chainId":3,"address":"terra1u5szg038ur9kzuular3cae8hq6q5rk5u27tuvz","decimals":8}]},{"symbol":"gOHM","displayName":"Governance OHM (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FUGsN8H74WjRBBMfQWcf9Kk32gebA9VnNaGxqwcVvUW7/logo.png","coinGeckoId":"governance-ohm","nativeDetails":{"chainId":2,"address":"0x0ab87046fbb341d058f17cbc4c1133f25a20a52f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FUGsN8H74WjRBBMfQWcf9Kk32gebA9VnNaGxqwcVvUW7","decimals":8},{"chainId":3,"address":"terra1fpfn2kkr8mv390wx4dtpfk3vkjx9ch3thvykl3","decimals":8}]},{"symbol":"ibBTC","displayName":"Interest Bearing Bitcoin (Portal)","logo":"https://etherscan.io/token/images/badgeribtc_32.png","coinGeckoId":"interest-bearing-bitcoin","nativeDetails":{"chainId":2,"address":"0xc4e15973e6ff2a35cc804c2cf9d2a1b817a8b40f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi","decimals":8}]},{"symbol":"stETH","displayName":"Lido Staked Ether (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/H2mf9QNdU2Niq6QR7367Ua2trBsvscLyX5bz7R3Pw5sE/logo.png","coinGeckoId":"lido-staked-ether","nativeDetails":{"chainId":2,"address":"0xae7ab96520de3a18e5e111b5eaab095312d7fe84","decimals":18},"wrappedDetails":[{"chainId":1,"address":"H2mf9QNdU2Niq6QR7367Ua2trBsvscLyX5bz7R3Pw5sE","decimals":8},{"chainId":3,"address":"terra1w7ywr6waxtjuvn5svk5wqydqpjj0q9ps7qct4d","decimals":8}]},{"symbol":"wstETH","displayName":"Lido wstETH (Portal)","logo":"https://static.lido.fi/wstETH/wstETH.png","coinGeckoId":"wrapped-steth","nativeDetails":{"chainId":2,"address":"0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0","decimals":18},"wrappedDetails":[{"chainId":3,"address":"terra133chr09wu8sakfte5v7vd8qzq9vghtkv4tn0ur","decimals":8}]},{"symbol":"BNB","displayName":"Binance Coin (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa/logo.png","coinGeckoId":"binance-coin","nativeDetails":{"chainId":4,"address":"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c","decimals":18},"wrappedDetails":[{"chainId":1,"address":"9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa","decimals":8},{"chainId":2,"address":"0x418D75f65a02b3D53B2418FB8E1fe493759c7605","decimals":18},{"chainId":3,"address":"terra1cetg5wruw2wsdjp7j46rj44xdel00z006e9yg8","decimals":8},{"chainId":5,"address":"0xecdcb5b88f8e3c15f95c720c51c71c9e2080525d","decimals":18},{"chainId":6,"address":"0x442F7f22b1EE2c842bEAFf52880d4573E9201158","decimals":18},{"chainId":7,"address":"0xd79Ef9A91b56c690C7b80570a3c060678667f469","decimals":18}]},{"symbol":"BUSDbs","displayName":"Binance USD (Portal from BSC)","logo":"https://etherscan.io/token/images/binanceusd_32.png","coinGeckoId":"binance-usd","nativeDetails":{"chainId":4,"address":"0xe9e7cea3dedca5984780bafc599bd69add087d56","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2","decimals":8},{"chainId":2,"address":"0x7B4B0B9b024109D182dCF3831222fbdA81369423","decimals":18},{"chainId":3,"address":"terra1skjr69exm6v8zellgjpaa2emhwutrk5a6dz7dd","decimals":8},{"chainId":5,"address":"0xa8d394fe7380b8ce6145d5f85e6ac22d4e91acde","decimals":18},{"chainId":6,"address":"0xA41a6c7E25DdD361343e8Cb8cFa579bbE5eEdb7a","decimals":18},{"chainId":7,"address":"0xf6568FD76f9fcD1f60f73b730F142853c5eF627E","decimals":18}]},{"symbol":"CAKE","displayName":"PancakeSwap Token (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/J8LKx7pr9Zxh9nMhhT7X3EBmj5RzuhFrHKyJAe2F2i9S/logo.png","coinGeckoId":"pancakeswap","nativeDetails":{"chainId":4,"address":"0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82","decimals":18},"wrappedDetails":[{"chainId":1,"address":"J8LKx7pr9Zxh9nMhhT7X3EBmj5RzuhFrHKyJAe2F2i9S","decimals":8},{"chainId":2,"address":"0x7c8161545717a334f3196e765d9713f8042EF338","decimals":18},{"chainId":3,"address":"terra1xvqlpjl2dxyel9qrp6qvtrg04xe3jh9cyxc6av","decimals":8},{"chainId":6,"address":"0x98a4d09036Cc5337810096b1D004109686E56Afc","decimals":18}]},{"symbol":"USDCbs","displayName":"USD Coin (Portal from BSC)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":4,"address":"0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA","decimals":8},{"chainId":2,"address":"0x7cd167B101D2808Cfd2C45d17b2E7EA9F46b74B6","decimals":18},{"chainId":3,"address":"terra1yljlrxvkar0c6ujpvf8g57m5rpcwl7r032zyvu","decimals":8},{"chainId":6,"address":"0x6145E8a910aE937913426BF32De2b26039728ACF","decimals":18},{"chainId":7,"address":"0x4cA2A3De42eabC8fd8b0AC46127E64DB08b9150e","decimals":18}]},{"symbol":"USDTbs","displayName":"Tether USD (Portal from BSC)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg","coinGeckoId":"tether","nativeDetails":{"chainId":4,"address":"0x55d398326f99059fF775485246999027B3197955","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv","decimals":8},{"chainId":2,"address":"0xDe60aDfDdAAbaAAC3dAFa57B26AcC91Cb63728c4","decimals":18},{"chainId":3,"address":"terra1vlqeghv5mt5udh96kt5zxlh2wkh8q4kewkr0dd","decimals":8},{"chainId":6,"address":"0xA67BCC0D06d7d13A13A2AE30bF30f1B434f5a28B","decimals":18},{"chainId":7,"address":"0x366EF31C8dc715cbeff5fA54Ad106dC9c25C6153","decimals":18}]},{"symbol":"LUNA","displayName":"LUNA (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W/logo.png","coinGeckoId":"terra-luna","nativeDetails":{"chainId":3,"address":"uluna","decimals":6},"wrappedDetails":[{"chainId":1,"address":"F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W","decimals":6},{"chainId":2,"address":"0xbd31ea8212119f94a611fa969881cba3ea06fa3d","decimals":6},{"chainId":4,"address":"0x156ab3346823B651294766e23e6Cf87254d68962","decimals":6},{"chainId":5,"address":"0x9cd6746665D9557e1B9a775819625711d0693439","decimals":6},{"chainId":6,"address":"0x70928E5B188def72817b7775F0BF6325968e563B","decimals":6},{"chainId":7,"address":"0x4F43717B20ae319Aa50BC5B2349B93af5f7Ac823","decimals":6},{"chainId":10,"address":"0x593AE1d34c8BD7587C11D539E4F42BFf242c82Af","decimals":6},{"chainId":9,"address":"0x12302fbE05a7e833f87d4B7843F58d19BE4FdE3B","decimals":6}]},{"symbol":"UST","displayName":"UST (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i/logo.png","coinGeckoId":"terra-usd","nativeDetails":{"chainId":3,"address":"uusd","decimals":6},"wrappedDetails":[{"chainId":1,"address":"9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i","decimals":6},{"chainId":2,"address":"0xa693B19d2931d498c5B318dF961919BB4aee87a5","decimals":6},{"chainId":4,"address":"0x3d4350cD54aeF9f9b2C29435e0fa809957B3F30a","decimals":6},{"chainId":5,"address":"0xE6469Ba6D2fD6130788E0eA9C0a0515900563b59","decimals":6},{"chainId":6,"address":"0xb599c3590F42f8F995ECfa0f85D2980B76862fc1","decimals":6},{"chainId":7,"address":"0xa1E73c01E0cF7930F5e91CB291031739FE5Ad6C2","decimals":6},{"chainId":10,"address":"0x846e4D51d7E2043C1a87E0Ab7490B93FB940357b","decimals":6},{"chainId":9,"address":"0x8D07bBb478B84f7E940e97C8e9cF7B3645166b03","decimals":6}]},{"symbol":"aUST","displayName":"AnchorUST (Portal)","logo":"","coinGeckoId":"anchorust","nativeDetails":{"chainId":3,"address":"terra1hzh9vpxhsk8253se0vv5jj6etdvxu3nv8z07zu","decimals":6},"wrappedDetails":[{"chainId":1,"address":"4CsZsUCoKFiaGyU7DEVDayqeVtG8iqgGDR6RjzQmzQao","decimals":6},{"chainId":4,"address":"0x8b04E56A8cd5f4D465b784ccf564899F30Aaf88C","decimals":6}]},{"symbol":"DAIpo","displayName":"DAI (Portal from Polygon)","logo":"","coinGeckoId":"dai","nativeDetails":{"chainId":5,"address":"0x8f3cf7ad23cd3cadbd9735aff958023239c6a063","decimals":18},"wrappedDetails":[{"chainId":1,"address":"4Fo67MYQpVhZj9R7jQTd63FPAnWbPpaafAUxsMGX2geP","decimals":8}]},{"symbol":"MATICpo","displayName":"MATIC (Portal from Polygon)","logo":"","coinGeckoId":"polygon","nativeDetails":{"chainId":5,"address":"0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Gz7VkD4MacbEB6yC5XD3HcumEiYx2EtDYYrfikGsvopG","decimals":8},{"chainId":2,"address":"0x7c9f4C87d911613Fe9ca58b579f737911AAD2D43","decimals":18},{"chainId":4,"address":"0xc836d8dC361E44DbE64c4862D55BA041F88Ddd39","decimals":18},{"chainId":3,"address":"terra1dtqlfecglk47yplfrtwjzyagkgcqqngd5lgjp8","decimals":8},{"chainId":6,"address":"0xf2f13f0B7008ab2FA4A2418F4ccC3684E49D20Eb","decimals":18}]},{"symbol":"QUICK","displayName":"Quickswap (Portal)","logo":"","coinGeckoId":"quickswap","nativeDetails":{"chainId":5,"address":"0x831753dd7087cac61ab5644b308642cc1c33dc13","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5njTmK53Ss5jkiHHZvzabVzZj6ztu6WYWpAPYgbVnbjs","decimals":8}]},{"symbol":"USDCpo","displayName":"USD Coin (PoS) (Portal from Polygon)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":5,"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","decimals":6},"wrappedDetails":[{"chainId":1,"address":"E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M","decimals":6},{"chainId":2,"address":"0x566957eF80F9fd5526CD2BEF8BE67035C0b81130","decimals":6},{"chainId":4,"address":"0x672147dD47674757C457eB155BAA382cc10705Dd","decimals":6},{"chainId":3,"address":"terra1kkyyh7vganlpkj0gkc2rfmhy858ma4rtwywe3x","decimals":6},{"chainId":6,"address":"0x543672E9CBEC728CBBa9C3Ccd99ed80aC3607FA8","decimals":6},{"chainId":7,"address":"0x3E62a9c3aF8b810dE79645C4579acC8f0d06a241","decimals":6}]},{"symbol":"USDTpo","displayName":"Tether USD (PoS) (Portal from Polygon)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1/logo.png","coinGeckoId":"tether","nativeDetails":{"chainId":5,"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6},"wrappedDetails":[{"chainId":1,"address":"5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1","decimals":6},{"chainId":7,"address":"0xFffD69E757d8220CEA60dc80B9Fe1a30b58c94F3","decimals":6}]},{"symbol":"AVAX","displayName":"AVAX (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/KgV1GvrHQmRBY8sHQQeUKwTm2r2h8t4C8qt12Cw1HVE/logo.png","coinGeckoId":"avalanche","nativeDetails":{"chainId":6,"address":"0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7","decimals":18},"wrappedDetails":[{"chainId":1,"address":"KgV1GvrHQmRBY8sHQQeUKwTm2r2h8t4C8qt12Cw1HVE","decimals":8},{"chainId":2,"address":"0x85f138bfEE4ef8e540890CFb48F620571d67Eda3","decimals":18},{"chainId":4,"address":"0x96412902aa9aFf61E13f085e70D3152C6ef2a817","decimals":18},{"chainId":3,"address":"terra1hj8de24c3yqvcsv9r8chr03fzwsak3hgd8gv3m","decimals":8},{"chainId":5,"address":"0x7Bb11E7f8b10E9e571E5d8Eace04735fDFB2358a","decimals":18},{"chainId":7,"address":"0x32847e63E99D3a044908763056e25694490082F8","decimals":18}]},{"symbol":"JOE","displayName":"JoeToken (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CriXdFS9iRAYbGEQiTcUqbWwG9RBmYt5B6LwTnoJ61Sm/logo.png","coinGeckoId":"joe","nativeDetails":{"chainId":6,"address":"0x6e84a6216ea6dacc71ee8e6b0a5b7322eebc0fdd","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CriXdFS9iRAYbGEQiTcUqbWwG9RBmYt5B6LwTnoJ61Sm","decimals":8}]},{"symbol":"USDCav","displayName":"USD Coin (Portal from Avalanche)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":6,"address":"0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664","decimals":6},"wrappedDetails":[{"chainId":1,"address":"AGqKX7F4mqJ8x2mUQVangJb5pWQJApaKoUfe5gXM53CV","decimals":8},{"chainId":4,"address":"0xc1F47175d96Fe7c4cD5370552e5954f384E3C791","decimals":6},{"chainId":3,"address":"terra1pvel56a2hs93yd429pzv9zp5aptcjg5ulhkz7w","decimals":6},{"chainId":7,"address":"0x05CbE6319Dcc937BdbDf0931466F4fFd0d392B47","decimals":6}]},{"symbol":"USDTav","displayName":"Tether USD (Portal from Avalanche)","logo":"","coinGeckoId":"tether","nativeDetails":{"chainId":6,"address":"0xc7198437980c041c805a1edcba50c1ce5db95118","decimals":6},"wrappedDetails":[{"chainId":1,"address":"B2wfeYz5VtBnQVrX4M8F6FeDrprVrzKPws5qg1in8bzR","decimals":8},{"chainId":4,"address":"0x2B90E061a517dB2BbD7E39Ef7F733Fd234B494CA","decimals":6},{"chainId":3,"address":"terra1eqvq3thjhye7anv6f6mhxpjhyvww8zjvqcdgjx","decimals":6},{"chainId":7,"address":"0x05832a0905E516f29344ADBa1c2052a788B10129","decimals":6}]},{"symbol":"ROSE","displayName":"ROSE (Portal)","logo":"https://assets.coingecko.com/coins/images/13162/small/rose.png","coinGeckoId":"oasis-network","nativeDetails":{"chainId":7,"address":"0x21C718C22D52d0F3a789b752D4c2fD5908a8A733","decimals":18},"wrappedDetails":[{"chainId":1,"address":"S3SQfD6RheMXQ3EEYn1Z5sJsbtwfXdt7tSAVXPQFtYo","decimals":8},{"chainId":2,"address":"0x26B80FBfC01b71495f477d5237071242e0d959d7","decimals":18},{"chainId":4,"address":"0x6c6D604D3f07aBE287C1A3dF0281e999A83495C0","decimals":18},{"chainId":6,"address":"0x12AF5C1a232675f62F405b5812A80e7a6F75D746","decimals":18}]},{"symbol":"SWEAT","displayName":"Sweat Economy","logo":"https://assets.coingecko.com/coins/images/25057/small/fhD9Xs16_400x400.jpg?1649947000","coinGeckoId":"sweatcoin","nativeDetails":{"chainId":15,"address":"token.sweat","decimals":18},"wrappedDetails":[{"chainId":2,"address":"0xB4b9DC1C77bdbb135eA907fd5a08094d98883A35","decimals":18},{"chainId":4,"address":"0x510Ad22d8C956dCC20f68932861f54A591001283","decimals":18}]}] \ No newline at end of file From e771efc9a01b8362966273eb9443872969b533c7 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 18:04:40 +0200 Subject: [PATCH 05/24] refactor(core): Adjust InitiateWormholeTransferParams to take sourceAddress --- packages/core/src/client.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts index 7e8d35efc..9934fe184 100644 --- a/packages/core/src/client.ts +++ b/packages/core/src/client.ts @@ -1,5 +1,4 @@ import type { ChainId } from "@certusone/wormhole-sdk"; -import type { TokenProjectId } from "@swim-io/token-projects"; import type Decimal from "decimal.js"; import type { ChainConfig } from "./chain"; @@ -10,17 +9,16 @@ export interface WrappedTokenInfo { readonly originChainId: ChainId; /** Standardized Wormhole format, ie 32 bytes */ readonly originAddress: Uint8Array; - /** Ecosystem-specific format */ - readonly wrappedAddress: string; } export interface InitiatePortalTransferParams { readonly atomicAmount: string; readonly interactionId: string; + /** Ecosystem-specific address format */ + readonly sourceAddress: string; /** Standardized Wormhole format, ie 32 bytes */ readonly targetAddress: Uint8Array; readonly targetChainId: ChainId; - readonly tokenProjectId: TokenProjectId; readonly wallet: Wallet; readonly wrappedTokenInfo?: WrappedTokenInfo; } From 49c02b95334abf037a53112b9a055ce6a8a57aff Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 18:08:37 +0200 Subject: [PATCH 06/24] refactor(evm): Update for new InitiateWormholeTransferParams --- packages/evm/src/client.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/evm/src/client.ts b/packages/evm/src/client.ts index 1addf126c..036c2bfed 100644 --- a/packages/evm/src/client.ts +++ b/packages/evm/src/client.ts @@ -4,7 +4,7 @@ import { createNonce, getAllowanceEth, } from "@certusone/wormhole-sdk"; -import { Client, getTokenDetails } from "@swim-io/core"; +import { Client } from "@swim-io/core"; import type { CompletePortalTransferParams, InitiatePortalTransferParams, @@ -154,11 +154,10 @@ export class EvmClient extends Client< public async *generateInitiatePortalTransferTxs({ atomicAmount, interactionId, + sourceAddress, targetAddress, targetChainId, - tokenProjectId, wallet, - wrappedTokenInfo, }: InitiatePortalTransferParams): AsyncGenerator< TxGeneratorResult< TransactionReceipt, @@ -166,15 +165,11 @@ export class EvmClient extends Client< EvmTxType.Erc20Approve | EvmTxType.PortalTransferTokens > > { - const mintAddress = - wrappedTokenInfo?.wrappedAddress ?? - getTokenDetails(this.chainConfig, tokenProjectId).address; - await wallet.switchNetwork(this.chainConfig.chainId); const approvalGenerator = this.generateErc20ApproveTxs({ atomicAmount, - mintAddress, + mintAddress: sourceAddress, spenderAddress: this.chainConfig.wormhole.portal, wallet, }); @@ -185,7 +180,7 @@ export class EvmClient extends Client< const tx = await this.transferToken({ interactionId, - mintAddress, + mintAddress: sourceAddress, atomicAmount, targetChainId, targetAddress, From 8b9eebbbf20dfcc1a0006251419742730de49b36 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 18:09:13 +0200 Subject: [PATCH 07/24] refactor(solana): Update for new InitiateWormholeTransferParams --- packages/solana/src/client.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/solana/src/client.ts b/packages/solana/src/client.ts index 7974a65d6..e85352107 100644 --- a/packages/solana/src/client.ts +++ b/packages/solana/src/client.ts @@ -25,7 +25,7 @@ import type { TokenDetails, TxGeneratorResult, } from "@swim-io/core"; -import { Client, getTokenDetails } from "@swim-io/core"; +import { Client } from "@swim-io/core"; import { atomicToHuman, chunks, sleep } from "@swim-io/utils"; import Decimal from "decimal.js"; @@ -177,10 +177,10 @@ export class SolanaClient extends Client< public async *generateInitiatePortalTransferTxs({ atomicAmount, - targetChainId, + sourceAddress, targetAddress, + targetChainId, interactionId, - tokenProjectId, wallet, wrappedTokenInfo, auxiliarySigner = Keypair.generate(), @@ -197,11 +197,8 @@ export class SolanaClient extends Client< if (solanaWalletAddress === null) { throw new Error("No Solana wallet address"); } - const mintAddress = - wrappedTokenInfo?.wrappedAddress ?? - getTokenDetails(this.chainConfig, tokenProjectId).address; const associatedTokenAccountAddress = getAssociatedTokenAddressSync( - new PublicKey(mintAddress), + new PublicKey(sourceAddress), new PublicKey(solanaWalletAddress), ).toBase58(); const txRequest = await createTransferFromSolanaTx({ @@ -212,7 +209,7 @@ export class SolanaClient extends Client< payerAddress: solanaWalletAddress, auxiliarySignerAddress: auxiliarySigner.publicKey.toString(), fromAddress: associatedTokenAccountAddress, - mintAddress, + mintAddress: sourceAddress, amount: BigInt(atomicAmount), targetAddress, targetChainId, From 470ab4339c466a1761176f47ce21f883a407c457 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 18:11:38 +0200 Subject: [PATCH 08/24] WIP: revert --- apps/ui/package.json | 20 +++--- yarn.lock | 160 ++++--------------------------------------- 2 files changed, 24 insertions(+), 156 deletions(-) diff --git a/apps/ui/package.json b/apps/ui/package.json index 4a848ea2d..8c9b1eeff 100644 --- a/apps/ui/package.json +++ b/apps/ui/package.json @@ -50,16 +50,16 @@ "@sentry/types": "^7.9.0", "@solana/spl-token": "^0.3.5", "@solana/web3.js": "^1.62.0", - "@swim-io/aptos": "^0.40.0", - "@swim-io/core": "^0.40.0", - "@swim-io/evm": "^0.40.0", - "@swim-io/evm-contracts": "^0.40.0", - "@swim-io/pool-math": "^0.40.0", - "@swim-io/solana": "^0.40.0", - "@swim-io/solana-contracts": "^0.40.0", - "@swim-io/token-projects": "^0.40.0", - "@swim-io/utils": "^0.40.0", - "@swim-io/wormhole": "^0.40.0", + "@swim-io/aptos": "workspace:^", + "@swim-io/core": "workspace:^", + "@swim-io/evm": "workspace:^", + "@swim-io/evm-contracts": "workspace:^", + "@swim-io/pool-math": "workspace:^", + "@swim-io/solana": "workspace:^", + "@swim-io/solana-contracts": "workspace:^", + "@swim-io/token-projects": "workspace:^", + "@swim-io/utils": "workspace:^", + "@swim-io/wormhole": "workspace:^", "bn.js": "^5.2.1", "classnames": "^2.3.1", "decimal.js": "^10.3.1", diff --git a/yarn.lock b/yarn.lock index 851b20be7..84e47f862 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7156,21 +7156,7 @@ __metadata: languageName: node linkType: hard -"@swim-io/aptos@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/aptos@npm:0.40.0" - dependencies: - "@swim-io/core": ^0.40.0 - "@swim-io/utils": ^0.40.0 - aptos: ^1.3.13 - peerDependencies: - decimal.js: ^10.3.1 - eventemitter3: ^4.0.7 - checksum: c20ed5033c04f12909ba46605ea40a5866db25cfe5ae08a8fe2e99c1a99fab2c8488e11d5737c74b5cc6ae282f2819097fd71e8a9af2a7dc507f08785d3a8496 - languageName: node - linkType: hard - -"@swim-io/aptos@workspace:packages/aptos": +"@swim-io/aptos@workspace:^, @swim-io/aptos@workspace:packages/aptos": version: 0.0.0-use.local resolution: "@swim-io/aptos@workspace:packages/aptos" dependencies: @@ -7261,19 +7247,6 @@ __metadata: languageName: node linkType: hard -"@swim-io/core@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/core@npm:0.40.0" - dependencies: - "@swim-io/token-projects": ^0.40.0 - "@swim-io/utils": ^0.40.0 - decimal.js: ^10.3.1 - peerDependencies: - "@certusone/wormhole-sdk": ^0.6.2 - checksum: 8f71a7c1708ae099d70fa6f39c3eac475702c948ed670924a66053ed8def4578358365a8e48d1fb31f253fd6df515b1827977f6072561159d7e604cfa8207afc - languageName: node - linkType: hard - "@swim-io/core@workspace:^, @swim-io/core@workspace:packages/core": version: 0.0.0-use.local resolution: "@swim-io/core@workspace:packages/core" @@ -7365,13 +7338,6 @@ __metadata: languageName: node linkType: hard -"@swim-io/evm-contracts@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/evm-contracts@npm:0.40.0" - checksum: 5061e0d2594e4912f271613f2cbbfb819238a809cb3c01a086339e325890607fd67efe8f5b47d6d434b016d8b92c6968331458a49ed4da9333753cc2fcf19145 - languageName: node - linkType: hard - "@swim-io/evm-contracts@workspace:^, @swim-io/evm-contracts@workspace:packages/evm-contracts": version: 0.0.0-use.local resolution: "@swim-io/evm-contracts@workspace:packages/evm-contracts" @@ -7426,27 +7392,7 @@ __metadata: languageName: node linkType: hard -"@swim-io/evm@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/evm@npm:0.40.0" - dependencies: - "@swim-io/core": ^0.40.0 - "@swim-io/evm-contracts": ^0.40.0 - "@swim-io/token-projects": ^0.40.0 - "@swim-io/utils": ^0.40.0 - graphql: ^16.6.0 - graphql-request: ^4.3.0 - moralis: ^1.8.0 - peerDependencies: - "@certusone/wormhole-sdk": ^0.6.2 - decimal.js: ^10.3.1 - ethers: ^5.6.9 - eventemitter3: ^4.0.7 - checksum: ba65ee3dcf51c9a4c1e329a7597b41c4226028f2fc76afd57c9e8185b20e04ef5563d47cdf017ec9aa122e148162408b16d544a167c6953b251a77fc83cebdfb - languageName: node - linkType: hard - -"@swim-io/evm@workspace:packages/evm": +"@swim-io/evm@workspace:^, @swim-io/evm@workspace:packages/evm": version: 0.0.0-use.local resolution: "@swim-io/evm@workspace:packages/evm" dependencies: @@ -7505,15 +7451,6 @@ __metadata: languageName: unknown linkType: soft -"@swim-io/pool-math@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/pool-math@npm:0.40.0" - peerDependencies: - decimal.js: ^10.3.1 - checksum: 6b3de0916194bcab630111aa1bc34d46d046c7d1960437a734b354a5f376e23e89ccfa228a077332ff33989373a9de6d883ff437849bd2cf61526d6db52d5843 - languageName: node - linkType: hard - "@swim-io/pool-math@workspace:^, @swim-io/pool-math@workspace:packages/pool-math": version: 0.0.0-use.local resolution: "@swim-io/pool-math@workspace:packages/pool-math" @@ -7640,19 +7577,7 @@ __metadata: languageName: unknown linkType: soft -"@swim-io/solana-contracts@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/solana-contracts@npm:0.40.0" - peerDependencies: - "@project-serum/anchor": ^0.25.0 - "@project-serum/borsh": ^0.2.5 - "@solana/spl-token": ^0.2.0 - "@solana/web3.js": ^1.50.1 - checksum: 5f78da938ff92fa660024ed2ad63345db68bee8b0f83f7e26cb86aa7e959a6e35d8afece1d11374274037b0821b4d55e1597f1ba40e1814a65e8faf75e75c041 - languageName: node - linkType: hard - -"@swim-io/solana-contracts@workspace:packages/solana-contracts": +"@swim-io/solana-contracts@workspace:^, @swim-io/solana-contracts@workspace:packages/solana-contracts": version: 0.0.0-use.local resolution: "@swim-io/solana-contracts@workspace:packages/solana-contracts" dependencies: @@ -7779,28 +7704,6 @@ __metadata: languageName: node linkType: hard -"@swim-io/solana@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/solana@npm:0.40.0" - dependencies: - "@ledgerhq/hw-transport": ^6.27.1 - "@ledgerhq/hw-transport-webusb": ^6.0.2 - "@project-serum/sol-wallet-adapter": 0.2.2 - "@swim-io/core": ^0.40.0 - "@swim-io/token-projects": ^0.40.0 - "@swim-io/utils": ^0.40.0 - peerDependencies: - "@certusone/wormhole-sdk": ^0.6.2 - "@project-serum/borsh": ^0.2.5 - "@solana/spl-token": ^0.3.4 - "@solana/web3.js": ^1.62.0 - bn.js: ^5.2.1 - decimal.js: ^10.3.1 - ethers: ^5.7.0 - checksum: 207c35b40b87f6e2bdbec0a50dcbe0cb5bb437d5170e2691790b56c1c91fff508ea2cb5ec9cb8abbf52dcd23a1ca1e1663e843abee9e10c57eec1996584c186b - languageName: node - linkType: hard - "@swim-io/solana@workspace:^, @swim-io/solana@workspace:packages/solana": version: 0.0.0-use.local resolution: "@swim-io/solana@workspace:packages/solana" @@ -7891,15 +7794,6 @@ __metadata: languageName: node linkType: hard -"@swim-io/token-projects@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/token-projects@npm:0.40.0" - dependencies: - "@swim-io/utils": ^0.40.0 - checksum: 48958357bcb6d30978833321f9e6db875581102416327f50b345515166505a5ce5e6e5f1b0d3d458ac440503f3cc9cb9436384e59da86da703f1e95e15518733 - languageName: node - linkType: hard - "@swim-io/token-projects@workspace:^, @swim-io/token-projects@workspace:packages/token-projects": version: 0.0.0-use.local resolution: "@swim-io/token-projects@workspace:packages/token-projects" @@ -7966,18 +7860,18 @@ __metadata: "@storybook/manager-webpack4": ^6.5.10 "@storybook/node-logger": ^6.5.10 "@storybook/react": ^6.5.10 - "@swim-io/aptos": ^0.40.0 - "@swim-io/core": ^0.40.0 + "@swim-io/aptos": "workspace:^" + "@swim-io/core": "workspace:^" "@swim-io/eslint-config": "workspace:^" - "@swim-io/evm": ^0.40.0 - "@swim-io/evm-contracts": ^0.40.0 - "@swim-io/pool-math": ^0.40.0 - "@swim-io/solana": ^0.40.0 - "@swim-io/solana-contracts": ^0.40.0 - "@swim-io/token-projects": ^0.40.0 + "@swim-io/evm": "workspace:^" + "@swim-io/evm-contracts": "workspace:^" + "@swim-io/pool-math": "workspace:^" + "@swim-io/solana": "workspace:^" + "@swim-io/solana-contracts": "workspace:^" + "@swim-io/token-projects": "workspace:^" "@swim-io/tsconfig": "workspace:^" - "@swim-io/utils": ^0.40.0 - "@swim-io/wormhole": ^0.40.0 + "@swim-io/utils": "workspace:^" + "@swim-io/wormhole": "workspace:^" "@testing-library/jest-dom": ^5.16.4 "@testing-library/react": ^12.1.5 "@testing-library/react-hooks": ^7.0.2 @@ -8052,15 +7946,6 @@ __metadata: languageName: node linkType: hard -"@swim-io/utils@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/utils@npm:0.40.0" - peerDependencies: - decimal.js: ^10.3.1 - checksum: 0a9c84c556c57015aa118ddb4b72a00e01ac837c1c7870e475897b85a0cfdc1583f9e90b6615a804a90e8185fa80bc05e06e8f15275dda0dcd8475bbbb219bb3 - languageName: node - linkType: hard - "@swim-io/utils@workspace:^, @swim-io/utils@workspace:packages/utils": version: 0.0.0-use.local resolution: "@swim-io/utils@workspace:packages/utils" @@ -8088,24 +7973,7 @@ __metadata: languageName: unknown linkType: soft -"@swim-io/wormhole@npm:^0.40.0": - version: 0.40.0 - resolution: "@swim-io/wormhole@npm:0.40.0" - dependencies: - "@swim-io/core": ^0.40.0 - "@swim-io/solana": ^0.40.0 - "@swim-io/utils": ^0.40.0 - grpc-web: ^1.3.1 - peerDependencies: - "@certusone/wormhole-sdk": ^0.6.2 - "@solana/spl-token": ^0.3.4 - "@solana/web3.js": ^1.62.0 - ethers: ^5.6.9 - checksum: 12af304e4184bb1db601df1bc8a3c40f38f76ef64d18de5bfcc783b55680adc3090fb7beb08bcee15c9a22313a724fb6418713eaa628f0fad1be449865455f9e - languageName: node - linkType: hard - -"@swim-io/wormhole@workspace:packages/wormhole": +"@swim-io/wormhole@workspace:^, @swim-io/wormhole@workspace:packages/wormhole": version: 0.0.0-use.local resolution: "@swim-io/wormhole@workspace:packages/wormhole" dependencies: From 023c8097a09537a54e2bd3176db3e4ece2a2af89 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 18:11:53 +0200 Subject: [PATCH 09/24] refactor(ui): Update for new InitiateWormholeTransferParams --- .../hooks/interaction/useFromSolanaTransferMutation.ts | 6 ++---- .../hooks/interaction/useToSolanaTransferMutation.ts | 2 +- apps/ui/src/models/wormhole/getWrappedTokenInfo.ts | 10 +--------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/apps/ui/src/hooks/interaction/useFromSolanaTransferMutation.ts b/apps/ui/src/hooks/interaction/useFromSolanaTransferMutation.ts index 89f8d5370..b24edddd8 100644 --- a/apps/ui/src/hooks/interaction/useFromSolanaTransferMutation.ts +++ b/apps/ui/src/hooks/interaction/useFromSolanaTransferMutation.ts @@ -13,7 +13,6 @@ import { useMutation } from "react-query"; import { ECOSYSTEMS, Protocol, - getSolanaTokenDetails, getTokenDetailsForEcosystem, getWormholeRetries, } from "../../config"; @@ -128,7 +127,6 @@ export const useFromSolanaTransferMutation = () => { } const amount = Amount.fromHuman(token, value); const evmEcosystem = ECOSYSTEMS[toEcosystem]; - const solanaTokenDetails = getSolanaTokenDetails(token); const evmWallet = wallets[toEcosystem].wallet; if (!evmWallet) { throw new Error("No EVM wallet"); @@ -142,7 +140,7 @@ export const useFromSolanaTransferMutation = () => { throw new Error("No token details"); } const splTokenAccount = findTokenAccountForMint( - solanaTokenDetails.address, + token.nativeDetails.address, solanaWalletAddress, splTokenAccounts, ); @@ -157,12 +155,12 @@ export const useFromSolanaTransferMutation = () => { solanaClient.generateInitiatePortalTransferTxs({ atomicAmount: amount.toAtomicString(SOLANA_ECOSYSTEM_ID), interactionId, + sourceAddress: token.nativeDetails.address, targetAddress: formatWormholeAddress( evmEcosystem.protocol, evmWalletAddress, ), targetChainId: evmEcosystem.wormholeChainId, - tokenProjectId: token.projectId, wallet: solanaWallet, auxiliarySigner, wrappedTokenInfo: getWrappedTokenInfo(token, SOLANA_ECOSYSTEM_ID), diff --git a/apps/ui/src/hooks/interaction/useToSolanaTransferMutation.ts b/apps/ui/src/hooks/interaction/useToSolanaTransferMutation.ts index 1662c04e3..1f91397cc 100644 --- a/apps/ui/src/hooks/interaction/useToSolanaTransferMutation.ts +++ b/apps/ui/src/hooks/interaction/useToSolanaTransferMutation.ts @@ -105,12 +105,12 @@ export const useToSolanaTransferMutation = () => { ].generateInitiatePortalTransferTxs({ atomicAmount: humanDecimalToAtomicString(value, token, fromEcosystem), interactionId, + sourceAddress: token.nativeDetails.address, targetAddress: formatWormholeAddress( Protocol.Solana, splTokenAccount.address.toBase58(), ), targetChainId: WormholeChainId.Solana, - tokenProjectId: token.projectId, wallet: evmWallet, wrappedTokenInfo: getWrappedTokenInfo(token, fromEcosystem), }); diff --git a/apps/ui/src/models/wormhole/getWrappedTokenInfo.ts b/apps/ui/src/models/wormhole/getWrappedTokenInfo.ts index d13d88667..275b51360 100644 --- a/apps/ui/src/models/wormhole/getWrappedTokenInfo.ts +++ b/apps/ui/src/models/wormhole/getWrappedTokenInfo.ts @@ -1,7 +1,7 @@ import type { WrappedTokenInfo } from "@swim-io/core"; import type { EcosystemId, TokenConfig } from "../../config"; -import { ECOSYSTEMS, getTokenDetailsForEcosystem } from "../../config"; +import { ECOSYSTEMS } from "../../config"; import { formatWormholeAddress } from "./formatWormholeAddress"; @@ -14,19 +14,11 @@ export const getWrappedTokenInfo = ( } const nativeAddress = tokenConfig.nativeDetails.address; const nativeEcosystem = ECOSYSTEMS[tokenConfig.nativeEcosystemId]; - const sourceTokenDetails = getTokenDetailsForEcosystem( - tokenConfig, - sourceEcosystemId, - ); - if (sourceTokenDetails === null) { - throw new Error("No source token details"); - } return { originAddress: formatWormholeAddress( nativeEcosystem.protocol, nativeAddress, ), originChainId: nativeEcosystem.wormholeChainId, - wrappedAddress: sourceTokenDetails.address, }; }; From 55ba5d03e98247619ebb163a480699c93f8fe4aa Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 21:08:13 +0200 Subject: [PATCH 10/24] feat(ui): Add Wormhole transfer models --- apps/ui/src/models/wormhole/index.ts | 1 + apps/ui/src/models/wormhole/transfer.ts | 57 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 apps/ui/src/models/wormhole/transfer.ts diff --git a/apps/ui/src/models/wormhole/index.ts b/apps/ui/src/models/wormhole/index.ts index 6ca9cc732..9b78077c0 100644 --- a/apps/ui/src/models/wormhole/index.ts +++ b/apps/ui/src/models/wormhole/index.ts @@ -3,3 +3,4 @@ export * from "./formatWormholeAddress"; export * from "./getWrappedTokenInfo"; export * from "./guardiansRpc"; export * from "./solana"; +export * from "./transfer"; diff --git a/apps/ui/src/models/wormhole/transfer.ts b/apps/ui/src/models/wormhole/transfer.ts new file mode 100644 index 000000000..007e40f76 --- /dev/null +++ b/apps/ui/src/models/wormhole/transfer.ts @@ -0,0 +1,57 @@ +import type { ChainId } from "@certusone/wormhole-sdk"; +import type { WrappedTokenInfo } from "@swim-io/core"; +import { findOrThrow } from "@swim-io/utils"; +import type Decimal from "decimal.js"; + +import { ECOSYSTEM_LIST } from "../../config"; + +import { formatWormholeAddress } from "./formatWormholeAddress"; + +export interface TxResult { + readonly chainId: ChainId; + readonly txId: string; +} + +export interface WormholeTokenDetails { + readonly chainId: ChainId; + readonly address: string; + readonly decimals: number; +} + +export interface WormholeToken { + readonly symbol: string; + readonly displayName: string; + readonly logo: string; + readonly coinGeckoId: string; + readonly nativeDetails: WormholeTokenDetails; + readonly wrappedDetails: readonly WormholeTokenDetails[]; +} + +export interface WormholeTransfer { + readonly interactionId: string; + readonly value: Decimal; + readonly sourceDetails: WormholeTokenDetails; + readonly targetDetails: WormholeTokenDetails; + readonly nativeDetails: WormholeTokenDetails; + readonly onTxResult: (txResult: TxResult) => any; +} + +export const getWrappedTokenInfoFromNativeDetails = ( + sourceChainId: ChainId, + nativeDetails: WormholeTokenDetails, +): WrappedTokenInfo | undefined => { + if (sourceChainId === nativeDetails.chainId) { + return undefined; + } + const nativeEcosystem = findOrThrow( + ECOSYSTEM_LIST, + (ecosystem) => ecosystem.wormholeChainId === nativeDetails.chainId, + ); + return { + originAddress: formatWormholeAddress( + nativeEcosystem.protocol, + nativeDetails.address, + ), + originChainId: nativeDetails.chainId, + }; +}; From 72d94f4169c8223fa69c868c27f0c2f62a188bc5 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 21:18:13 +0200 Subject: [PATCH 11/24] feat(ui): Add Wormhole transfer hooks --- apps/ui/src/hooks/index.ts | 1 + apps/ui/src/hooks/wormhole/index.ts | 1 + .../wormhole/useTransferEvmToEvmMutation.ts | 141 ++++++++++++++++ .../useTransferEvmToSolanaMutation.ts | 155 ++++++++++++++++++ .../useTransferSolanaToEvmMutation.ts | 128 +++++++++++++++ .../src/hooks/wormhole/useWormholeTransfer.ts | 42 +++++ 6 files changed, 468 insertions(+) create mode 100644 apps/ui/src/hooks/wormhole/index.ts create mode 100644 apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts create mode 100644 apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts create mode 100644 apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts create mode 100644 apps/ui/src/hooks/wormhole/useWormholeTransfer.ts diff --git a/apps/ui/src/hooks/index.ts b/apps/ui/src/hooks/index.ts index 7059127ad..eeb156d4a 100644 --- a/apps/ui/src/hooks/index.ts +++ b/apps/ui/src/hooks/index.ts @@ -7,3 +7,4 @@ export * from "./solana"; export * from "./swim"; export * from "./utils"; export * from "./wallets"; +export * from "./wormhole"; diff --git a/apps/ui/src/hooks/wormhole/index.ts b/apps/ui/src/hooks/wormhole/index.ts new file mode 100644 index 000000000..aec868412 --- /dev/null +++ b/apps/ui/src/hooks/wormhole/index.ts @@ -0,0 +1 @@ +export * from "./useWormholeTransfer"; diff --git a/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts b/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts new file mode 100644 index 000000000..5323115a2 --- /dev/null +++ b/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts @@ -0,0 +1,141 @@ +import { + getEmitterAddressEth, + parseSequenceFromLogEth, +} from "@certusone/wormhole-sdk"; +import { isEvmEcosystemId } from "@swim-io/evm"; +import { findOrThrow, humanToAtomic } from "@swim-io/utils"; +import { useMutation } from "react-query"; +import shallow from "zustand/shallow.js"; + +import { ECOSYSTEM_LIST, Protocol, getWormholeRetries } from "../../config"; +import { selectConfig } from "../../core/selectors"; +import { useEnvironment } from "../../core/store"; +import type { WormholeTransfer } from "../../models"; +import { + formatWormholeAddress, + getSignedVaaWithRetry, + getWrappedTokenInfoFromNativeDetails, +} from "../../models"; +import { useWallets } from "../crossEcosystem"; +import { useGetEvmClient } from "../evm"; + +export const useTransferEvmToEvmMutation = () => { + const { chains, wormhole } = useEnvironment(selectConfig, shallow); + const getEvmClient = useGetEvmClient(); + const wallets = useWallets(); + + return useMutation( + async ({ + interactionId, + value, + sourceDetails, + targetDetails, + nativeDetails, + onTxResult, + }: WormholeTransfer) => { + if (!wormhole) { + throw new Error("No Wormhole RPC configured"); + } + + const [sourceEcosystem, targetEcosystem] = [ + sourceDetails.chainId, + targetDetails.chainId, + ].map((chainId) => + findOrThrow( + ECOSYSTEM_LIST, + (ecosystem) => ecosystem.wormholeChainId === chainId, + ), + ); + const sourceEcosystemId = sourceEcosystem.id; + if (!isEvmEcosystemId(sourceEcosystemId)) { + throw new Error("Invalid source chain"); + } + const targetEcosystemId = targetEcosystem.id; + if (!isEvmEcosystemId(targetEcosystemId)) { + throw new Error("Invalid target chain"); + } + const sourceChain = findOrThrow( + chains[Protocol.Evm], + (chain) => chain.ecosystem === sourceEcosystemId, + ); + const targetChain = findOrThrow( + chains[Protocol.Evm], + (chain) => chain.ecosystem === targetEcosystemId, + ); + + const evmWallet = wallets[sourceEcosystemId].wallet; + if (evmWallet === null) { + throw new Error("Missing EVM wallet"); + } + const evmWalletAddress = evmWallet.address; + if (evmWalletAddress === null) { + throw new Error("Missing EVM wallet address"); + } + + const sourceClient = getEvmClient(sourceEcosystemId); + const targetClient = getEvmClient(targetEcosystemId); + + await evmWallet.switchNetwork(sourceChain.chainId); + // Process transfer if transfer txId does not exist + const { approvalResponses, transferResponse } = + await sourceClient.initiateWormholeTransfer({ + atomicAmount: humanToAtomic(value, sourceDetails.decimals).toString(), + interactionId, + sourceAddress: sourceDetails.address, + targetAddress: formatWormholeAddress(Protocol.Evm, evmWalletAddress), + targetChainId: targetDetails.chainId, + wallet: evmWallet, + wrappedTokenInfo: getWrappedTokenInfoFromNativeDetails( + sourceDetails.chainId, + nativeDetails, + ), + }); + + approvalResponses.forEach((response) => + onTxResult({ + chainId: sourceDetails.chainId, + txId: response.hash, + }), + ); + + const transferTxReceipt = await sourceClient.getTxReceiptOrThrow( + transferResponse, + ); + onTxResult({ + chainId: sourceDetails.chainId, + txId: transferTxReceipt.transactionHash, + }); + const sequence = parseSequenceFromLogEth( + transferTxReceipt, + sourceChain.wormhole.bridge, + ); + const retries = getWormholeRetries(sourceDetails.chainId); + const { vaaBytes: vaa } = await getSignedVaaWithRetry( + [...wormhole.rpcUrls], + sourceDetails.chainId, + getEmitterAddressEth(sourceChain.wormhole.portal), + sequence, + undefined, + undefined, + retries, + ); + + await evmWallet.switchNetwork(targetChain.chainId); + const redeemResponse = await targetClient.completeWormholeTransfer({ + interactionId, + vaa, + wallet: evmWallet, + }); + if (redeemResponse === null) { + throw new Error( + `Transaction not found: (unlock/mint on ${targetEcosystemId})`, + ); + } + const evmReceipt = await targetClient.getTxReceiptOrThrow(redeemResponse); + onTxResult({ + chainId: targetDetails.chainId, + txId: evmReceipt.transactionHash, + }); + }, + ); +}; diff --git a/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts b/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts new file mode 100644 index 000000000..1aaa05e7f --- /dev/null +++ b/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts @@ -0,0 +1,155 @@ +import { + getEmitterAddressEth, + parseSequenceFromLogEth, +} from "@certusone/wormhole-sdk"; +import { Keypair } from "@solana/web3.js"; +import { isEvmEcosystemId } from "@swim-io/evm"; +import { SOLANA_ECOSYSTEM_ID, solana } from "@swim-io/solana"; +import { findOrThrow, humanToAtomic } from "@swim-io/utils"; +import { WormholeChainId } from "@swim-io/wormhole"; +import { useMutation, useQueryClient } from "react-query"; +import shallow from "zustand/shallow.js"; + +import { ECOSYSTEM_LIST, Protocol, getWormholeRetries } from "../../config"; +import { selectConfig } from "../../core/selectors"; +import { useEnvironment } from "../../core/store"; +import type { WormholeTransfer } from "../../models"; +import { + findOrCreateSplTokenAccount, + formatWormholeAddress, + getSignedVaaWithRetry, + getWrappedTokenInfoFromNativeDetails, +} from "../../models"; +import { useWallets } from "../crossEcosystem"; +import { useGetEvmClient } from "../evm"; +import { useSolanaClient, useSplTokenAccountsQuery } from "../solana"; + +export const useTransferEvmToSolanaMutation = () => { + const queryClient = useQueryClient(); + const { env } = useEnvironment(); + const { chains, wormhole } = useEnvironment(selectConfig, shallow); + const getEvmClient = useGetEvmClient(); + const solanaClient = useSolanaClient(); + const wallets = useWallets(); + const solanaWallet = wallets[SOLANA_ECOSYSTEM_ID].wallet; + const { data: splTokenAccounts = [] } = useSplTokenAccountsQuery(); + + return useMutation( + async ({ + interactionId, + value, + sourceDetails, + targetDetails, + nativeDetails, + onTxResult, + }: WormholeTransfer) => { + if (!wormhole) { + throw new Error("No Wormhole RPC configured"); + } + if (!solanaWallet) { + throw new Error("No Solana wallet"); + } + if (targetDetails.chainId !== WormholeChainId.Solana) { + throw new Error("Invalid target chain"); + } + + const evmEcosystem = findOrThrow( + ECOSYSTEM_LIST, + (ecosystem) => ecosystem.wormholeChainId === sourceDetails.chainId, + ); + const evmEcosystemId = evmEcosystem.id; + if (!isEvmEcosystemId(evmEcosystemId)) { + throw new Error("Invalid EVM chain"); + } + const evmChain = findOrThrow( + chains[Protocol.Evm], + ({ ecosystem }) => ecosystem === evmEcosystemId, + ); + const evmClient = getEvmClient(evmEcosystemId); + const evmWallet = wallets[evmEcosystemId].wallet; + if (!evmWallet) { + throw new Error("Missing EVM wallet"); + } + + const { tokenAccount, creationTxId } = await findOrCreateSplTokenAccount({ + env, + solanaClient, + wallet: solanaWallet, + queryClient, + splTokenMintAddress: targetDetails.address, + splTokenAccounts, + }); + const splTokenAccountAddress = tokenAccount.address.toBase58(); + if (creationTxId) { + onTxResult({ + chainId: targetDetails.chainId, + txId: creationTxId, + }); + } + + await evmWallet.switchNetwork(evmChain.chainId); + // Process transfer if transfer txId does not exist + const { approvalResponses, transferResponse } = + await evmClient.initiateWormholeTransfer({ + atomicAmount: humanToAtomic(value, sourceDetails.decimals).toString(), + interactionId, + sourceAddress: sourceDetails.address, + targetAddress: formatWormholeAddress( + Protocol.Solana, + splTokenAccountAddress, + ), + targetChainId: solana.wormholeChainId, + wallet: evmWallet, + wrappedTokenInfo: getWrappedTokenInfoFromNativeDetails( + sourceDetails.chainId, + nativeDetails, + ), + }); + + approvalResponses.forEach((response) => + onTxResult({ + chainId: sourceDetails.chainId, + txId: response.hash, + }), + ); + + const transferTxReceipt = await evmClient.getTxReceiptOrThrow( + transferResponse, + ); + onTxResult({ + chainId: sourceDetails.chainId, + txId: transferTxReceipt.transactionHash, + }); + const sequence = parseSequenceFromLogEth( + transferTxReceipt, + evmChain.wormhole.bridge, + ); + + const auxiliarySigner = Keypair.generate(); + const retries = getWormholeRetries(evmEcosystem.wormholeChainId); + const { vaaBytes: vaa } = await getSignedVaaWithRetry( + [...wormhole.rpcUrls], + evmEcosystem.wormholeChainId, + getEmitterAddressEth(evmChain.wormhole.portal), + sequence, + undefined, + undefined, + retries, + ); + const unlockSplTokenTxIdsGenerator = + solanaClient.generateCompleteWormholeTransferTxIds({ + interactionId, + vaa, + wallet: solanaWallet, + auxiliarySigner, + }); + + for await (const txId of unlockSplTokenTxIdsGenerator) { + onTxResult({ + chainId: targetDetails.chainId, + txId, + }); + } + }, + ); +}; diff --git a/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts b/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts new file mode 100644 index 000000000..87f4d8e70 --- /dev/null +++ b/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts @@ -0,0 +1,128 @@ +import { getEmitterAddressSolana } from "@certusone/wormhole-sdk"; +import { Keypair } from "@solana/web3.js"; +import { isEvmEcosystemId } from "@swim-io/evm"; +import { + SOLANA_ECOSYSTEM_ID, + parseSequenceFromLogSolana, + solana, +} from "@swim-io/solana"; +import { findOrThrow, humanToAtomic } from "@swim-io/utils"; +import { useMutation } from "react-query"; +import shallow from "zustand/shallow.js"; + +import { ECOSYSTEM_LIST, Protocol, getWormholeRetries } from "../../config"; +import { selectConfig } from "../../core/selectors"; +import { useEnvironment } from "../../core/store"; +import type { WormholeTransfer } from "../../models"; +import { + formatWormholeAddress, + getSignedVaaWithRetry, + getWrappedTokenInfoFromNativeDetails, +} from "../../models"; +import { useWallets } from "../crossEcosystem"; +import { useGetEvmClient } from "../evm"; +import { useSolanaClient } from "../solana"; + +export const useTransferSolanaToEvmMutation = () => { + const { chains, wormhole } = useEnvironment(selectConfig, shallow); + const [solanaChain] = chains[Protocol.Solana]; + const getEvmClient = useGetEvmClient(); + const solanaClient = useSolanaClient(); + const wallets = useWallets(); + const solanaWallet = wallets[SOLANA_ECOSYSTEM_ID].wallet; + + return useMutation( + async ({ + interactionId, + value, + sourceDetails, + targetDetails, + nativeDetails, + onTxResult, + }: WormholeTransfer) => { + if (!wormhole) { + throw new Error("No Wormhole RPC configured"); + } + if (!solanaWallet) { + throw new Error("No Solana wallet"); + } + const solanaWalletAddress = solanaWallet.address ?? null; + if (!solanaWalletAddress) { + throw new Error("No Solana wallet address"); + } + + const evmEcosystem = findOrThrow( + ECOSYSTEM_LIST, + (ecosystem) => ecosystem.wormholeChainId === targetDetails.chainId, + ); + const evmEcosystemId = evmEcosystem.id; + if (!isEvmEcosystemId(evmEcosystemId)) { + throw new Error("Invalid EVM chain"); + } + const evmChain = findOrThrow( + chains[Protocol.Evm], + ({ ecosystem }) => ecosystem === evmEcosystemId, + ); + const evmClient = getEvmClient(evmEcosystemId); + const evmWallet = wallets[evmEcosystemId].wallet; + if (!evmWallet) { + throw new Error("No EVM wallet"); + } + const evmWalletAddress = evmWallet.address; + if (evmWalletAddress === null) { + throw new Error("No EVM wallet address"); + } + + const auxiliarySigner = Keypair.generate(); + const transferSplTokenTxId = await solanaClient.initiateWormholeTransfer({ + atomicAmount: humanToAtomic(value, sourceDetails.decimals).toString(), + interactionId, + sourceAddress: sourceDetails.address, + targetAddress: formatWormholeAddress(Protocol.Evm, evmWalletAddress), + targetChainId: evmEcosystem.wormholeChainId, + wallet: solanaWallet, + auxiliarySigner, + wrappedTokenInfo: getWrappedTokenInfoFromNativeDetails( + sourceDetails.chainId, + nativeDetails, + ), + }); + onTxResult({ + chainId: sourceDetails.chainId, + txId: transferSplTokenTxId, + }); + + const parsedTx = await solanaClient.getParsedTx(transferSplTokenTxId); + const sequence = parseSequenceFromLogSolana(parsedTx); + const emitterAddress = await getEmitterAddressSolana( + solanaChain.wormhole.portal, + ); + const retries = getWormholeRetries(solana.wormholeChainId); + const { vaaBytes: vaa } = await getSignedVaaWithRetry( + [...wormhole.rpcUrls], + sourceDetails.chainId, + emitterAddress, + sequence, + undefined, + undefined, + retries, + ); + await evmWallet.switchNetwork(evmChain.chainId); + const redeemResponse = await evmClient.completeWormholeTransfer({ + interactionId, + vaa, + wallet: evmWallet, + }); + if (redeemResponse === null) { + throw new Error( + `Transaction not found: (unlock/mint on ${evmChain.ecosystem})`, + ); + } + const evmReceipt = await evmClient.getTxReceiptOrThrow(redeemResponse); + onTxResult({ + chainId: targetDetails.chainId, + txId: evmReceipt.transactionHash, + }); + }, + ); +}; diff --git a/apps/ui/src/hooks/wormhole/useWormholeTransfer.ts b/apps/ui/src/hooks/wormhole/useWormholeTransfer.ts new file mode 100644 index 000000000..adedceaa3 --- /dev/null +++ b/apps/ui/src/hooks/wormhole/useWormholeTransfer.ts @@ -0,0 +1,42 @@ +import { CHAIN_ID_SOLANA, isEVMChain } from "@certusone/wormhole-sdk"; +import { useMutation } from "react-query"; + +import type { WormholeTransfer } from "../../models"; + +import { useTransferEvmToEvmMutation } from "./useTransferEvmToEvmMutation"; +import { useTransferEvmToSolanaMutation } from "./useTransferEvmToSolanaMutation"; +import { useTransferSolanaToEvmMutation } from "./useTransferSolanaToEvmMutation"; + +export const useWormholeTransfer = () => { + const { mutateAsync: transferEvmToEvm } = useTransferEvmToEvmMutation(); + const { mutateAsync: transferEvmToSolana } = useTransferEvmToSolanaMutation(); + const { mutateAsync: transferSolanaToEvm } = useTransferSolanaToEvmMutation(); + + return useMutation(async (transfer: WormholeTransfer) => { + const { + sourceDetails: { chainId: sourceChainId }, + targetDetails: { chainId: targetChainId }, + } = transfer; + if (sourceChainId === targetChainId) { + throw new Error("Source and target chains are the same"); + } + + if (sourceChainId === CHAIN_ID_SOLANA) { + if (isEVMChain(targetChainId)) { + return await transferSolanaToEvm(transfer); + } + throw new Error(`Transfer from Solana to ${targetChainId} not supported`); + } + if (isEVMChain(sourceChainId)) { + if (targetChainId === CHAIN_ID_SOLANA) { + return await transferEvmToSolana(transfer); + } + if (isEVMChain(targetChainId)) { + return await transferEvmToEvm(transfer); + } + throw new Error( + `Transfer from ${sourceChainId} to ${targetChainId} not supported`, + ); + } + }); +}; From be1352cf304bebf4bab6d177fc56545441d39fa5 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 21:18:27 +0200 Subject: [PATCH 12/24] feat(ui): Add basic Wormhole form --- apps/ui/src/components/WormholeForm.tsx | 232 ++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 apps/ui/src/components/WormholeForm.tsx diff --git a/apps/ui/src/components/WormholeForm.tsx b/apps/ui/src/components/WormholeForm.tsx new file mode 100644 index 000000000..b036e04fa --- /dev/null +++ b/apps/ui/src/components/WormholeForm.tsx @@ -0,0 +1,232 @@ +import type { ChainId } from "@certusone/wormhole-sdk"; +import { CHAIN_ID_TO_NAME } from "@certusone/wormhole-sdk"; +import type { EuiSelectOption } from "@elastic/eui"; +import { + EuiButton, + EuiForm, + EuiFormRow, + EuiSelect, + EuiSpacer, +} from "@elastic/eui"; +import { findOrThrow } from "@swim-io/utils"; +import Decimal from "decimal.js"; +import type { ReactElement } from "react"; +import { useEffect, useMemo, useState } from "react"; + +import { wormholeTokens as rawWormholeTokens } from "../config"; +import { useWormholeTransfer } from "../hooks"; +import type { TxResult, WormholeToken, WormholeTokenDetails } from "../models"; +import { generateId } from "../models"; + +import { EuiFieldIntlNumber } from "./EuiFieldIntlNumber"; + +const getDetailsByChainId = ( + token: WormholeToken, + chainId: ChainId, +): WormholeTokenDetails => + findOrThrow( + [token.nativeDetails, ...token.wrappedDetails], + (details) => details.chainId === chainId, + ); + +export const WormholeForm = (): ReactElement => { + const wormholeTokens = rawWormholeTokens as readonly WormholeToken[]; + const [currentTokenSymbol, setCurrentTokenSymbol] = useState( + wormholeTokens[0].symbol, + ); + const currentToken = findOrThrow( + wormholeTokens, + (token) => token.symbol === currentTokenSymbol, + ); + const tokenOptions: readonly EuiSelectOption[] = wormholeTokens.map( + (token) => ({ + value: token.symbol, + text: `${token.displayName} (${token.symbol})`, + selected: token.symbol === currentTokenSymbol, + }), + ); + + const sourceChains = useMemo( + () => [ + currentToken.nativeDetails.chainId, + ...currentToken.wrappedDetails.map(({ chainId }) => chainId), + ], + [currentToken], + ); + const [sourceChainId, setSourceChainId] = useState(sourceChains[0]); + const sourceChainOptions = sourceChains.map((chainId) => ({ + value: chainId, + text: CHAIN_ID_TO_NAME[chainId], + selected: chainId === sourceChainId, + })); + + const targetChains = useMemo( + () => sourceChains.filter((option) => option !== sourceChainId), + [sourceChains, sourceChainId], + ); + const [targetChainId, setTargetChainId] = useState(targetChains[0]); + const targetChainOptions = targetChains.map((chainId) => ({ + value: chainId, + text: CHAIN_ID_TO_NAME[chainId], + selected: chainId === targetChainId, + })); + + const [formInputAmount, setFormInputAmount] = useState(""); + const [inputAmount, setInputAmount] = useState(new Decimal(0)); + + const [txResults, setTxResults] = useState([]); + + const { mutateAsync: transfer, isLoading } = useWormholeTransfer(); + + const handleTxResult = (txResult: TxResult): void => { + setTxResults((previousResults) => [...previousResults, txResult]); + }; + + const handleSubmit = () => { + (async (): Promise => { + setTxResults([]); + const sourceDetails = getDetailsByChainId(currentToken, sourceChainId); + const targetDetails = getDetailsByChainId(currentToken, targetChainId); + await transfer({ + interactionId: generateId(), + value: inputAmount, + sourceDetails, + targetDetails, + nativeDetails: currentToken.nativeDetails, + onTxResult: handleTxResult, + }); + })().catch(console.error); + }; + + useEffect(() => { + setSourceChainId(sourceChains[0]); + }, [sourceChains]); + + useEffect(() => { + if (targetChainId === sourceChainId) { + setTargetChainId(targetChains[0]); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [targetChains]); + + return ( + + {/* These tables are only to show what data is available */} + + + + + + + + + + {currentToken.logo && ( + + + + + )} + + + + + + + + + + + + +
{"Symbol"}{currentToken.symbol}
{"Name"}{currentToken.displayName}
{"Logo"} + {currentToken.displayName} +
{"Source Chain"}{sourceChainId}
{"Target Chain"}{targetChainId}
{"Loading?"}{isLoading.toString()}
+ {txResults.length > 0 && ( + <> +

Tx results

+ + + + + + {txResults.map(({ chainId, txId }) => ( + + + + + ))} +
Chain IDTx ID
{chainId}{txId}
+ + )} + + + + + { + setCurrentTokenSymbol(event.target.value); + }} + /> + + + + + + { + const newSourceChainId = parseInt( + event.target.value, + 10, + ) as ChainId; + setSourceChainId(newSourceChainId); + }} + /> + + + + + + { + const newTargetChainId = parseInt( + event.target.value, + 10, + ) as ChainId; + setTargetChainId(newTargetChainId); + }} + /> + + + + + + { + setInputAmount(new Decimal(formInputAmount)); + }} + /> + + + + + + + {"Transfer"} + + +
+ ); +}; From d7a3e4afa71114161f785691d5df4cf8c608d5ed Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 13 Oct 2022 21:18:39 +0200 Subject: [PATCH 13/24] feat(ui): Add Wormhole page --- apps/ui/src/App.tsx | 2 ++ apps/ui/src/pages/WormholePage.scss | 10 ++++++++ apps/ui/src/pages/WormholePage.tsx | 38 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 apps/ui/src/pages/WormholePage.scss create mode 100644 apps/ui/src/pages/WormholePage.tsx diff --git a/apps/ui/src/App.tsx b/apps/ui/src/App.tsx index 9f4b05fcd..fde766901 100644 --- a/apps/ui/src/App.tsx +++ b/apps/ui/src/App.tsx @@ -23,6 +23,7 @@ import StakePage from "./pages/StakePage"; import SwapPage from "./pages/SwapPage"; import SwapPageV2 from "./pages/SwapPageV2"; import TosPage from "./pages/TosPage"; +import WormholePage from "./pages/WormholePage"; function App(): ReactElement { return ( @@ -64,6 +65,7 @@ function App(): ReactElement { {process.env.REACT_APP_ENABLE_POOL_RESTRUCTURE && ( } /> )} + } /> } /> } /> } /> diff --git a/apps/ui/src/pages/WormholePage.scss b/apps/ui/src/pages/WormholePage.scss new file mode 100644 index 000000000..010e88b94 --- /dev/null +++ b/apps/ui/src/pages/WormholePage.scss @@ -0,0 +1,10 @@ +.wormholeForm { + width: 500px; + transition: all 0.5s ease; +} + +@media (min-width: 768px) { + .wormholeForm { + min-width: 460px; + } +} diff --git a/apps/ui/src/pages/WormholePage.tsx b/apps/ui/src/pages/WormholePage.tsx new file mode 100644 index 000000000..3d12a9f16 --- /dev/null +++ b/apps/ui/src/pages/WormholePage.tsx @@ -0,0 +1,38 @@ +import { + EuiPage, + EuiPageBody, + EuiPageContent, + EuiPageContentBody, + EuiSpacer, + EuiTitle, +} from "@elastic/eui"; +import type { ReactElement } from "react"; +import { useTranslation } from "react-i18next"; + +import { WormholeForm } from "../components/WormholeForm"; +import { useTitle } from "../hooks"; + +import "./WormholePage.scss"; + +const WormholePage = (): ReactElement => { + const { t } = useTranslation(); + useTitle(t("nav.wormhole")); + + return ( + + + + + +

{"Wormhole"}

+
+ + +
+
+
+
+ ); +}; + +export default WormholePage; From b27d22e3457d18fa1395bfb311793d11346a8794 Mon Sep 17 00:00:00 2001 From: wormat Date: Fri, 14 Oct 2022 16:40:43 +0200 Subject: [PATCH 14/24] chore(ui): Add npm script for Wormhole token scraper --- apps/ui/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/ui/package.json b/apps/ui/package.json index 8c9b1eeff..d23fc67e8 100644 --- a/apps/ui/package.json +++ b/apps/ui/package.json @@ -3,6 +3,7 @@ "private": true, "version": "0.1.0", "scripts": { + "scrape-wormhole-tokens": "./scripts/scrapeWormholeTokenData.sh", "start": "NODE_ENV=development SKIP_PREFLIGHT_CHECK=true DISABLE_ESLINT_PLUGIN=true craco start", "build": "SKIP_PREFLIGHT_CHECK=true DISABLE_ESLINT_PLUGIN=true craco build", "release": "SENTRY_RELEASE=$(git rev-parse --short HEAD) yarn workspaces foreach --topological-dev --parallel --recursive --from @swim-io/ui run build", From b7e126db1de279ac5fc8e063e32b917bb24ca023 Mon Sep 17 00:00:00 2001 From: wormat Date: Fri, 14 Oct 2022 16:46:41 +0200 Subject: [PATCH 15/24] feat(ui): Restrict Wormhole tokens to min 2 Solana/EVM chains --- apps/ui/scripts/processWormholeTokenData.ts | 26 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/apps/ui/scripts/processWormholeTokenData.ts b/apps/ui/scripts/processWormholeTokenData.ts index 132d86f27..e9c8d09f5 100644 --- a/apps/ui/scripts/processWormholeTokenData.ts +++ b/apps/ui/scripts/processWormholeTokenData.ts @@ -1,4 +1,4 @@ -import { CHAINS, ChainId } from "@certusone/wormhole-sdk"; +import { CHAINS, ChainId, isEVMChain } from "@certusone/wormhole-sdk"; import fs from "fs"; import { parse } from "csv-parse"; @@ -103,10 +103,26 @@ const sourceToChainId: Record = { terra2: CHAINS.terra2, }; +const isChainSupported = (chainId: ChainId): boolean => + chainId === CHAINS.solana || isEVMChain(chainId); + +const supportedSourceToChainId = Object.entries(sourceToChainId).reduce< + Partial> +>( + (accumulator, [source, chainId]) => + isChainSupported(chainId) + ? { + ...accumulator, + [source]: chainId, + } + : accumulator, + {}, +); + const processWrappedDetails = ( wrappedDetails: WrappedDetails, ): readonly WormholeTokenDetails[] => - Object.entries(sourceToChainId).reduce( + Object.entries(supportedSourceToChainId).reduce( (accumulator: readonly WormholeTokenDetails[], [source, chainId]) => { const address: string = wrappedDetails[`${source}Address` as keyof WrappedDetails]; @@ -162,7 +178,11 @@ const main = async () => { for await (const record of parser) { const processedRecord = processRecord(record); - if (Object.keys(processedRecord.wrappedDetails).length > 0) { + const supportedChains = [ + processedRecord.nativeDetails, + ...processedRecord.wrappedDetails, + ].filter((details) => isChainSupported(details.chainId)); + if (supportedChains.length >= 2) { processedRecords.push(processedRecord); } } From 60d4c4ccc8822d1dc45e74a91abc2f97018513ee Mon Sep 17 00:00:00 2001 From: wormat Date: Fri, 14 Oct 2022 16:48:11 +0200 Subject: [PATCH 16/24] chore(ui): Update Wormhole token list --- apps/ui/src/config/wormholeTokens.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ui/src/config/wormholeTokens.json b/apps/ui/src/config/wormholeTokens.json index 520368be5..208961037 100644 --- a/apps/ui/src/config/wormholeTokens.json +++ b/apps/ui/src/config/wormholeTokens.json @@ -1 +1 @@ -[{"symbol":"RAY","displayName":"Raydium (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R/logo.png","coinGeckoId":"raydium","nativeDetails":{"chainId":1,"address":"4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0xE617dd80c621a5072bD8cBa65E9d76c07327004d","decimals":6},{"chainId":4,"address":"0x13b6A55662f6591f8B8408Af1C73B017E32eEdB8","decimals":6},{"chainId":3,"address":"terra1ht5sepn28z999jx33sdduuxm9acthad507jg9q","decimals":6}]},{"symbol":"SBR","displayName":"Saber (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1/logo.svg","coinGeckoId":"saber","nativeDetails":{"chainId":1,"address":"Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1","decimals":6},"wrappedDetails":[{"chainId":4,"address":"0x75344E5693ed5ecAdF4f292fFeb866c2cF8afCF1","decimals":6},{"chainId":3,"address":"terra17h82zsq6q8x5tsgm5ugcx4gytw3axguvzt4pkc","decimals":6}]},{"symbol":"SOL","displayName":"SOL (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png","coinGeckoId":"solana","nativeDetails":{"chainId":1,"address":"So11111111111111111111111111111111111111112","decimals":9},"wrappedDetails":[{"chainId":2,"address":"0xD31a59c85aE9D8edEFeC411D448f90841571b89c","decimals":9},{"chainId":4,"address":"0xfA54fF1a158B5189Ebba6ae130CEd6bbd3aEA76e","decimals":9},{"chainId":3,"address":"terra190tqwgqx7s8qrknz6kckct7v607cu068gfujpk","decimals":8},{"chainId":5,"address":"0xd93f7e271cb87c23aaa73edc008a79646d1f9912","decimals":9},{"chainId":6,"address":"0xFE6B19286885a4F7F55AdAD09C3Cd1f906D2478F","decimals":9},{"chainId":7,"address":"0xd17dDAC91670274F7ba1590a06EcA0f2FD2b12bc","decimals":9},{"chainId":10,"address":"0xd99021C2A33e4Cf243010539c9e9b7c52E0236c1","decimals":9}]},{"symbol":"SRMso","displayName":"Serum (Portal from Solana)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png","coinGeckoId":"serum","nativeDetails":{"chainId":1,"address":"SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0xE3ADAA4fb7c92AB833Ee08B3561D9c434aA2A3eE","decimals":6},{"chainId":4,"address":"0x12BeffdCEcb547640DC30e1495E4B9cdc21922b4","decimals":6},{"chainId":3,"address":"terra1dkam9wd5yvaswv4yq3n2aqd4wm5j8n82qc0c7c","decimals":6}]},{"symbol":"USDCso","displayName":"USD Coin (Portal from Solana)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":1,"address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0x41f7B8b9b897276b7AAE926a9016935280b44E97","decimals":6},{"chainId":4,"address":"0x91Ca579B0D47E5cfD5D0862c21D5659d39C8eCf0","decimals":6},{"chainId":3,"address":"terra1e6mq63y64zcxz8xyu5van4tgkhemj3r86yvgu4","decimals":6},{"chainId":5,"address":"0x576cf361711cd940cd9c397bb98c4c896cbd38de","decimals":6},{"chainId":6,"address":"0x0950Fc1AD509358dAeaD5eB8020a3c7d8b43b9DA","decimals":6},{"chainId":7,"address":"0x1d1149a53deB36F2836Ae7877c9176413aDfA4A8","decimals":6},{"chainId":10,"address":"0xb8398DA4FB3BC4306B9D9d9d13d9573e7d0E299f","decimals":6},{"chainId":9,"address":"0xDd1DaFedeBa5F9851C4F4a2876E0f3aF3c774B1A","decimals":6}]},{"symbol":"USDTso","displayName":"Tether USD (Portal from Solana)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg","coinGeckoId":"tether","nativeDetails":{"chainId":1,"address":"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0x1CDD2EaB61112697626F7b4bB0e23Da4FeBF7B7C","decimals":6},{"chainId":4,"address":"0x49d5cC521F75e13fa8eb4E89E9D381352C897c96","decimals":6},{"chainId":3,"address":"terra1hd9n65snaluvf7en0p4hqzse9eqecejz2k8rl5","decimals":6},{"chainId":5,"address":"0x3553f861dec0257bada9f8ed268bf0d74e45e89c","decimals":6},{"chainId":6,"address":"0xF0FF231e3F1A50F83136717f287ADAB862f89431","decimals":6},{"chainId":7,"address":"0x24285C5232ce3858F00bacb950Cae1f59d1b2704","decimals":6},{"chainId":9,"address":"0xd80890AFDBd7148456D8Ee358eF9127F0F8c7faf","decimals":6}]},{"symbol":"XTAG","displayName":"XTAG Token (Portal)","logo":"https://raw.githubusercontent.com/sudomon/wormhole-token-list/main/src/logogen/base/xtag.png","coinGeckoId":"xhashtag","nativeDetails":{"chainId":1,"address":"5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp","decimals":6},"wrappedDetails":[{"chainId":6,"address":"0xa608d79c5f695c0d4c0e773a4938b57e18e0fc57","decimals":6}]},{"symbol":"ZBC","displayName":"Zebec Protocol","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF/logo.png","coinGeckoId":"zebec-protocol","nativeDetails":{"chainId":1,"address":"zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF","decimals":9},"wrappedDetails":[{"chainId":4,"address":"0x6D1054C3102E842314e250b9e9C4Be327b8DaaE2","decimals":9}]},{"symbol":"mSOL","displayName":"Marinade staked SOL (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So/logo.png","coinGeckoId":"marinade-staked-sol","nativeDetails":{"chainId":1,"address":"mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So","decimals":9},"wrappedDetails":[{"chainId":2,"address":"0x756bFb452cFE36A5Bc82e4F5f4261A89a18c242b","decimals":9},{"chainId":3,"address":"terra1qvlpf2v0zmru3gtex40sqq02wxp39x3cjh359y","decimals":8},{"chainId":7,"address":"0x5E11A4f64D3B9fA042dB9e1AA918F735038FdfD8","decimals":9}]},{"symbol":"1INCH","displayName":"1INCH Token (Portal)","logo":"","coinGeckoId":"1inch","nativeDetails":{"chainId":2,"address":"0x111111111117dC0aa78b770fA6A738034120C302","decimals":18},"wrappedDetails":[{"chainId":1,"address":"AjkPkq3nsyDe1yKcbyZT7N4aK4Evv9om9tzhQD3wsRC","decimals":8}]},{"symbol":"1SOL","displayName":"1sol.io (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF/logo.png","coinGeckoId":"1sol","nativeDetails":{"chainId":2,"address":"0x009178997aff09a67d4caccfeb897fb79d036214","decimals":18},"wrappedDetails":[{"chainId":1,"address":"4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF","decimals":8}]},{"symbol":"AAVE","displayName":"Aave Token (Portal)","logo":"","coinGeckoId":"aave","nativeDetails":{"chainId":2,"address":"0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3vAs4D1WE6Na4tCgt4BApgFfENbm8WY7q4cSPD1yM4Cg","decimals":8}]},{"symbol":"AKRO","displayName":"Akropolis (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/G3h8NZgJozk9crme2me6sKDJuSQ12mNCtvC9NbSWqGuk/logo.png","coinGeckoId":"akropolis","nativeDetails":{"chainId":2,"address":"0x8ab7404063ec4dbcfd4598215992dc3f8ec853d7","decimals":18},"wrappedDetails":[{"chainId":1,"address":"12uHjozDVgyGWeLqQ8DMCRbig8amW5VmvZu3FdMMdcaG","decimals":8}]},{"symbol":"ALEPH","displayName":"Aleph.im (Portal)","logo":"","coinGeckoId":"aleph-im","nativeDetails":{"chainId":2,"address":"0x27702a26126e0b3702af63ee09ac4d1a084ef628","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3UCMiSnkcnkPE1pgQ5ggPCBv6dXgVUy16TmMUe1WpG9x","decimals":8}]},{"symbol":"ALICE","displayName":"My Neighbor Alice (Portal)","logo":"","coinGeckoId":"my-neighbor-alice","nativeDetails":{"chainId":2,"address":"0xac51066d7bec65dc4589368da368b212745d63e8","decimals":6},"wrappedDetails":[{"chainId":1,"address":"9ARQsBfAn65q522cEqSJuse3cLhA31jgWDBGQHeiq7Mg","decimals":8}]},{"symbol":"AMP","displayName":"Amp (Portal)","logo":"","coinGeckoId":"amp","nativeDetails":{"chainId":2,"address":"0xff20817765cb7f73d4bde2e66e067e58d11095c2","decimals":18},"wrappedDetails":[{"chainId":1,"address":"D559HwgjYGDYsXpmFUKxhFTEwutvS9sya1kXiyCVogCV","decimals":8}]},{"symbol":"AMPL","displayName":"Ampleforth (Portal)","logo":"","coinGeckoId":"ampleforth","nativeDetails":{"chainId":2,"address":"0xd46ba6d942050d489dbd938a2c909a5d5039a161","decimals":9},"wrappedDetails":[{"chainId":1,"address":"EHKQvJGu48ydKA4d3RivrkNyTJTkSdoS32UafxSX1yak","decimals":8}]},{"symbol":"ANKR","displayName":"Ankr (Portal)","logo":"","coinGeckoId":"ankr","nativeDetails":{"chainId":2,"address":"0x8290333cef9e6d528dd5618fb97a76f268f3edd4","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Gq2norJ1kBemBp3mPfkgAUMhMMmnFmY4zEyi26tRcxFB","decimals":8}]},{"symbol":"AUDIO","displayName":"Audius (Portal)","logo":"","coinGeckoId":"audius","nativeDetails":{"chainId":2,"address":"0x18aaa7115705e8be94bffebde57af9bfc265b998","decimals":18},"wrappedDetails":[{"chainId":1,"address":"9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM","decimals":8},{"chainId":3,"address":"terra1nc6flp57m5hsr6y5y8aexzszy43ksr0drdr8rp","decimals":8}]},{"symbol":"AXSet","displayName":"Axie Infinity Shard (Portal from Ethereum)","logo":"https://etherscan.io/token/images/axieinfinityshard_32.png","coinGeckoId":"axie-infinity","nativeDetails":{"chainId":2,"address":"0xbb0e17ef65f82ab018d8edd776e8dd940327b28b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HysWcbHiYY9888pHbaqhwLYZQeZrcQMXKQWRqS7zcPK5","decimals":8},{"chainId":4,"address":"0x556b60c53fbC1518Ad17E03d52E47368dD4d81B3","decimals":18}]},{"symbol":"BAT","displayName":"Basic Attention Token (Portal)","logo":"","coinGeckoId":"basic-attention-token","nativeDetails":{"chainId":2,"address":"0x0d8775f648430679a709e98d2b0cb6250d2887ef","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EPeUFDgHRxs9xxEPVaL6kfGQvCon7jmAWKVUHuux1Tpz","decimals":8},{"chainId":4,"address":"0x31C78f583ed0288D67b2b80Dc5C443Bc3b15C661","decimals":18},{"chainId":3,"address":"terra1apxgj5agkkfdm2tprwvykug0qtahxvfmugnhx2","decimals":8}]},{"symbol":"BNT","displayName":"Bancor Network Token (Portal)","logo":"","coinGeckoId":"bancor-network","nativeDetails":{"chainId":2,"address":"0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EDVVEYW4fPJ6vKw5LZXRGUSPzxoHrv6eWvTqhCr8oShs","decimals":8}]},{"symbol":"BUSDet","displayName":"Binance USD (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX/logo.png","coinGeckoId":"binance-usd","nativeDetails":{"chainId":2,"address":"0x4fabb145d64652a948d72533023f6e7a623c7c53","decimals":18},"wrappedDetails":[{"chainId":1,"address":"33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX","decimals":8},{"chainId":4,"address":"0x035de3679E692C471072d1A09bEb9298fBB2BD31","decimals":18}]},{"symbol":"CEL","displayName":"Celsius (Portal)","logo":"","coinGeckoId":"celsius-network","nativeDetails":{"chainId":2,"address":"0xaaaebe6fe48e54f431b0c390cfaf0b017d09d42d","decimals":4},"wrappedDetails":[{"chainId":1,"address":"nRtfwU9G82CSHhHGJNxFhtn7FLvWP2rqvQvje1WtL69","decimals":4}]},{"symbol":"CHZ","displayName":"Chiliz (Portal)","logo":"","coinGeckoId":"chiliz","nativeDetails":{"chainId":2,"address":"0x3506424f91fd33084466f402d5d97f05f8e3b4af","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5TtSKAamFq88grN1QGrEaZ1AjjyciqnCya1aiMhAgFvG","decimals":8}]},{"symbol":"COMP","displayName":"Compound (Portal)","logo":"","coinGeckoId":"compound","nativeDetails":{"chainId":2,"address":"0xc00e94cb662c3520282e6f5717214004a7f26888","decimals":18},"wrappedDetails":[{"chainId":1,"address":"AwEauVaTMQRB71WeDnwf1DWSBxaMKjEPuxyLr1uixFom","decimals":8}]},{"symbol":"CREAM","displayName":"Cream (Portal)","logo":"","coinGeckoId":"cream","nativeDetails":{"chainId":2,"address":"0x2ba592f78db6436527729929aaf6c908497cb200","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HihxL2iM6L6P1oqoSeiixdJ3PhPYNxvSKH9A2dDqLVDH","decimals":8}]},{"symbol":"CRO","displayName":"Crypto.com Coin (Portal)","logo":"","coinGeckoId":"crypto-com-coin","nativeDetails":{"chainId":2,"address":"0xa0b73e1ff0b80914ab6fe0444e65848c4c34450b","decimals":8},"wrappedDetails":[{"chainId":1,"address":"DvjMYMVeXgKxaixGKpzQThLoG98nc7HSU7eanzsdCboA","decimals":8}]},{"symbol":"CRV","displayName":"Curve DAO Token (Portal)","logo":"","coinGeckoId":"curve-dao-token","nativeDetails":{"chainId":2,"address":"0xd533a949740bb3306d119cc777fa900ba034cd52","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7gjNiPun3AzEazTZoFEjZgcBMeuaXdpjHq2raZTmTrfs","decimals":8}]},{"symbol":"CVX","displayName":"Convex Finance (Portal)","logo":"","coinGeckoId":"convex-finance","nativeDetails":{"chainId":2,"address":"0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"BLvmrccP4g1B6SpiVvmQrLUDya1nZ4B2D1nm9jzKF7sz","decimals":8}]},{"symbol":"DAI","displayName":"DAI (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png","coinGeckoId":"dai","nativeDetails":{"chainId":2,"address":"0x6b175474e89094c44da98b954eedeac495271d0f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o","decimals":8},{"chainId":4,"address":"0x3413a030EF81a3dD5a302F4B4D11d911e12ed337","decimals":18},{"chainId":3,"address":"terra1zmclyfepfmqvfqflu8r3lv6f75trmg05z7xq95","decimals":8}]},{"symbol":"DYDX","displayName":"dYdX (Portal)","logo":"https://etherscan.io/token/images/dydx2_32.png","coinGeckoId":"dydx","nativeDetails":{"chainId":2,"address":"0x92d6c1e31e14520e676a687f0a93788b716beff5","decimals":18},"wrappedDetails":[{"chainId":1,"address":"4Hx6Bj56eGyw8EJrrheM6LBQAvVYRikYCWsALeTrwyRU","decimals":8}]},{"symbol":"ELON","displayName":"Dogelon Mars (Portal)","logo":"","coinGeckoId":"dogelon-mars","nativeDetails":{"chainId":2,"address":"0x761d38e5ddf6ccf6cf7c55759d5210750b5d60f3","decimals":18},"wrappedDetails":[{"chainId":1,"address":"6nKUU36URHkewHg5GGGAgxs6szkE4VTioGUT5txQqJFU","decimals":8}]},{"symbol":"ENJ","displayName":"EnjinCoin (Portal)","logo":"","coinGeckoId":"enjin","nativeDetails":{"chainId":2,"address":"0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EXExWvT6VyYxEjFzF5BrUxt5GZMPVZnd48y3iWrRefMq","decimals":8}]},{"symbol":"ENS","displayName":"Ethereum Name Service (Portal)","logo":"","coinGeckoId":"ethereum-name-service","nativeDetails":{"chainId":2,"address":"0xc18360217d8f7ab5e7c516566761ea12ce7f9d72","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CLQsDGoGibdNPnVCFp8BAsN2unvyvb41Jd5USYwAnzAg","decimals":8}]},{"symbol":"ETH","displayName":"Ether (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs/logo.png","coinGeckoId":"ether","nativeDetails":{"chainId":2,"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs","decimals":8},{"chainId":4,"address":"0x4DB5a66E937A9F4473fA95b1cAF1d1E1D62E29EA","decimals":18},{"chainId":3,"address":"terra14tl83xcwqjy0ken9peu4pjjuu755lrry2uy25r","decimals":8},{"chainId":5,"address":"0x11CD37bb86F65419713f30673A480EA33c826872","decimals":18},{"chainId":6,"address":"0x8b82A291F83ca07Af22120ABa21632088fC92931","decimals":18},{"chainId":7,"address":"0x3223f17957Ba502cbe71401D55A0DB26E5F7c68F","decimals":18},{"chainId":9,"address":"0x811Cc0d762eA72aC72385d93b98a97263AE37E4C","decimals":18},{"chainId":14,"address":"0x66803FB87aBd4aaC3cbB3fAd7C3aa01f6F3FB207","decimals":18}]},{"symbol":"ETHIX","displayName":"Ethix (Portal)","logo":"https://raw.githubusercontent.com/ethichub/wormhole-token-list/main/src/logogen/base/ETHIX.png","coinGeckoId":"ethichub","nativeDetails":{"chainId":2,"address":"0xFd09911130e6930Bf87F2B0554c44F400bD80D3e","decimals":18},"wrappedDetails":[{"chainId":14,"address":"0x9995cc8F20Db5896943Afc8eE0ba463259c931ed","decimals":18}]},{"symbol":"FRAX","displayName":"Frax (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp/logo.png","coinGeckoId":"frax","nativeDetails":{"chainId":2,"address":"0x853d955acef822db058eb8505911ed77f175b99e","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp","decimals":8}]},{"symbol":"FRONT","displayName":"Frontier (Portal)","logo":"","coinGeckoId":"frontier","nativeDetails":{"chainId":2,"address":"0xf8c3527cc04340b208c854e985240c02f7b7793f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"A9ik2NrpKRRG2snyTjofZQcTuav9yH3mNVHLsLiDQmYt","decimals":8}]},{"symbol":"FTMet","displayName":"Fantom (Portal from Ethereum)","logo":"","coinGeckoId":"fantom","nativeDetails":{"chainId":2,"address":"0x4e15361fd6b4bb609fa63c81a2be19d873717870","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8gC27rQF4NEDYfyf5aS8ZmQJUum5gufowKGYRRba4ENN","decimals":8}]},{"symbol":"FTT","displayName":"FTX Token (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv/logo.png","coinGeckoId":"ftx-token","nativeDetails":{"chainId":2,"address":"0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv","decimals":8},{"chainId":4,"address":"0x49BA054B9664e99ac335667a917c63bB94332E84","decimals":18}]},{"symbol":"FXS","displayName":"Frax Share (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/6LX8BhMQ4Sy2otmAWj7Y5sKd9YTVVUgfMsBzT6B9W7ct/logo.png","coinGeckoId":"frax-share","nativeDetails":{"chainId":2,"address":"0x3432b6a60d23ca0dfca7761b7ab56459d9c964d0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"6LX8BhMQ4Sy2otmAWj7Y5sKd9YTVVUgfMsBzT6B9W7ct","decimals":8}]},{"symbol":"GALA","displayName":"Gala (Portal)","logo":"","coinGeckoId":"gala","nativeDetails":{"chainId":2,"address":"0x15d4c048f83bd7e37d49ea4c83a07267ec4203da","decimals":8},"wrappedDetails":[{"chainId":1,"address":"AuGz22orMknxQHTVGwAu7e3dJikTJKgcjFwMNDikEKmF","decimals":8}]},{"symbol":"GRT","displayName":"Graph Token (Portal)","logo":"","coinGeckoId":"the-graph","nativeDetails":{"chainId":2,"address":"0xc944E90C64B2c07662A292be6244BDf05Cda44a7","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HGsLG4PnZ28L8A4R5nPqKgZd86zUUdmfnkTRnuFJ5dAX","decimals":8}]},{"symbol":"GT","displayName":"GateToken (Portal)","logo":"","coinGeckoId":"gatetoken","nativeDetails":{"chainId":2,"address":"0xe66747a101bff2dba3697199dcce5b743b454759","decimals":18},"wrappedDetails":[{"chainId":1,"address":"ABAq2R9gSpDDGguQxBk4u13s4ZYW6zbwKVBx15mCMG8","decimals":8}]},{"symbol":"HBTC","displayName":"Huobi BTC (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8/logo.png","coinGeckoId":"huobi-btc","nativeDetails":{"chainId":2,"address":"0x0316eb71485b0ab14103307bf65a021042c6d380","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8","decimals":8}]},{"symbol":"HGET","displayName":"Hedget (Portal)","logo":"","coinGeckoId":"hedget","nativeDetails":{"chainId":2,"address":"0x7968bc6a03017ea2de509aaa816f163db0f35148","decimals":6},"wrappedDetails":[{"chainId":1,"address":"2ueY1bLcPHfuFzEJq7yN1V2Wrpu8nkun9xG2TVCE1mhD","decimals":8}]},{"symbol":"HUSD","displayName":"HUSD Stablecoin (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw/logo.png","coinGeckoId":"husd","nativeDetails":{"chainId":2,"address":"0xdf574c24545e5ffecb9a659c229253d4111d87e1","decimals":8},"wrappedDetails":[{"chainId":1,"address":"7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw","decimals":8}]},{"symbol":"HXRO","displayName":"Hxro (Portal)","logo":"","coinGeckoId":"hxro","nativeDetails":{"chainId":2,"address":"0x4bd70556ae3f8a6ec6c4080a0c327b24325438f3","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HxhWkVpk5NS4Ltg5nij2G671CKXFRKPK8vy271Ub4uEK","decimals":8}]},{"symbol":"ICE","displayName":"PopsicleToken (Portal)","logo":"","coinGeckoId":"popsicle-finance","nativeDetails":{"chainId":2,"address":"0xf16e81dce15b08f326220742020379b855b87df9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"DiJut4U3CU8b3bRgwfyqtJMJ4wjzJHaX6hudamjH46Km","decimals":8}]},{"symbol":"ILV","displayName":"Illuvium (Portal)","logo":"","coinGeckoId":"illuvium","nativeDetails":{"chainId":2,"address":"0x767fe9edc9e0df98e07454847909b5e959d7ca0e","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8UJbtpsEubDVkY53rk7d61hNYKkvouicczB2XmuwiG4g","decimals":8}]},{"symbol":"KEEP","displayName":"Keep Network (Portal)","logo":"","coinGeckoId":"keep-network","nativeDetails":{"chainId":2,"address":"0x85eee30c52b0b379b046fb0f85f4f3dc3009afec","decimals":18},"wrappedDetails":[{"chainId":1,"address":"64L6o4G2H7Ln1vN7AHZsUMW4pbFciHyuwn4wUdSbcFxh","decimals":8}]},{"symbol":"KP3R","displayName":"Keep3rV1 (Portal)","logo":"","coinGeckoId":"keep3rv1","nativeDetails":{"chainId":2,"address":"0x1ceb5cb57c4d4e2b2433641b95dd330a33185a44","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3a2VW9t5N6p4baMW3M6yLH1UJ9imMt7VsyUk6ouXPVLq","decimals":8}]},{"symbol":"LDO","displayName":"Lido DAO (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p/logo.png","coinGeckoId":"lido-dao","nativeDetails":{"chainId":2,"address":"0x5a98fcbea516cf06857215779fd812ca3bef1b32","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p","decimals":8},{"chainId":4,"address":"0x986854779804799C1d68867F5E03e601E781e41b","decimals":18},{"chainId":3,"address":"terra1jxypgnfa07j6w92wazzyskhreq2ey2a5crgt6z","decimals":8}]},{"symbol":"LINK","displayName":"Chainlink (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2wpTofQ8SkACrkZWrZDjXPitYa8AwWgX8AfxdeBRRVLX/logo.png","coinGeckoId":"chainlink","nativeDetails":{"chainId":2,"address":"0x514910771af9ca656af840dff83e8264ecf986ca","decimals":18},"wrappedDetails":[{"chainId":1,"address":"2wpTofQ8SkACrkZWrZDjXPitYa8AwWgX8AfxdeBRRVLX","decimals":8},{"chainId":3,"address":"terra12dfv3f0e6m22z6cnhfn3nxk2en3z3zeqy6ctym","decimals":8}]},{"symbol":"LRC","displayName":"Loopring (Portal)","logo":"","coinGeckoId":"loopring","nativeDetails":{"chainId":2,"address":"0xbbbbca6a901c926f240b89eacb641d8aec7aeafd","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HCTVFTzHL21a1dPzKxAUeWwqbE8QMUyvgChFDL4XYoi1","decimals":8}]},{"symbol":"LUA","displayName":"LuaSwap (Portal)","logo":"","coinGeckoId":"luaswap","nativeDetails":{"chainId":2,"address":"0xb1f66997a5760428d3a87d68b90bfe0ae64121cc","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5Wc4U1ZoQRzF4tPdqKQzBwRSjYe8vEf3EvZMuXgtKUW6","decimals":8}]},{"symbol":"MANA","displayName":"Decentraland (Portal)","logo":"https://assets.coingecko.com/coins/images/878/thumb/decentraland-mana.png","coinGeckoId":"decentraland","nativeDetails":{"chainId":2,"address":"0x0F5D2fB29fb7d3CFeE444a200298f468908cC942","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7dgHoN8wBZCc5wbnQ2C47TDnBMAxG4Q5L3KjP67z8kNi","decimals":8}]},{"symbol":"MATH","displayName":"MATH Token (Portal)","logo":"","coinGeckoId":"math","nativeDetails":{"chainId":2,"address":"0x08d967bb0134f2d07f7cfb6e246680c53927dd30","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CaGa7pddFXS65Gznqwp42kBhkJQdceoFVT7AQYo8Jr8Q","decimals":8}]},{"symbol":"MATICet","displayName":"MATIC (Portal from Ethereum)","logo":"","coinGeckoId":"polygon","nativeDetails":{"chainId":2,"address":"0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"C7NNPWuZCNjZBfW5p6JvGsR8pUdsRpEdP1ZAhnoDwj7h","decimals":8}]},{"symbol":"MIMet","displayName":"Magic Internet Money (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HRQke5DKdDo3jV7wnomyiM8AA3EzkVnxMDdo2FQ5XUe1/logo.png","coinGeckoId":"magic-internet-money","nativeDetails":{"chainId":2,"address":"0x99d8a9c45b2eca8864373a26d1459e3dff1e17f3","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HRQke5DKdDo3jV7wnomyiM8AA3EzkVnxMDdo2FQ5XUe1","decimals":8},{"chainId":3,"address":"terra15a9dr3a2a2lj5fclrw35xxg9yuxg0d908wpf2y","decimals":8}]},{"symbol":"NXM","displayName":"Nexus Mutual (Portal)","logo":"","coinGeckoId":"nexus-mutual","nativeDetails":{"chainId":2,"address":"0xd7c49cee7e9188cca6ad8ff264c1da2e69d4cf3b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Aqs5ydqKXEK2cjotDXxHmk8N9PknqQ5q4ZED4ymY1eeh","decimals":8}]},{"symbol":"ORION","displayName":"Orion Money (Portal)","logo":"https://assets.coingecko.com/coins/images/18630/small/YtrqPIWc.png","coinGeckoId":"orion-money","nativeDetails":{"chainId":2,"address":"0x727f064a78dc734d33eec18d5370aef32ffd46e4","decimals":18},"wrappedDetails":[{"chainId":4,"address":"0x3dcB18569425930954feb191122e574b87F66abd","decimals":18},{"chainId":3,"address":"terra1mddcdx0ujx89f38gu7zspk2r2ffdl5enyz2u03","decimals":8},{"chainId":5,"address":"0x5E0294Af1732498C77F8dB015a2d52a76298542B","decimals":18}]},{"symbol":"PAXG","displayName":"Paxos Gold (Portal)","logo":"","coinGeckoId":"pax-gold","nativeDetails":{"chainId":2,"address":"0x45804880de22913dafe09f4980848ece6ecbaf78","decimals":18},"wrappedDetails":[{"chainId":1,"address":"C6oFsE8nXRDThzrMEQ5SxaNFGKoyyfWDDVPw37JKvPTe","decimals":8}]},{"symbol":"PEOPLE","displayName":"ConstitutionDAO (Portal)","logo":"","coinGeckoId":"constitutiondao","nativeDetails":{"chainId":2,"address":"0x7a58c0be72be218b41c608b7fe7c5bb630736c71","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CobcsUrt3p91FwvULYKorQejgsm5HoQdv5T8RUZ6PnLA","decimals":8}]},{"symbol":"PERP","displayName":"Perpetual Protocol (Portal)","logo":"","coinGeckoId":"perpetual-protocol","nativeDetails":{"chainId":2,"address":"0xbc396689893d065f41bc2c6ecbee5e0085233447","decimals":18},"wrappedDetails":[{"chainId":1,"address":"9BsnSWDPfbusseZfnXyZ3un14CyPMZYvsKjWY3Y8Gbqn","decimals":8}]},{"symbol":"RGT","displayName":"Rari Governance Token (Portal)","logo":"","coinGeckoId":"rari-governance-token","nativeDetails":{"chainId":2,"address":"0xd291e7a03283640fdc51b121ac401383a46cc623","decimals":18},"wrappedDetails":[{"chainId":1,"address":"ASk8bss7PoxfFVJfXnSJepj9KupTX15QaRnhdjs6DdYe","decimals":8}]},{"symbol":"RPL","displayName":"Rocket Pool (Portal)","logo":"","coinGeckoId":"rocket-pool","nativeDetails":{"chainId":2,"address":"0xd33526068d116ce69f19a9ee46f0bd304f21a51f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HUCyuyqESEUV4YWTKFvvB4JiQLqoovscTBpRXfGzW4Wx","decimals":8}]},{"symbol":"RSR","displayName":"Reserve Rights (Portal)","logo":"","coinGeckoId":"reserve-rights-token","nativeDetails":{"chainId":2,"address":"0x8762db106B2c2A0bccB3A80d1Ed41273552616E8","decimals":18},"wrappedDetails":[{"chainId":1,"address":"DkbE8U4gSRuGHcVMA1LwyZPYUjYbfEbjW8DMR3iSXBzr","decimals":8}]},{"symbol":"SAND","displayName":"The Sandbox (Portal)","logo":"https://gemini.com/images/currencies/icons/default/sand.svg","coinGeckoId":"the-sandbox","nativeDetails":{"chainId":2,"address":"0x3845badAde8e6dFF049820680d1F14bD3903a5d0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"49c7WuCZkQgc3M4qH8WuEUNXfgwupZf1xqWkDQ7gjRGt","decimals":8}]},{"symbol":"SD","displayName":"Stader SD (Portal)","logo":"https://raw.githubusercontent.com/stader-labs/assets/main/eth/SD.png","coinGeckoId":"stader","nativeDetails":{"chainId":2,"address":"0x30D20208d987713f46DFD34EF128Bb16C404D10f","decimals":18},"wrappedDetails":[{"chainId":3,"address":"terra1ustvnmngueq0p4jd7gfnutgvdc6ujpsjhsjd02","decimals":8}]},{"symbol":"SHIB","displayName":"Shiba Inu (Portal)","logo":"https://etherscan.io/token/images/shibatoken_32.png","coinGeckoId":"shiba-inu","nativeDetails":{"chainId":2,"address":"0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CiKu4eHsVrc1eueVQeHn7qhXTcVu95gSQmBpX4utjL9z","decimals":8},{"chainId":4,"address":"0xb1547683DA678f2e1F003A780143EC10Af8a832B","decimals":18},{"chainId":3,"address":"terra1huku2lecfjhq9d00k5a8dh73gw7dwe6vvuf2dd","decimals":8}]},{"symbol":"SLP","displayName":"Smooth Love Potion (Portal)","logo":"","coinGeckoId":"smooth-love-potion","nativeDetails":{"chainId":2,"address":"0xcc8fa225d80b9c7d42f96e9570156c65d6caaa25","decimals":0},"wrappedDetails":[{"chainId":1,"address":"4hpngEp1v3CXpeKB81Gw4sv7YvwUVRKvY3SGag9ND8Q4","decimals":8}]},{"symbol":"SNX","displayName":"Synthetix Network Token (Portal)","logo":"","coinGeckoId":"synthetix-network-token","nativeDetails":{"chainId":2,"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8cTNUtcV2ueC3royJ642uRnvTxorJAWLZc58gxAo7y56","decimals":8}]},{"symbol":"SOS","displayName":"OpenDAO (Portal)","logo":"","coinGeckoId":"opendao","nativeDetails":{"chainId":2,"address":"0x3b484b82567a09e2588a13d54d032153f0c0aee0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"6Q5fvsJ6kgAFmisgDqqyaFd9FURYzHf8MCUbpAUaGZnE","decimals":8}]},{"symbol":"SPELL","displayName":"Spell Token (Portal)","logo":"","coinGeckoId":"spell-token","nativeDetails":{"chainId":2,"address":"0x090185f2135308bad17527004364ebcc2d37e5f6","decimals":18},"wrappedDetails":[{"chainId":1,"address":"BCsFXYm81iqXyYmrLKgAp3AePcgLHnirb8FjTs6sjM7U","decimals":8}]},{"symbol":"SRMet","displayName":"Serum (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png","coinGeckoId":"serum","nativeDetails":{"chainId":2,"address":"0x476c5e26a75bd202a9683ffd34359c0cc15be0ff","decimals":6},"wrappedDetails":[{"chainId":1,"address":"xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG","decimals":6},{"chainId":4,"address":"0xd63CDf02853D759831550fAe7dF8FFfE0B317b39","decimals":6}]},{"symbol":"SUSHI","displayName":"SushiToken (Portal)","logo":"https://etherscan.io/token/images/sushitoken_32.png","coinGeckoId":"sushi","nativeDetails":{"chainId":2,"address":"0x6b3595068778dd592e39a122f4f5a5cf09c90fe2","decimals":18},"wrappedDetails":[{"chainId":1,"address":"ChVzxWRmrTeSgwd3Ui3UumcN8KX7VK3WaD4KGeSKpypj","decimals":8},{"chainId":4,"address":"0x3524fd7488fdb1F4723BBc22C9cbD1Bf89f46E3B","decimals":18},{"chainId":3,"address":"terra1csvuzlf92nyemu6tv25h0l79etpe8hz3h5vn4a","decimals":8}]},{"symbol":"SWAG","displayName":"SWAG Finance (Portal)","logo":"","coinGeckoId":"swag-finance","nativeDetails":{"chainId":2,"address":"0x87edffde3e14c7a66c9b9724747a1c5696b742e6","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5hcdG6NjQwiNhVa9bcyaaDsCyA1muPQ6WRzQwHfgeeKo","decimals":8}]},{"symbol":"SXP","displayName":"Swipe (Portal)","logo":"","coinGeckoId":"swipe","nativeDetails":{"chainId":2,"address":"0x8ce9137d39326ad0cd6491fb5cc0cba0e089b6a9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3CyiEDRehaGufzkpXJitCP5tvh7cNhRqd9rPBxZrgK5z","decimals":8}]},{"symbol":"TOKE","displayName":"Tokemak (Portal)","logo":"","coinGeckoId":"tokemak","nativeDetails":{"chainId":2,"address":"0x2e9d63788249371f1dfc918a52f8d799f4a38c94","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3EQ6LqLkiFcoxTeGEsHMFpSLWNVPe9yT7XPX2HYSFyxX","decimals":8}]},{"symbol":"TRIBE","displayName":"Tribe (Portal)","logo":"","coinGeckoId":"tribe","nativeDetails":{"chainId":2,"address":"0xc7283b66eb1eb5fb86327f08e1b5816b0720212b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"DPgNKZJAG2w1S6vfYHDBT62R4qrWWH5f45CnxtbQduZE","decimals":8}]},{"symbol":"UBXT","displayName":"UpBots (Portal)","logo":"","coinGeckoId":"upbots","nativeDetails":{"chainId":2,"address":"0x8564653879a18c560e7c0ea0e084c516c62f5653","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FTtXEUosNn6EKG2SQtfbGuYB4rBttreQQcoWn1YDsuTq","decimals":8}]},{"symbol":"UFO","displayName":"UFO Gaming (Portal)","logo":"","coinGeckoId":"ufo-gaming","nativeDetails":{"chainId":2,"address":"0x249e38ea4102d0cf8264d3701f1a0e39c4f2dc3b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"GWdkYFnXnSJAsCBvmsqFLiPPe2tpvXynZcJdxf11Fu3U","decimals":8}]},{"symbol":"UNI","displayName":"Uniswap (Portal)","logo":"https://etherscan.io/token/images/uniswap_32.png","coinGeckoId":"uniswap","nativeDetails":{"chainId":2,"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8FU95xFJhUUkyyCLU13HSzDLs7oC4QZdXQHL6SCeab36","decimals":8},{"chainId":3,"address":"terra1wyxkuy5jq545fn7xfn3enpvs5zg9f9dghf6gxf","decimals":8}]},{"symbol":"USDCet","displayName":"USD Coin (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":2,"address":"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48","decimals":6},"wrappedDetails":[{"chainId":1,"address":"A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM","decimals":6},{"chainId":4,"address":"0xB04906e95AB5D797aDA81508115611fee694c2b3","decimals":6},{"chainId":3,"address":"terra1pepwcav40nvj3kh60qqgrk8k07ydmc00xyat06","decimals":6},{"chainId":5,"address":"0x4318cb63a2b8edf2de971e2f17f77097e499459d","decimals":6},{"chainId":6,"address":"0xB24CA28D4e2742907115fECda335b40dbda07a4C","decimals":6},{"chainId":7,"address":"0xE8A638b3B7565Ee7c5eb9755E58552aFc87b94DD","decimals":6},{"chainId":10,"address":"0x2Ec752329c3EB419136ca5e4432Aa2CDb1eA23e6","decimals":6},{"chainId":14,"address":"0x37f750B7cC259A2f741AF45294f6a16572CF5cAd","decimals":6}]},{"symbol":"USDK","displayName":"USDK (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F/logo.png","coinGeckoId":"usdk","nativeDetails":{"chainId":2,"address":"0x1c48f86ae57291f7686349f12601910bd8d470bb","decimals":18},"wrappedDetails":[{"chainId":1,"address":"43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F","decimals":8}]},{"symbol":"USDTet","displayName":"Tether USD (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg","coinGeckoId":"tether","nativeDetails":{"chainId":2,"address":"0xdac17f958d2ee523a2206206994597c13d831ec7","decimals":6},"wrappedDetails":[{"chainId":1,"address":"Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1","decimals":6},{"chainId":4,"address":"0x524bC91Dc82d6b90EF29F76A3ECAaBAffFD490Bc","decimals":6},{"chainId":3,"address":"terra1ce06wkrdm4vl6t0hvc0g86rsy27pu8yadg3dva","decimals":6},{"chainId":5,"address":"0x9417669fBF23357D2774e9D421307bd5eA1006d2","decimals":6},{"chainId":7,"address":"0xdC19A122e268128B5eE20366299fc7b5b199C8e3","decimals":6}]},{"symbol":"WBTC","displayName":"Wrapped BTC (Portal)","logo":"https://etherscan.io/token/images/wbtc_28.png?v=1","coinGeckoId":"wrapped-bitcoin","nativeDetails":{"chainId":2,"address":"0x2260fac5e5542a773aa44fbcfedf7c193bc2c599","decimals":8},"wrappedDetails":[{"chainId":1,"address":"3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh","decimals":8},{"chainId":3,"address":"terra1aa7upykmmqqc63l924l5qfap8mrmx5rfdm0v55","decimals":8},{"chainId":5,"address":"0x5D49c278340655B56609FdF8976eb0612aF3a0C3","decimals":8},{"chainId":7,"address":"0xd43ce0aa2a29DCb75bDb83085703dc589DE6C7eb","decimals":8}]},{"symbol":"YFI","displayName":"yearn.finance (Portal)","logo":"","coinGeckoId":"yearn-finance","nativeDetails":{"chainId":2,"address":"0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e","decimals":18},"wrappedDetails":[{"chainId":1,"address":"BXZX2JRJFjvKazM1ibeDFxgAngKExb74MRXzXKvgikxX","decimals":8}]},{"symbol":"YGG","displayName":"Yield Guild Games (Portal)","logo":"","coinGeckoId":"yield-guild-games","nativeDetails":{"chainId":2,"address":"0x25f8087ead173b73d6e8b84329989a8eea16cf73","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EzZp7LRN1xwu3QsB2RJRrWwEGjJGsuWzuMCeQDB3NSPK","decimals":8}]},{"symbol":"ZRX","displayName":"0x (Portal)","logo":"","coinGeckoId":"0x","nativeDetails":{"chainId":2,"address":"0xe41d2489571d322189246dafa5ebde1f4699f498","decimals":18},"wrappedDetails":[{"chainId":1,"address":"GJa1VeEYLTRoHbaeqcxfzHmjGCGtZGF3CUqxv9znZZAY","decimals":8}]},{"symbol":"agEUR","displayName":"agEUR (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1/logo.svg","coinGeckoId":"ageur","nativeDetails":{"chainId":2,"address":"0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1","decimals":8}]},{"symbol":"bETH","displayName":"Lido bETH (Portal)","logo":"https://static.lido.fi/bETH/bETH.png","coinGeckoId":"anchor-beth-token","nativeDetails":{"chainId":2,"address":"0x707f9118e33a9b8998bea41dd0d46f38bb963fc8","decimals":18},"wrappedDetails":[{"chainId":3,"address":"terra1u5szg038ur9kzuular3cae8hq6q5rk5u27tuvz","decimals":8}]},{"symbol":"gOHM","displayName":"Governance OHM (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FUGsN8H74WjRBBMfQWcf9Kk32gebA9VnNaGxqwcVvUW7/logo.png","coinGeckoId":"governance-ohm","nativeDetails":{"chainId":2,"address":"0x0ab87046fbb341d058f17cbc4c1133f25a20a52f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FUGsN8H74WjRBBMfQWcf9Kk32gebA9VnNaGxqwcVvUW7","decimals":8},{"chainId":3,"address":"terra1fpfn2kkr8mv390wx4dtpfk3vkjx9ch3thvykl3","decimals":8}]},{"symbol":"ibBTC","displayName":"Interest Bearing Bitcoin (Portal)","logo":"https://etherscan.io/token/images/badgeribtc_32.png","coinGeckoId":"interest-bearing-bitcoin","nativeDetails":{"chainId":2,"address":"0xc4e15973e6ff2a35cc804c2cf9d2a1b817a8b40f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi","decimals":8}]},{"symbol":"stETH","displayName":"Lido Staked Ether (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/H2mf9QNdU2Niq6QR7367Ua2trBsvscLyX5bz7R3Pw5sE/logo.png","coinGeckoId":"lido-staked-ether","nativeDetails":{"chainId":2,"address":"0xae7ab96520de3a18e5e111b5eaab095312d7fe84","decimals":18},"wrappedDetails":[{"chainId":1,"address":"H2mf9QNdU2Niq6QR7367Ua2trBsvscLyX5bz7R3Pw5sE","decimals":8},{"chainId":3,"address":"terra1w7ywr6waxtjuvn5svk5wqydqpjj0q9ps7qct4d","decimals":8}]},{"symbol":"wstETH","displayName":"Lido wstETH (Portal)","logo":"https://static.lido.fi/wstETH/wstETH.png","coinGeckoId":"wrapped-steth","nativeDetails":{"chainId":2,"address":"0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0","decimals":18},"wrappedDetails":[{"chainId":3,"address":"terra133chr09wu8sakfte5v7vd8qzq9vghtkv4tn0ur","decimals":8}]},{"symbol":"BNB","displayName":"Binance Coin (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa/logo.png","coinGeckoId":"binance-coin","nativeDetails":{"chainId":4,"address":"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c","decimals":18},"wrappedDetails":[{"chainId":1,"address":"9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa","decimals":8},{"chainId":2,"address":"0x418D75f65a02b3D53B2418FB8E1fe493759c7605","decimals":18},{"chainId":3,"address":"terra1cetg5wruw2wsdjp7j46rj44xdel00z006e9yg8","decimals":8},{"chainId":5,"address":"0xecdcb5b88f8e3c15f95c720c51c71c9e2080525d","decimals":18},{"chainId":6,"address":"0x442F7f22b1EE2c842bEAFf52880d4573E9201158","decimals":18},{"chainId":7,"address":"0xd79Ef9A91b56c690C7b80570a3c060678667f469","decimals":18}]},{"symbol":"BUSDbs","displayName":"Binance USD (Portal from BSC)","logo":"https://etherscan.io/token/images/binanceusd_32.png","coinGeckoId":"binance-usd","nativeDetails":{"chainId":4,"address":"0xe9e7cea3dedca5984780bafc599bd69add087d56","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2","decimals":8},{"chainId":2,"address":"0x7B4B0B9b024109D182dCF3831222fbdA81369423","decimals":18},{"chainId":3,"address":"terra1skjr69exm6v8zellgjpaa2emhwutrk5a6dz7dd","decimals":8},{"chainId":5,"address":"0xa8d394fe7380b8ce6145d5f85e6ac22d4e91acde","decimals":18},{"chainId":6,"address":"0xA41a6c7E25DdD361343e8Cb8cFa579bbE5eEdb7a","decimals":18},{"chainId":7,"address":"0xf6568FD76f9fcD1f60f73b730F142853c5eF627E","decimals":18}]},{"symbol":"CAKE","displayName":"PancakeSwap Token (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/J8LKx7pr9Zxh9nMhhT7X3EBmj5RzuhFrHKyJAe2F2i9S/logo.png","coinGeckoId":"pancakeswap","nativeDetails":{"chainId":4,"address":"0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82","decimals":18},"wrappedDetails":[{"chainId":1,"address":"J8LKx7pr9Zxh9nMhhT7X3EBmj5RzuhFrHKyJAe2F2i9S","decimals":8},{"chainId":2,"address":"0x7c8161545717a334f3196e765d9713f8042EF338","decimals":18},{"chainId":3,"address":"terra1xvqlpjl2dxyel9qrp6qvtrg04xe3jh9cyxc6av","decimals":8},{"chainId":6,"address":"0x98a4d09036Cc5337810096b1D004109686E56Afc","decimals":18}]},{"symbol":"USDCbs","displayName":"USD Coin (Portal from BSC)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":4,"address":"0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA","decimals":8},{"chainId":2,"address":"0x7cd167B101D2808Cfd2C45d17b2E7EA9F46b74B6","decimals":18},{"chainId":3,"address":"terra1yljlrxvkar0c6ujpvf8g57m5rpcwl7r032zyvu","decimals":8},{"chainId":6,"address":"0x6145E8a910aE937913426BF32De2b26039728ACF","decimals":18},{"chainId":7,"address":"0x4cA2A3De42eabC8fd8b0AC46127E64DB08b9150e","decimals":18}]},{"symbol":"USDTbs","displayName":"Tether USD (Portal from BSC)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg","coinGeckoId":"tether","nativeDetails":{"chainId":4,"address":"0x55d398326f99059fF775485246999027B3197955","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv","decimals":8},{"chainId":2,"address":"0xDe60aDfDdAAbaAAC3dAFa57B26AcC91Cb63728c4","decimals":18},{"chainId":3,"address":"terra1vlqeghv5mt5udh96kt5zxlh2wkh8q4kewkr0dd","decimals":8},{"chainId":6,"address":"0xA67BCC0D06d7d13A13A2AE30bF30f1B434f5a28B","decimals":18},{"chainId":7,"address":"0x366EF31C8dc715cbeff5fA54Ad106dC9c25C6153","decimals":18}]},{"symbol":"LUNA","displayName":"LUNA (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W/logo.png","coinGeckoId":"terra-luna","nativeDetails":{"chainId":3,"address":"uluna","decimals":6},"wrappedDetails":[{"chainId":1,"address":"F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W","decimals":6},{"chainId":2,"address":"0xbd31ea8212119f94a611fa969881cba3ea06fa3d","decimals":6},{"chainId":4,"address":"0x156ab3346823B651294766e23e6Cf87254d68962","decimals":6},{"chainId":5,"address":"0x9cd6746665D9557e1B9a775819625711d0693439","decimals":6},{"chainId":6,"address":"0x70928E5B188def72817b7775F0BF6325968e563B","decimals":6},{"chainId":7,"address":"0x4F43717B20ae319Aa50BC5B2349B93af5f7Ac823","decimals":6},{"chainId":10,"address":"0x593AE1d34c8BD7587C11D539E4F42BFf242c82Af","decimals":6},{"chainId":9,"address":"0x12302fbE05a7e833f87d4B7843F58d19BE4FdE3B","decimals":6}]},{"symbol":"UST","displayName":"UST (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i/logo.png","coinGeckoId":"terra-usd","nativeDetails":{"chainId":3,"address":"uusd","decimals":6},"wrappedDetails":[{"chainId":1,"address":"9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i","decimals":6},{"chainId":2,"address":"0xa693B19d2931d498c5B318dF961919BB4aee87a5","decimals":6},{"chainId":4,"address":"0x3d4350cD54aeF9f9b2C29435e0fa809957B3F30a","decimals":6},{"chainId":5,"address":"0xE6469Ba6D2fD6130788E0eA9C0a0515900563b59","decimals":6},{"chainId":6,"address":"0xb599c3590F42f8F995ECfa0f85D2980B76862fc1","decimals":6},{"chainId":7,"address":"0xa1E73c01E0cF7930F5e91CB291031739FE5Ad6C2","decimals":6},{"chainId":10,"address":"0x846e4D51d7E2043C1a87E0Ab7490B93FB940357b","decimals":6},{"chainId":9,"address":"0x8D07bBb478B84f7E940e97C8e9cF7B3645166b03","decimals":6}]},{"symbol":"aUST","displayName":"AnchorUST (Portal)","logo":"","coinGeckoId":"anchorust","nativeDetails":{"chainId":3,"address":"terra1hzh9vpxhsk8253se0vv5jj6etdvxu3nv8z07zu","decimals":6},"wrappedDetails":[{"chainId":1,"address":"4CsZsUCoKFiaGyU7DEVDayqeVtG8iqgGDR6RjzQmzQao","decimals":6},{"chainId":4,"address":"0x8b04E56A8cd5f4D465b784ccf564899F30Aaf88C","decimals":6}]},{"symbol":"DAIpo","displayName":"DAI (Portal from Polygon)","logo":"","coinGeckoId":"dai","nativeDetails":{"chainId":5,"address":"0x8f3cf7ad23cd3cadbd9735aff958023239c6a063","decimals":18},"wrappedDetails":[{"chainId":1,"address":"4Fo67MYQpVhZj9R7jQTd63FPAnWbPpaafAUxsMGX2geP","decimals":8}]},{"symbol":"MATICpo","displayName":"MATIC (Portal from Polygon)","logo":"","coinGeckoId":"polygon","nativeDetails":{"chainId":5,"address":"0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Gz7VkD4MacbEB6yC5XD3HcumEiYx2EtDYYrfikGsvopG","decimals":8},{"chainId":2,"address":"0x7c9f4C87d911613Fe9ca58b579f737911AAD2D43","decimals":18},{"chainId":4,"address":"0xc836d8dC361E44DbE64c4862D55BA041F88Ddd39","decimals":18},{"chainId":3,"address":"terra1dtqlfecglk47yplfrtwjzyagkgcqqngd5lgjp8","decimals":8},{"chainId":6,"address":"0xf2f13f0B7008ab2FA4A2418F4ccC3684E49D20Eb","decimals":18}]},{"symbol":"QUICK","displayName":"Quickswap (Portal)","logo":"","coinGeckoId":"quickswap","nativeDetails":{"chainId":5,"address":"0x831753dd7087cac61ab5644b308642cc1c33dc13","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5njTmK53Ss5jkiHHZvzabVzZj6ztu6WYWpAPYgbVnbjs","decimals":8}]},{"symbol":"USDCpo","displayName":"USD Coin (PoS) (Portal from Polygon)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":5,"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","decimals":6},"wrappedDetails":[{"chainId":1,"address":"E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M","decimals":6},{"chainId":2,"address":"0x566957eF80F9fd5526CD2BEF8BE67035C0b81130","decimals":6},{"chainId":4,"address":"0x672147dD47674757C457eB155BAA382cc10705Dd","decimals":6},{"chainId":3,"address":"terra1kkyyh7vganlpkj0gkc2rfmhy858ma4rtwywe3x","decimals":6},{"chainId":6,"address":"0x543672E9CBEC728CBBa9C3Ccd99ed80aC3607FA8","decimals":6},{"chainId":7,"address":"0x3E62a9c3aF8b810dE79645C4579acC8f0d06a241","decimals":6}]},{"symbol":"USDTpo","displayName":"Tether USD (PoS) (Portal from Polygon)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1/logo.png","coinGeckoId":"tether","nativeDetails":{"chainId":5,"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6},"wrappedDetails":[{"chainId":1,"address":"5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1","decimals":6},{"chainId":7,"address":"0xFffD69E757d8220CEA60dc80B9Fe1a30b58c94F3","decimals":6}]},{"symbol":"AVAX","displayName":"AVAX (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/KgV1GvrHQmRBY8sHQQeUKwTm2r2h8t4C8qt12Cw1HVE/logo.png","coinGeckoId":"avalanche","nativeDetails":{"chainId":6,"address":"0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7","decimals":18},"wrappedDetails":[{"chainId":1,"address":"KgV1GvrHQmRBY8sHQQeUKwTm2r2h8t4C8qt12Cw1HVE","decimals":8},{"chainId":2,"address":"0x85f138bfEE4ef8e540890CFb48F620571d67Eda3","decimals":18},{"chainId":4,"address":"0x96412902aa9aFf61E13f085e70D3152C6ef2a817","decimals":18},{"chainId":3,"address":"terra1hj8de24c3yqvcsv9r8chr03fzwsak3hgd8gv3m","decimals":8},{"chainId":5,"address":"0x7Bb11E7f8b10E9e571E5d8Eace04735fDFB2358a","decimals":18},{"chainId":7,"address":"0x32847e63E99D3a044908763056e25694490082F8","decimals":18}]},{"symbol":"JOE","displayName":"JoeToken (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CriXdFS9iRAYbGEQiTcUqbWwG9RBmYt5B6LwTnoJ61Sm/logo.png","coinGeckoId":"joe","nativeDetails":{"chainId":6,"address":"0x6e84a6216ea6dacc71ee8e6b0a5b7322eebc0fdd","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CriXdFS9iRAYbGEQiTcUqbWwG9RBmYt5B6LwTnoJ61Sm","decimals":8}]},{"symbol":"USDCav","displayName":"USD Coin (Portal from Avalanche)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":6,"address":"0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664","decimals":6},"wrappedDetails":[{"chainId":1,"address":"AGqKX7F4mqJ8x2mUQVangJb5pWQJApaKoUfe5gXM53CV","decimals":8},{"chainId":4,"address":"0xc1F47175d96Fe7c4cD5370552e5954f384E3C791","decimals":6},{"chainId":3,"address":"terra1pvel56a2hs93yd429pzv9zp5aptcjg5ulhkz7w","decimals":6},{"chainId":7,"address":"0x05CbE6319Dcc937BdbDf0931466F4fFd0d392B47","decimals":6}]},{"symbol":"USDTav","displayName":"Tether USD (Portal from Avalanche)","logo":"","coinGeckoId":"tether","nativeDetails":{"chainId":6,"address":"0xc7198437980c041c805a1edcba50c1ce5db95118","decimals":6},"wrappedDetails":[{"chainId":1,"address":"B2wfeYz5VtBnQVrX4M8F6FeDrprVrzKPws5qg1in8bzR","decimals":8},{"chainId":4,"address":"0x2B90E061a517dB2BbD7E39Ef7F733Fd234B494CA","decimals":6},{"chainId":3,"address":"terra1eqvq3thjhye7anv6f6mhxpjhyvww8zjvqcdgjx","decimals":6},{"chainId":7,"address":"0x05832a0905E516f29344ADBa1c2052a788B10129","decimals":6}]},{"symbol":"ROSE","displayName":"ROSE (Portal)","logo":"https://assets.coingecko.com/coins/images/13162/small/rose.png","coinGeckoId":"oasis-network","nativeDetails":{"chainId":7,"address":"0x21C718C22D52d0F3a789b752D4c2fD5908a8A733","decimals":18},"wrappedDetails":[{"chainId":1,"address":"S3SQfD6RheMXQ3EEYn1Z5sJsbtwfXdt7tSAVXPQFtYo","decimals":8},{"chainId":2,"address":"0x26B80FBfC01b71495f477d5237071242e0d959d7","decimals":18},{"chainId":4,"address":"0x6c6D604D3f07aBE287C1A3dF0281e999A83495C0","decimals":18},{"chainId":6,"address":"0x12AF5C1a232675f62F405b5812A80e7a6F75D746","decimals":18}]},{"symbol":"SWEAT","displayName":"Sweat Economy","logo":"https://assets.coingecko.com/coins/images/25057/small/fhD9Xs16_400x400.jpg?1649947000","coinGeckoId":"sweatcoin","nativeDetails":{"chainId":15,"address":"token.sweat","decimals":18},"wrappedDetails":[{"chainId":2,"address":"0xB4b9DC1C77bdbb135eA907fd5a08094d98883A35","decimals":18},{"chainId":4,"address":"0x510Ad22d8C956dCC20f68932861f54A591001283","decimals":18}]}] \ No newline at end of file +[{"symbol":"RAY","displayName":"Raydium (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R/logo.png","coinGeckoId":"raydium","nativeDetails":{"chainId":1,"address":"4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0xE617dd80c621a5072bD8cBa65E9d76c07327004d","decimals":6},{"chainId":4,"address":"0x13b6A55662f6591f8B8408Af1C73B017E32eEdB8","decimals":6}]},{"symbol":"SBR","displayName":"Saber (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1/logo.svg","coinGeckoId":"saber","nativeDetails":{"chainId":1,"address":"Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1","decimals":6},"wrappedDetails":[{"chainId":4,"address":"0x75344E5693ed5ecAdF4f292fFeb866c2cF8afCF1","decimals":6}]},{"symbol":"SOL","displayName":"SOL (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png","coinGeckoId":"solana","nativeDetails":{"chainId":1,"address":"So11111111111111111111111111111111111111112","decimals":9},"wrappedDetails":[{"chainId":2,"address":"0xD31a59c85aE9D8edEFeC411D448f90841571b89c","decimals":9},{"chainId":4,"address":"0xfA54fF1a158B5189Ebba6ae130CEd6bbd3aEA76e","decimals":9},{"chainId":5,"address":"0xd93f7e271cb87c23aaa73edc008a79646d1f9912","decimals":9},{"chainId":6,"address":"0xFE6B19286885a4F7F55AdAD09C3Cd1f906D2478F","decimals":9},{"chainId":7,"address":"0xd17dDAC91670274F7ba1590a06EcA0f2FD2b12bc","decimals":9},{"chainId":10,"address":"0xd99021C2A33e4Cf243010539c9e9b7c52E0236c1","decimals":9}]},{"symbol":"SRMso","displayName":"Serum (Portal from Solana)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png","coinGeckoId":"serum","nativeDetails":{"chainId":1,"address":"SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0xE3ADAA4fb7c92AB833Ee08B3561D9c434aA2A3eE","decimals":6},{"chainId":4,"address":"0x12BeffdCEcb547640DC30e1495E4B9cdc21922b4","decimals":6}]},{"symbol":"USDCso","displayName":"USD Coin (Portal from Solana)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":1,"address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0x41f7B8b9b897276b7AAE926a9016935280b44E97","decimals":6},{"chainId":4,"address":"0x91Ca579B0D47E5cfD5D0862c21D5659d39C8eCf0","decimals":6},{"chainId":5,"address":"0x576cf361711cd940cd9c397bb98c4c896cbd38de","decimals":6},{"chainId":6,"address":"0x0950Fc1AD509358dAeaD5eB8020a3c7d8b43b9DA","decimals":6},{"chainId":7,"address":"0x1d1149a53deB36F2836Ae7877c9176413aDfA4A8","decimals":6},{"chainId":10,"address":"0xb8398DA4FB3BC4306B9D9d9d13d9573e7d0E299f","decimals":6},{"chainId":9,"address":"0xDd1DaFedeBa5F9851C4F4a2876E0f3aF3c774B1A","decimals":6}]},{"symbol":"USDTso","displayName":"Tether USD (Portal from Solana)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg","coinGeckoId":"tether","nativeDetails":{"chainId":1,"address":"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB","decimals":6},"wrappedDetails":[{"chainId":2,"address":"0x1CDD2EaB61112697626F7b4bB0e23Da4FeBF7B7C","decimals":6},{"chainId":4,"address":"0x49d5cC521F75e13fa8eb4E89E9D381352C897c96","decimals":6},{"chainId":5,"address":"0x3553f861dec0257bada9f8ed268bf0d74e45e89c","decimals":6},{"chainId":6,"address":"0xF0FF231e3F1A50F83136717f287ADAB862f89431","decimals":6},{"chainId":7,"address":"0x24285C5232ce3858F00bacb950Cae1f59d1b2704","decimals":6},{"chainId":9,"address":"0xd80890AFDBd7148456D8Ee358eF9127F0F8c7faf","decimals":6}]},{"symbol":"XTAG","displayName":"XTAG Token (Portal)","logo":"https://raw.githubusercontent.com/sudomon/wormhole-token-list/main/src/logogen/base/xtag.png","coinGeckoId":"xhashtag","nativeDetails":{"chainId":1,"address":"5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp","decimals":6},"wrappedDetails":[{"chainId":6,"address":"0xa608d79c5f695c0d4c0e773a4938b57e18e0fc57","decimals":6}]},{"symbol":"ZBC","displayName":"Zebec Protocol","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF/logo.png","coinGeckoId":"zebec-protocol","nativeDetails":{"chainId":1,"address":"zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF","decimals":9},"wrappedDetails":[{"chainId":4,"address":"0x6D1054C3102E842314e250b9e9C4Be327b8DaaE2","decimals":9}]},{"symbol":"mSOL","displayName":"Marinade staked SOL (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So/logo.png","coinGeckoId":"marinade-staked-sol","nativeDetails":{"chainId":1,"address":"mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So","decimals":9},"wrappedDetails":[{"chainId":2,"address":"0x756bFb452cFE36A5Bc82e4F5f4261A89a18c242b","decimals":9},{"chainId":7,"address":"0x5E11A4f64D3B9fA042dB9e1AA918F735038FdfD8","decimals":9}]},{"symbol":"1INCH","displayName":"1INCH Token (Portal)","logo":"","coinGeckoId":"1inch","nativeDetails":{"chainId":2,"address":"0x111111111117dC0aa78b770fA6A738034120C302","decimals":18},"wrappedDetails":[{"chainId":1,"address":"AjkPkq3nsyDe1yKcbyZT7N4aK4Evv9om9tzhQD3wsRC","decimals":8}]},{"symbol":"1SOL","displayName":"1sol.io (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF/logo.png","coinGeckoId":"1sol","nativeDetails":{"chainId":2,"address":"0x009178997aff09a67d4caccfeb897fb79d036214","decimals":18},"wrappedDetails":[{"chainId":1,"address":"4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF","decimals":8}]},{"symbol":"AAVE","displayName":"Aave Token (Portal)","logo":"","coinGeckoId":"aave","nativeDetails":{"chainId":2,"address":"0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3vAs4D1WE6Na4tCgt4BApgFfENbm8WY7q4cSPD1yM4Cg","decimals":8}]},{"symbol":"AKRO","displayName":"Akropolis (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/G3h8NZgJozk9crme2me6sKDJuSQ12mNCtvC9NbSWqGuk/logo.png","coinGeckoId":"akropolis","nativeDetails":{"chainId":2,"address":"0x8ab7404063ec4dbcfd4598215992dc3f8ec853d7","decimals":18},"wrappedDetails":[{"chainId":1,"address":"12uHjozDVgyGWeLqQ8DMCRbig8amW5VmvZu3FdMMdcaG","decimals":8}]},{"symbol":"ALEPH","displayName":"Aleph.im (Portal)","logo":"","coinGeckoId":"aleph-im","nativeDetails":{"chainId":2,"address":"0x27702a26126e0b3702af63ee09ac4d1a084ef628","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3UCMiSnkcnkPE1pgQ5ggPCBv6dXgVUy16TmMUe1WpG9x","decimals":8}]},{"symbol":"ALICE","displayName":"My Neighbor Alice (Portal)","logo":"","coinGeckoId":"my-neighbor-alice","nativeDetails":{"chainId":2,"address":"0xac51066d7bec65dc4589368da368b212745d63e8","decimals":6},"wrappedDetails":[{"chainId":1,"address":"9ARQsBfAn65q522cEqSJuse3cLhA31jgWDBGQHeiq7Mg","decimals":8}]},{"symbol":"AMP","displayName":"Amp (Portal)","logo":"","coinGeckoId":"amp","nativeDetails":{"chainId":2,"address":"0xff20817765cb7f73d4bde2e66e067e58d11095c2","decimals":18},"wrappedDetails":[{"chainId":1,"address":"D559HwgjYGDYsXpmFUKxhFTEwutvS9sya1kXiyCVogCV","decimals":8}]},{"symbol":"AMPL","displayName":"Ampleforth (Portal)","logo":"","coinGeckoId":"ampleforth","nativeDetails":{"chainId":2,"address":"0xd46ba6d942050d489dbd938a2c909a5d5039a161","decimals":9},"wrappedDetails":[{"chainId":1,"address":"EHKQvJGu48ydKA4d3RivrkNyTJTkSdoS32UafxSX1yak","decimals":8}]},{"symbol":"ANKR","displayName":"Ankr (Portal)","logo":"","coinGeckoId":"ankr","nativeDetails":{"chainId":2,"address":"0x8290333cef9e6d528dd5618fb97a76f268f3edd4","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Gq2norJ1kBemBp3mPfkgAUMhMMmnFmY4zEyi26tRcxFB","decimals":8}]},{"symbol":"AUDIO","displayName":"Audius (Portal)","logo":"","coinGeckoId":"audius","nativeDetails":{"chainId":2,"address":"0x18aaa7115705e8be94bffebde57af9bfc265b998","decimals":18},"wrappedDetails":[{"chainId":1,"address":"9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM","decimals":8}]},{"symbol":"AXSet","displayName":"Axie Infinity Shard (Portal from Ethereum)","logo":"https://etherscan.io/token/images/axieinfinityshard_32.png","coinGeckoId":"axie-infinity","nativeDetails":{"chainId":2,"address":"0xbb0e17ef65f82ab018d8edd776e8dd940327b28b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HysWcbHiYY9888pHbaqhwLYZQeZrcQMXKQWRqS7zcPK5","decimals":8},{"chainId":4,"address":"0x556b60c53fbC1518Ad17E03d52E47368dD4d81B3","decimals":18}]},{"symbol":"BAT","displayName":"Basic Attention Token (Portal)","logo":"","coinGeckoId":"basic-attention-token","nativeDetails":{"chainId":2,"address":"0x0d8775f648430679a709e98d2b0cb6250d2887ef","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EPeUFDgHRxs9xxEPVaL6kfGQvCon7jmAWKVUHuux1Tpz","decimals":8},{"chainId":4,"address":"0x31C78f583ed0288D67b2b80Dc5C443Bc3b15C661","decimals":18}]},{"symbol":"BNT","displayName":"Bancor Network Token (Portal)","logo":"","coinGeckoId":"bancor-network","nativeDetails":{"chainId":2,"address":"0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EDVVEYW4fPJ6vKw5LZXRGUSPzxoHrv6eWvTqhCr8oShs","decimals":8}]},{"symbol":"BUSDet","displayName":"Binance USD (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX/logo.png","coinGeckoId":"binance-usd","nativeDetails":{"chainId":2,"address":"0x4fabb145d64652a948d72533023f6e7a623c7c53","decimals":18},"wrappedDetails":[{"chainId":1,"address":"33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX","decimals":8},{"chainId":4,"address":"0x035de3679E692C471072d1A09bEb9298fBB2BD31","decimals":18}]},{"symbol":"CEL","displayName":"Celsius (Portal)","logo":"","coinGeckoId":"celsius-network","nativeDetails":{"chainId":2,"address":"0xaaaebe6fe48e54f431b0c390cfaf0b017d09d42d","decimals":4},"wrappedDetails":[{"chainId":1,"address":"nRtfwU9G82CSHhHGJNxFhtn7FLvWP2rqvQvje1WtL69","decimals":4}]},{"symbol":"CHZ","displayName":"Chiliz (Portal)","logo":"","coinGeckoId":"chiliz","nativeDetails":{"chainId":2,"address":"0x3506424f91fd33084466f402d5d97f05f8e3b4af","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5TtSKAamFq88grN1QGrEaZ1AjjyciqnCya1aiMhAgFvG","decimals":8}]},{"symbol":"COMP","displayName":"Compound (Portal)","logo":"","coinGeckoId":"compound","nativeDetails":{"chainId":2,"address":"0xc00e94cb662c3520282e6f5717214004a7f26888","decimals":18},"wrappedDetails":[{"chainId":1,"address":"AwEauVaTMQRB71WeDnwf1DWSBxaMKjEPuxyLr1uixFom","decimals":8}]},{"symbol":"CREAM","displayName":"Cream (Portal)","logo":"","coinGeckoId":"cream","nativeDetails":{"chainId":2,"address":"0x2ba592f78db6436527729929aaf6c908497cb200","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HihxL2iM6L6P1oqoSeiixdJ3PhPYNxvSKH9A2dDqLVDH","decimals":8}]},{"symbol":"CRO","displayName":"Crypto.com Coin (Portal)","logo":"","coinGeckoId":"crypto-com-coin","nativeDetails":{"chainId":2,"address":"0xa0b73e1ff0b80914ab6fe0444e65848c4c34450b","decimals":8},"wrappedDetails":[{"chainId":1,"address":"DvjMYMVeXgKxaixGKpzQThLoG98nc7HSU7eanzsdCboA","decimals":8}]},{"symbol":"CRV","displayName":"Curve DAO Token (Portal)","logo":"","coinGeckoId":"curve-dao-token","nativeDetails":{"chainId":2,"address":"0xd533a949740bb3306d119cc777fa900ba034cd52","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7gjNiPun3AzEazTZoFEjZgcBMeuaXdpjHq2raZTmTrfs","decimals":8}]},{"symbol":"CVX","displayName":"Convex Finance (Portal)","logo":"","coinGeckoId":"convex-finance","nativeDetails":{"chainId":2,"address":"0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"BLvmrccP4g1B6SpiVvmQrLUDya1nZ4B2D1nm9jzKF7sz","decimals":8}]},{"symbol":"DAI","displayName":"DAI (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png","coinGeckoId":"dai","nativeDetails":{"chainId":2,"address":"0x6b175474e89094c44da98b954eedeac495271d0f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o","decimals":8},{"chainId":4,"address":"0x3413a030EF81a3dD5a302F4B4D11d911e12ed337","decimals":18}]},{"symbol":"DYDX","displayName":"dYdX (Portal)","logo":"https://etherscan.io/token/images/dydx2_32.png","coinGeckoId":"dydx","nativeDetails":{"chainId":2,"address":"0x92d6c1e31e14520e676a687f0a93788b716beff5","decimals":18},"wrappedDetails":[{"chainId":1,"address":"4Hx6Bj56eGyw8EJrrheM6LBQAvVYRikYCWsALeTrwyRU","decimals":8}]},{"symbol":"ELON","displayName":"Dogelon Mars (Portal)","logo":"","coinGeckoId":"dogelon-mars","nativeDetails":{"chainId":2,"address":"0x761d38e5ddf6ccf6cf7c55759d5210750b5d60f3","decimals":18},"wrappedDetails":[{"chainId":1,"address":"6nKUU36URHkewHg5GGGAgxs6szkE4VTioGUT5txQqJFU","decimals":8}]},{"symbol":"ENJ","displayName":"EnjinCoin (Portal)","logo":"","coinGeckoId":"enjin","nativeDetails":{"chainId":2,"address":"0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EXExWvT6VyYxEjFzF5BrUxt5GZMPVZnd48y3iWrRefMq","decimals":8}]},{"symbol":"ENS","displayName":"Ethereum Name Service (Portal)","logo":"","coinGeckoId":"ethereum-name-service","nativeDetails":{"chainId":2,"address":"0xc18360217d8f7ab5e7c516566761ea12ce7f9d72","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CLQsDGoGibdNPnVCFp8BAsN2unvyvb41Jd5USYwAnzAg","decimals":8}]},{"symbol":"ETH","displayName":"Ether (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs/logo.png","coinGeckoId":"ether","nativeDetails":{"chainId":2,"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs","decimals":8},{"chainId":4,"address":"0x4DB5a66E937A9F4473fA95b1cAF1d1E1D62E29EA","decimals":18},{"chainId":5,"address":"0x11CD37bb86F65419713f30673A480EA33c826872","decimals":18},{"chainId":6,"address":"0x8b82A291F83ca07Af22120ABa21632088fC92931","decimals":18},{"chainId":7,"address":"0x3223f17957Ba502cbe71401D55A0DB26E5F7c68F","decimals":18},{"chainId":9,"address":"0x811Cc0d762eA72aC72385d93b98a97263AE37E4C","decimals":18},{"chainId":14,"address":"0x66803FB87aBd4aaC3cbB3fAd7C3aa01f6F3FB207","decimals":18}]},{"symbol":"ETHIX","displayName":"Ethix (Portal)","logo":"https://raw.githubusercontent.com/ethichub/wormhole-token-list/main/src/logogen/base/ETHIX.png","coinGeckoId":"ethichub","nativeDetails":{"chainId":2,"address":"0xFd09911130e6930Bf87F2B0554c44F400bD80D3e","decimals":18},"wrappedDetails":[{"chainId":14,"address":"0x9995cc8F20Db5896943Afc8eE0ba463259c931ed","decimals":18}]},{"symbol":"FRAX","displayName":"Frax (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp/logo.png","coinGeckoId":"frax","nativeDetails":{"chainId":2,"address":"0x853d955acef822db058eb8505911ed77f175b99e","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp","decimals":8}]},{"symbol":"FRONT","displayName":"Frontier (Portal)","logo":"","coinGeckoId":"frontier","nativeDetails":{"chainId":2,"address":"0xf8c3527cc04340b208c854e985240c02f7b7793f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"A9ik2NrpKRRG2snyTjofZQcTuav9yH3mNVHLsLiDQmYt","decimals":8}]},{"symbol":"FTMet","displayName":"Fantom (Portal from Ethereum)","logo":"","coinGeckoId":"fantom","nativeDetails":{"chainId":2,"address":"0x4e15361fd6b4bb609fa63c81a2be19d873717870","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8gC27rQF4NEDYfyf5aS8ZmQJUum5gufowKGYRRba4ENN","decimals":8}]},{"symbol":"FTT","displayName":"FTX Token (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv/logo.png","coinGeckoId":"ftx-token","nativeDetails":{"chainId":2,"address":"0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv","decimals":8},{"chainId":4,"address":"0x49BA054B9664e99ac335667a917c63bB94332E84","decimals":18}]},{"symbol":"FXS","displayName":"Frax Share (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/6LX8BhMQ4Sy2otmAWj7Y5sKd9YTVVUgfMsBzT6B9W7ct/logo.png","coinGeckoId":"frax-share","nativeDetails":{"chainId":2,"address":"0x3432b6a60d23ca0dfca7761b7ab56459d9c964d0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"6LX8BhMQ4Sy2otmAWj7Y5sKd9YTVVUgfMsBzT6B9W7ct","decimals":8}]},{"symbol":"GALA","displayName":"Gala (Portal)","logo":"","coinGeckoId":"gala","nativeDetails":{"chainId":2,"address":"0x15d4c048f83bd7e37d49ea4c83a07267ec4203da","decimals":8},"wrappedDetails":[{"chainId":1,"address":"AuGz22orMknxQHTVGwAu7e3dJikTJKgcjFwMNDikEKmF","decimals":8}]},{"symbol":"GRT","displayName":"Graph Token (Portal)","logo":"","coinGeckoId":"the-graph","nativeDetails":{"chainId":2,"address":"0xc944E90C64B2c07662A292be6244BDf05Cda44a7","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HGsLG4PnZ28L8A4R5nPqKgZd86zUUdmfnkTRnuFJ5dAX","decimals":8}]},{"symbol":"GT","displayName":"GateToken (Portal)","logo":"","coinGeckoId":"gatetoken","nativeDetails":{"chainId":2,"address":"0xe66747a101bff2dba3697199dcce5b743b454759","decimals":18},"wrappedDetails":[{"chainId":1,"address":"ABAq2R9gSpDDGguQxBk4u13s4ZYW6zbwKVBx15mCMG8","decimals":8}]},{"symbol":"HBTC","displayName":"Huobi BTC (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8/logo.png","coinGeckoId":"huobi-btc","nativeDetails":{"chainId":2,"address":"0x0316eb71485b0ab14103307bf65a021042c6d380","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8","decimals":8}]},{"symbol":"HGET","displayName":"Hedget (Portal)","logo":"","coinGeckoId":"hedget","nativeDetails":{"chainId":2,"address":"0x7968bc6a03017ea2de509aaa816f163db0f35148","decimals":6},"wrappedDetails":[{"chainId":1,"address":"2ueY1bLcPHfuFzEJq7yN1V2Wrpu8nkun9xG2TVCE1mhD","decimals":8}]},{"symbol":"HUSD","displayName":"HUSD Stablecoin (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw/logo.png","coinGeckoId":"husd","nativeDetails":{"chainId":2,"address":"0xdf574c24545e5ffecb9a659c229253d4111d87e1","decimals":8},"wrappedDetails":[{"chainId":1,"address":"7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw","decimals":8}]},{"symbol":"HXRO","displayName":"Hxro (Portal)","logo":"","coinGeckoId":"hxro","nativeDetails":{"chainId":2,"address":"0x4bd70556ae3f8a6ec6c4080a0c327b24325438f3","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HxhWkVpk5NS4Ltg5nij2G671CKXFRKPK8vy271Ub4uEK","decimals":8}]},{"symbol":"ICE","displayName":"PopsicleToken (Portal)","logo":"","coinGeckoId":"popsicle-finance","nativeDetails":{"chainId":2,"address":"0xf16e81dce15b08f326220742020379b855b87df9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"DiJut4U3CU8b3bRgwfyqtJMJ4wjzJHaX6hudamjH46Km","decimals":8}]},{"symbol":"ILV","displayName":"Illuvium (Portal)","logo":"","coinGeckoId":"illuvium","nativeDetails":{"chainId":2,"address":"0x767fe9edc9e0df98e07454847909b5e959d7ca0e","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8UJbtpsEubDVkY53rk7d61hNYKkvouicczB2XmuwiG4g","decimals":8}]},{"symbol":"KEEP","displayName":"Keep Network (Portal)","logo":"","coinGeckoId":"keep-network","nativeDetails":{"chainId":2,"address":"0x85eee30c52b0b379b046fb0f85f4f3dc3009afec","decimals":18},"wrappedDetails":[{"chainId":1,"address":"64L6o4G2H7Ln1vN7AHZsUMW4pbFciHyuwn4wUdSbcFxh","decimals":8}]},{"symbol":"KP3R","displayName":"Keep3rV1 (Portal)","logo":"","coinGeckoId":"keep3rv1","nativeDetails":{"chainId":2,"address":"0x1ceb5cb57c4d4e2b2433641b95dd330a33185a44","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3a2VW9t5N6p4baMW3M6yLH1UJ9imMt7VsyUk6ouXPVLq","decimals":8}]},{"symbol":"LDO","displayName":"Lido DAO (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p/logo.png","coinGeckoId":"lido-dao","nativeDetails":{"chainId":2,"address":"0x5a98fcbea516cf06857215779fd812ca3bef1b32","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p","decimals":8},{"chainId":4,"address":"0x986854779804799C1d68867F5E03e601E781e41b","decimals":18}]},{"symbol":"LINK","displayName":"Chainlink (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2wpTofQ8SkACrkZWrZDjXPitYa8AwWgX8AfxdeBRRVLX/logo.png","coinGeckoId":"chainlink","nativeDetails":{"chainId":2,"address":"0x514910771af9ca656af840dff83e8264ecf986ca","decimals":18},"wrappedDetails":[{"chainId":1,"address":"2wpTofQ8SkACrkZWrZDjXPitYa8AwWgX8AfxdeBRRVLX","decimals":8}]},{"symbol":"LRC","displayName":"Loopring (Portal)","logo":"","coinGeckoId":"loopring","nativeDetails":{"chainId":2,"address":"0xbbbbca6a901c926f240b89eacb641d8aec7aeafd","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HCTVFTzHL21a1dPzKxAUeWwqbE8QMUyvgChFDL4XYoi1","decimals":8}]},{"symbol":"LUA","displayName":"LuaSwap (Portal)","logo":"","coinGeckoId":"luaswap","nativeDetails":{"chainId":2,"address":"0xb1f66997a5760428d3a87d68b90bfe0ae64121cc","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5Wc4U1ZoQRzF4tPdqKQzBwRSjYe8vEf3EvZMuXgtKUW6","decimals":8}]},{"symbol":"MANA","displayName":"Decentraland (Portal)","logo":"https://assets.coingecko.com/coins/images/878/thumb/decentraland-mana.png","coinGeckoId":"decentraland","nativeDetails":{"chainId":2,"address":"0x0F5D2fB29fb7d3CFeE444a200298f468908cC942","decimals":18},"wrappedDetails":[{"chainId":1,"address":"7dgHoN8wBZCc5wbnQ2C47TDnBMAxG4Q5L3KjP67z8kNi","decimals":8}]},{"symbol":"MATH","displayName":"MATH Token (Portal)","logo":"","coinGeckoId":"math","nativeDetails":{"chainId":2,"address":"0x08d967bb0134f2d07f7cfb6e246680c53927dd30","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CaGa7pddFXS65Gznqwp42kBhkJQdceoFVT7AQYo8Jr8Q","decimals":8}]},{"symbol":"MATICet","displayName":"MATIC (Portal from Ethereum)","logo":"","coinGeckoId":"polygon","nativeDetails":{"chainId":2,"address":"0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"C7NNPWuZCNjZBfW5p6JvGsR8pUdsRpEdP1ZAhnoDwj7h","decimals":8}]},{"symbol":"MIMet","displayName":"Magic Internet Money (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HRQke5DKdDo3jV7wnomyiM8AA3EzkVnxMDdo2FQ5XUe1/logo.png","coinGeckoId":"magic-internet-money","nativeDetails":{"chainId":2,"address":"0x99d8a9c45b2eca8864373a26d1459e3dff1e17f3","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HRQke5DKdDo3jV7wnomyiM8AA3EzkVnxMDdo2FQ5XUe1","decimals":8}]},{"symbol":"NXM","displayName":"Nexus Mutual (Portal)","logo":"","coinGeckoId":"nexus-mutual","nativeDetails":{"chainId":2,"address":"0xd7c49cee7e9188cca6ad8ff264c1da2e69d4cf3b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Aqs5ydqKXEK2cjotDXxHmk8N9PknqQ5q4ZED4ymY1eeh","decimals":8}]},{"symbol":"ORION","displayName":"Orion Money (Portal)","logo":"https://assets.coingecko.com/coins/images/18630/small/YtrqPIWc.png","coinGeckoId":"orion-money","nativeDetails":{"chainId":2,"address":"0x727f064a78dc734d33eec18d5370aef32ffd46e4","decimals":18},"wrappedDetails":[{"chainId":4,"address":"0x3dcB18569425930954feb191122e574b87F66abd","decimals":18},{"chainId":5,"address":"0x5E0294Af1732498C77F8dB015a2d52a76298542B","decimals":18}]},{"symbol":"PAXG","displayName":"Paxos Gold (Portal)","logo":"","coinGeckoId":"pax-gold","nativeDetails":{"chainId":2,"address":"0x45804880de22913dafe09f4980848ece6ecbaf78","decimals":18},"wrappedDetails":[{"chainId":1,"address":"C6oFsE8nXRDThzrMEQ5SxaNFGKoyyfWDDVPw37JKvPTe","decimals":8}]},{"symbol":"PEOPLE","displayName":"ConstitutionDAO (Portal)","logo":"","coinGeckoId":"constitutiondao","nativeDetails":{"chainId":2,"address":"0x7a58c0be72be218b41c608b7fe7c5bb630736c71","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CobcsUrt3p91FwvULYKorQejgsm5HoQdv5T8RUZ6PnLA","decimals":8}]},{"symbol":"PERP","displayName":"Perpetual Protocol (Portal)","logo":"","coinGeckoId":"perpetual-protocol","nativeDetails":{"chainId":2,"address":"0xbc396689893d065f41bc2c6ecbee5e0085233447","decimals":18},"wrappedDetails":[{"chainId":1,"address":"9BsnSWDPfbusseZfnXyZ3un14CyPMZYvsKjWY3Y8Gbqn","decimals":8}]},{"symbol":"RGT","displayName":"Rari Governance Token (Portal)","logo":"","coinGeckoId":"rari-governance-token","nativeDetails":{"chainId":2,"address":"0xd291e7a03283640fdc51b121ac401383a46cc623","decimals":18},"wrappedDetails":[{"chainId":1,"address":"ASk8bss7PoxfFVJfXnSJepj9KupTX15QaRnhdjs6DdYe","decimals":8}]},{"symbol":"RPL","displayName":"Rocket Pool (Portal)","logo":"","coinGeckoId":"rocket-pool","nativeDetails":{"chainId":2,"address":"0xd33526068d116ce69f19a9ee46f0bd304f21a51f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"HUCyuyqESEUV4YWTKFvvB4JiQLqoovscTBpRXfGzW4Wx","decimals":8}]},{"symbol":"RSR","displayName":"Reserve Rights (Portal)","logo":"","coinGeckoId":"reserve-rights-token","nativeDetails":{"chainId":2,"address":"0x8762db106B2c2A0bccB3A80d1Ed41273552616E8","decimals":18},"wrappedDetails":[{"chainId":1,"address":"DkbE8U4gSRuGHcVMA1LwyZPYUjYbfEbjW8DMR3iSXBzr","decimals":8}]},{"symbol":"SAND","displayName":"The Sandbox (Portal)","logo":"https://gemini.com/images/currencies/icons/default/sand.svg","coinGeckoId":"the-sandbox","nativeDetails":{"chainId":2,"address":"0x3845badAde8e6dFF049820680d1F14bD3903a5d0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"49c7WuCZkQgc3M4qH8WuEUNXfgwupZf1xqWkDQ7gjRGt","decimals":8}]},{"symbol":"SHIB","displayName":"Shiba Inu (Portal)","logo":"https://etherscan.io/token/images/shibatoken_32.png","coinGeckoId":"shiba-inu","nativeDetails":{"chainId":2,"address":"0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CiKu4eHsVrc1eueVQeHn7qhXTcVu95gSQmBpX4utjL9z","decimals":8},{"chainId":4,"address":"0xb1547683DA678f2e1F003A780143EC10Af8a832B","decimals":18}]},{"symbol":"SLP","displayName":"Smooth Love Potion (Portal)","logo":"","coinGeckoId":"smooth-love-potion","nativeDetails":{"chainId":2,"address":"0xcc8fa225d80b9c7d42f96e9570156c65d6caaa25","decimals":0},"wrappedDetails":[{"chainId":1,"address":"4hpngEp1v3CXpeKB81Gw4sv7YvwUVRKvY3SGag9ND8Q4","decimals":8}]},{"symbol":"SNX","displayName":"Synthetix Network Token (Portal)","logo":"","coinGeckoId":"synthetix-network-token","nativeDetails":{"chainId":2,"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8cTNUtcV2ueC3royJ642uRnvTxorJAWLZc58gxAo7y56","decimals":8}]},{"symbol":"SOS","displayName":"OpenDAO (Portal)","logo":"","coinGeckoId":"opendao","nativeDetails":{"chainId":2,"address":"0x3b484b82567a09e2588a13d54d032153f0c0aee0","decimals":18},"wrappedDetails":[{"chainId":1,"address":"6Q5fvsJ6kgAFmisgDqqyaFd9FURYzHf8MCUbpAUaGZnE","decimals":8}]},{"symbol":"SPELL","displayName":"Spell Token (Portal)","logo":"","coinGeckoId":"spell-token","nativeDetails":{"chainId":2,"address":"0x090185f2135308bad17527004364ebcc2d37e5f6","decimals":18},"wrappedDetails":[{"chainId":1,"address":"BCsFXYm81iqXyYmrLKgAp3AePcgLHnirb8FjTs6sjM7U","decimals":8}]},{"symbol":"SRMet","displayName":"Serum (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png","coinGeckoId":"serum","nativeDetails":{"chainId":2,"address":"0x476c5e26a75bd202a9683ffd34359c0cc15be0ff","decimals":6},"wrappedDetails":[{"chainId":1,"address":"xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG","decimals":6},{"chainId":4,"address":"0xd63CDf02853D759831550fAe7dF8FFfE0B317b39","decimals":6}]},{"symbol":"SUSHI","displayName":"SushiToken (Portal)","logo":"https://etherscan.io/token/images/sushitoken_32.png","coinGeckoId":"sushi","nativeDetails":{"chainId":2,"address":"0x6b3595068778dd592e39a122f4f5a5cf09c90fe2","decimals":18},"wrappedDetails":[{"chainId":1,"address":"ChVzxWRmrTeSgwd3Ui3UumcN8KX7VK3WaD4KGeSKpypj","decimals":8},{"chainId":4,"address":"0x3524fd7488fdb1F4723BBc22C9cbD1Bf89f46E3B","decimals":18}]},{"symbol":"SWAG","displayName":"SWAG Finance (Portal)","logo":"","coinGeckoId":"swag-finance","nativeDetails":{"chainId":2,"address":"0x87edffde3e14c7a66c9b9724747a1c5696b742e6","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5hcdG6NjQwiNhVa9bcyaaDsCyA1muPQ6WRzQwHfgeeKo","decimals":8}]},{"symbol":"SXP","displayName":"Swipe (Portal)","logo":"","coinGeckoId":"swipe","nativeDetails":{"chainId":2,"address":"0x8ce9137d39326ad0cd6491fb5cc0cba0e089b6a9","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3CyiEDRehaGufzkpXJitCP5tvh7cNhRqd9rPBxZrgK5z","decimals":8}]},{"symbol":"TOKE","displayName":"Tokemak (Portal)","logo":"","coinGeckoId":"tokemak","nativeDetails":{"chainId":2,"address":"0x2e9d63788249371f1dfc918a52f8d799f4a38c94","decimals":18},"wrappedDetails":[{"chainId":1,"address":"3EQ6LqLkiFcoxTeGEsHMFpSLWNVPe9yT7XPX2HYSFyxX","decimals":8}]},{"symbol":"TRIBE","displayName":"Tribe (Portal)","logo":"","coinGeckoId":"tribe","nativeDetails":{"chainId":2,"address":"0xc7283b66eb1eb5fb86327f08e1b5816b0720212b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"DPgNKZJAG2w1S6vfYHDBT62R4qrWWH5f45CnxtbQduZE","decimals":8}]},{"symbol":"UBXT","displayName":"UpBots (Portal)","logo":"","coinGeckoId":"upbots","nativeDetails":{"chainId":2,"address":"0x8564653879a18c560e7c0ea0e084c516c62f5653","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FTtXEUosNn6EKG2SQtfbGuYB4rBttreQQcoWn1YDsuTq","decimals":8}]},{"symbol":"UFO","displayName":"UFO Gaming (Portal)","logo":"","coinGeckoId":"ufo-gaming","nativeDetails":{"chainId":2,"address":"0x249e38ea4102d0cf8264d3701f1a0e39c4f2dc3b","decimals":18},"wrappedDetails":[{"chainId":1,"address":"GWdkYFnXnSJAsCBvmsqFLiPPe2tpvXynZcJdxf11Fu3U","decimals":8}]},{"symbol":"UNI","displayName":"Uniswap (Portal)","logo":"https://etherscan.io/token/images/uniswap_32.png","coinGeckoId":"uniswap","nativeDetails":{"chainId":2,"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8FU95xFJhUUkyyCLU13HSzDLs7oC4QZdXQHL6SCeab36","decimals":8}]},{"symbol":"USDCet","displayName":"USD Coin (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":2,"address":"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48","decimals":6},"wrappedDetails":[{"chainId":1,"address":"A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM","decimals":6},{"chainId":4,"address":"0xB04906e95AB5D797aDA81508115611fee694c2b3","decimals":6},{"chainId":5,"address":"0x4318cb63a2b8edf2de971e2f17f77097e499459d","decimals":6},{"chainId":6,"address":"0xB24CA28D4e2742907115fECda335b40dbda07a4C","decimals":6},{"chainId":7,"address":"0xE8A638b3B7565Ee7c5eb9755E58552aFc87b94DD","decimals":6},{"chainId":10,"address":"0x2Ec752329c3EB419136ca5e4432Aa2CDb1eA23e6","decimals":6},{"chainId":14,"address":"0x37f750B7cC259A2f741AF45294f6a16572CF5cAd","decimals":6}]},{"symbol":"USDK","displayName":"USDK (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F/logo.png","coinGeckoId":"usdk","nativeDetails":{"chainId":2,"address":"0x1c48f86ae57291f7686349f12601910bd8d470bb","decimals":18},"wrappedDetails":[{"chainId":1,"address":"43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F","decimals":8}]},{"symbol":"USDTet","displayName":"Tether USD (Portal from Ethereum)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg","coinGeckoId":"tether","nativeDetails":{"chainId":2,"address":"0xdac17f958d2ee523a2206206994597c13d831ec7","decimals":6},"wrappedDetails":[{"chainId":1,"address":"Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1","decimals":6},{"chainId":4,"address":"0x524bC91Dc82d6b90EF29F76A3ECAaBAffFD490Bc","decimals":6},{"chainId":5,"address":"0x9417669fBF23357D2774e9D421307bd5eA1006d2","decimals":6},{"chainId":7,"address":"0xdC19A122e268128B5eE20366299fc7b5b199C8e3","decimals":6}]},{"symbol":"WBTC","displayName":"Wrapped BTC (Portal)","logo":"https://etherscan.io/token/images/wbtc_28.png?v=1","coinGeckoId":"wrapped-bitcoin","nativeDetails":{"chainId":2,"address":"0x2260fac5e5542a773aa44fbcfedf7c193bc2c599","decimals":8},"wrappedDetails":[{"chainId":1,"address":"3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh","decimals":8},{"chainId":5,"address":"0x5D49c278340655B56609FdF8976eb0612aF3a0C3","decimals":8},{"chainId":7,"address":"0xd43ce0aa2a29DCb75bDb83085703dc589DE6C7eb","decimals":8}]},{"symbol":"YFI","displayName":"yearn.finance (Portal)","logo":"","coinGeckoId":"yearn-finance","nativeDetails":{"chainId":2,"address":"0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e","decimals":18},"wrappedDetails":[{"chainId":1,"address":"BXZX2JRJFjvKazM1ibeDFxgAngKExb74MRXzXKvgikxX","decimals":8}]},{"symbol":"YGG","displayName":"Yield Guild Games (Portal)","logo":"","coinGeckoId":"yield-guild-games","nativeDetails":{"chainId":2,"address":"0x25f8087ead173b73d6e8b84329989a8eea16cf73","decimals":18},"wrappedDetails":[{"chainId":1,"address":"EzZp7LRN1xwu3QsB2RJRrWwEGjJGsuWzuMCeQDB3NSPK","decimals":8}]},{"symbol":"ZRX","displayName":"0x (Portal)","logo":"","coinGeckoId":"0x","nativeDetails":{"chainId":2,"address":"0xe41d2489571d322189246dafa5ebde1f4699f498","decimals":18},"wrappedDetails":[{"chainId":1,"address":"GJa1VeEYLTRoHbaeqcxfzHmjGCGtZGF3CUqxv9znZZAY","decimals":8}]},{"symbol":"agEUR","displayName":"agEUR (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1/logo.svg","coinGeckoId":"ageur","nativeDetails":{"chainId":2,"address":"0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1","decimals":8}]},{"symbol":"gOHM","displayName":"Governance OHM (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FUGsN8H74WjRBBMfQWcf9Kk32gebA9VnNaGxqwcVvUW7/logo.png","coinGeckoId":"governance-ohm","nativeDetails":{"chainId":2,"address":"0x0ab87046fbb341d058f17cbc4c1133f25a20a52f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FUGsN8H74WjRBBMfQWcf9Kk32gebA9VnNaGxqwcVvUW7","decimals":8}]},{"symbol":"ibBTC","displayName":"Interest Bearing Bitcoin (Portal)","logo":"https://etherscan.io/token/images/badgeribtc_32.png","coinGeckoId":"interest-bearing-bitcoin","nativeDetails":{"chainId":2,"address":"0xc4e15973e6ff2a35cc804c2cf9d2a1b817a8b40f","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi","decimals":8}]},{"symbol":"stETH","displayName":"Lido Staked Ether (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/H2mf9QNdU2Niq6QR7367Ua2trBsvscLyX5bz7R3Pw5sE/logo.png","coinGeckoId":"lido-staked-ether","nativeDetails":{"chainId":2,"address":"0xae7ab96520de3a18e5e111b5eaab095312d7fe84","decimals":18},"wrappedDetails":[{"chainId":1,"address":"H2mf9QNdU2Niq6QR7367Ua2trBsvscLyX5bz7R3Pw5sE","decimals":8}]},{"symbol":"BNB","displayName":"Binance Coin (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa/logo.png","coinGeckoId":"binance-coin","nativeDetails":{"chainId":4,"address":"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c","decimals":18},"wrappedDetails":[{"chainId":1,"address":"9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa","decimals":8},{"chainId":2,"address":"0x418D75f65a02b3D53B2418FB8E1fe493759c7605","decimals":18},{"chainId":5,"address":"0xecdcb5b88f8e3c15f95c720c51c71c9e2080525d","decimals":18},{"chainId":6,"address":"0x442F7f22b1EE2c842bEAFf52880d4573E9201158","decimals":18},{"chainId":7,"address":"0xd79Ef9A91b56c690C7b80570a3c060678667f469","decimals":18}]},{"symbol":"BUSDbs","displayName":"Binance USD (Portal from BSC)","logo":"https://etherscan.io/token/images/binanceusd_32.png","coinGeckoId":"binance-usd","nativeDetails":{"chainId":4,"address":"0xe9e7cea3dedca5984780bafc599bd69add087d56","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2","decimals":8},{"chainId":2,"address":"0x7B4B0B9b024109D182dCF3831222fbdA81369423","decimals":18},{"chainId":5,"address":"0xa8d394fe7380b8ce6145d5f85e6ac22d4e91acde","decimals":18},{"chainId":6,"address":"0xA41a6c7E25DdD361343e8Cb8cFa579bbE5eEdb7a","decimals":18},{"chainId":7,"address":"0xf6568FD76f9fcD1f60f73b730F142853c5eF627E","decimals":18}]},{"symbol":"CAKE","displayName":"PancakeSwap Token (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/J8LKx7pr9Zxh9nMhhT7X3EBmj5RzuhFrHKyJAe2F2i9S/logo.png","coinGeckoId":"pancakeswap","nativeDetails":{"chainId":4,"address":"0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82","decimals":18},"wrappedDetails":[{"chainId":1,"address":"J8LKx7pr9Zxh9nMhhT7X3EBmj5RzuhFrHKyJAe2F2i9S","decimals":8},{"chainId":2,"address":"0x7c8161545717a334f3196e765d9713f8042EF338","decimals":18},{"chainId":6,"address":"0x98a4d09036Cc5337810096b1D004109686E56Afc","decimals":18}]},{"symbol":"USDCbs","displayName":"USD Coin (Portal from BSC)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":4,"address":"0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d","decimals":18},"wrappedDetails":[{"chainId":1,"address":"FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA","decimals":8},{"chainId":2,"address":"0x7cd167B101D2808Cfd2C45d17b2E7EA9F46b74B6","decimals":18},{"chainId":6,"address":"0x6145E8a910aE937913426BF32De2b26039728ACF","decimals":18},{"chainId":7,"address":"0x4cA2A3De42eabC8fd8b0AC46127E64DB08b9150e","decimals":18}]},{"symbol":"USDTbs","displayName":"Tether USD (Portal from BSC)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg","coinGeckoId":"tether","nativeDetails":{"chainId":4,"address":"0x55d398326f99059fF775485246999027B3197955","decimals":18},"wrappedDetails":[{"chainId":1,"address":"8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv","decimals":8},{"chainId":2,"address":"0xDe60aDfDdAAbaAAC3dAFa57B26AcC91Cb63728c4","decimals":18},{"chainId":6,"address":"0xA67BCC0D06d7d13A13A2AE30bF30f1B434f5a28B","decimals":18},{"chainId":7,"address":"0x366EF31C8dc715cbeff5fA54Ad106dC9c25C6153","decimals":18}]},{"symbol":"LUNA","displayName":"LUNA (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W/logo.png","coinGeckoId":"terra-luna","nativeDetails":{"chainId":3,"address":"uluna","decimals":6},"wrappedDetails":[{"chainId":1,"address":"F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W","decimals":6},{"chainId":2,"address":"0xbd31ea8212119f94a611fa969881cba3ea06fa3d","decimals":6},{"chainId":4,"address":"0x156ab3346823B651294766e23e6Cf87254d68962","decimals":6},{"chainId":5,"address":"0x9cd6746665D9557e1B9a775819625711d0693439","decimals":6},{"chainId":6,"address":"0x70928E5B188def72817b7775F0BF6325968e563B","decimals":6},{"chainId":7,"address":"0x4F43717B20ae319Aa50BC5B2349B93af5f7Ac823","decimals":6},{"chainId":10,"address":"0x593AE1d34c8BD7587C11D539E4F42BFf242c82Af","decimals":6},{"chainId":9,"address":"0x12302fbE05a7e833f87d4B7843F58d19BE4FdE3B","decimals":6}]},{"symbol":"UST","displayName":"UST (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i/logo.png","coinGeckoId":"terra-usd","nativeDetails":{"chainId":3,"address":"uusd","decimals":6},"wrappedDetails":[{"chainId":1,"address":"9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i","decimals":6},{"chainId":2,"address":"0xa693B19d2931d498c5B318dF961919BB4aee87a5","decimals":6},{"chainId":4,"address":"0x3d4350cD54aeF9f9b2C29435e0fa809957B3F30a","decimals":6},{"chainId":5,"address":"0xE6469Ba6D2fD6130788E0eA9C0a0515900563b59","decimals":6},{"chainId":6,"address":"0xb599c3590F42f8F995ECfa0f85D2980B76862fc1","decimals":6},{"chainId":7,"address":"0xa1E73c01E0cF7930F5e91CB291031739FE5Ad6C2","decimals":6},{"chainId":10,"address":"0x846e4D51d7E2043C1a87E0Ab7490B93FB940357b","decimals":6},{"chainId":9,"address":"0x8D07bBb478B84f7E940e97C8e9cF7B3645166b03","decimals":6}]},{"symbol":"aUST","displayName":"AnchorUST (Portal)","logo":"","coinGeckoId":"anchorust","nativeDetails":{"chainId":3,"address":"terra1hzh9vpxhsk8253se0vv5jj6etdvxu3nv8z07zu","decimals":6},"wrappedDetails":[{"chainId":1,"address":"4CsZsUCoKFiaGyU7DEVDayqeVtG8iqgGDR6RjzQmzQao","decimals":6},{"chainId":4,"address":"0x8b04E56A8cd5f4D465b784ccf564899F30Aaf88C","decimals":6}]},{"symbol":"DAIpo","displayName":"DAI (Portal from Polygon)","logo":"","coinGeckoId":"dai","nativeDetails":{"chainId":5,"address":"0x8f3cf7ad23cd3cadbd9735aff958023239c6a063","decimals":18},"wrappedDetails":[{"chainId":1,"address":"4Fo67MYQpVhZj9R7jQTd63FPAnWbPpaafAUxsMGX2geP","decimals":8}]},{"symbol":"MATICpo","displayName":"MATIC (Portal from Polygon)","logo":"","coinGeckoId":"polygon","nativeDetails":{"chainId":5,"address":"0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270","decimals":18},"wrappedDetails":[{"chainId":1,"address":"Gz7VkD4MacbEB6yC5XD3HcumEiYx2EtDYYrfikGsvopG","decimals":8},{"chainId":2,"address":"0x7c9f4C87d911613Fe9ca58b579f737911AAD2D43","decimals":18},{"chainId":4,"address":"0xc836d8dC361E44DbE64c4862D55BA041F88Ddd39","decimals":18},{"chainId":6,"address":"0xf2f13f0B7008ab2FA4A2418F4ccC3684E49D20Eb","decimals":18}]},{"symbol":"QUICK","displayName":"Quickswap (Portal)","logo":"","coinGeckoId":"quickswap","nativeDetails":{"chainId":5,"address":"0x831753dd7087cac61ab5644b308642cc1c33dc13","decimals":18},"wrappedDetails":[{"chainId":1,"address":"5njTmK53Ss5jkiHHZvzabVzZj6ztu6WYWpAPYgbVnbjs","decimals":8}]},{"symbol":"USDCpo","displayName":"USD Coin (PoS) (Portal from Polygon)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":5,"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","decimals":6},"wrappedDetails":[{"chainId":1,"address":"E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M","decimals":6},{"chainId":2,"address":"0x566957eF80F9fd5526CD2BEF8BE67035C0b81130","decimals":6},{"chainId":4,"address":"0x672147dD47674757C457eB155BAA382cc10705Dd","decimals":6},{"chainId":6,"address":"0x543672E9CBEC728CBBa9C3Ccd99ed80aC3607FA8","decimals":6},{"chainId":7,"address":"0x3E62a9c3aF8b810dE79645C4579acC8f0d06a241","decimals":6}]},{"symbol":"USDTpo","displayName":"Tether USD (PoS) (Portal from Polygon)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1/logo.png","coinGeckoId":"tether","nativeDetails":{"chainId":5,"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6},"wrappedDetails":[{"chainId":1,"address":"5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1","decimals":6},{"chainId":7,"address":"0xFffD69E757d8220CEA60dc80B9Fe1a30b58c94F3","decimals":6}]},{"symbol":"AVAX","displayName":"AVAX (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/KgV1GvrHQmRBY8sHQQeUKwTm2r2h8t4C8qt12Cw1HVE/logo.png","coinGeckoId":"avalanche","nativeDetails":{"chainId":6,"address":"0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7","decimals":18},"wrappedDetails":[{"chainId":1,"address":"KgV1GvrHQmRBY8sHQQeUKwTm2r2h8t4C8qt12Cw1HVE","decimals":8},{"chainId":2,"address":"0x85f138bfEE4ef8e540890CFb48F620571d67Eda3","decimals":18},{"chainId":4,"address":"0x96412902aa9aFf61E13f085e70D3152C6ef2a817","decimals":18},{"chainId":5,"address":"0x7Bb11E7f8b10E9e571E5d8Eace04735fDFB2358a","decimals":18},{"chainId":7,"address":"0x32847e63E99D3a044908763056e25694490082F8","decimals":18}]},{"symbol":"JOE","displayName":"JoeToken (Portal)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CriXdFS9iRAYbGEQiTcUqbWwG9RBmYt5B6LwTnoJ61Sm/logo.png","coinGeckoId":"joe","nativeDetails":{"chainId":6,"address":"0x6e84a6216ea6dacc71ee8e6b0a5b7322eebc0fdd","decimals":18},"wrappedDetails":[{"chainId":1,"address":"CriXdFS9iRAYbGEQiTcUqbWwG9RBmYt5B6LwTnoJ61Sm","decimals":8}]},{"symbol":"USDCav","displayName":"USD Coin (Portal from Avalanche)","logo":"https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png","coinGeckoId":"usd-coin","nativeDetails":{"chainId":6,"address":"0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664","decimals":6},"wrappedDetails":[{"chainId":1,"address":"AGqKX7F4mqJ8x2mUQVangJb5pWQJApaKoUfe5gXM53CV","decimals":8},{"chainId":4,"address":"0xc1F47175d96Fe7c4cD5370552e5954f384E3C791","decimals":6},{"chainId":7,"address":"0x05CbE6319Dcc937BdbDf0931466F4fFd0d392B47","decimals":6}]},{"symbol":"USDTav","displayName":"Tether USD (Portal from Avalanche)","logo":"","coinGeckoId":"tether","nativeDetails":{"chainId":6,"address":"0xc7198437980c041c805a1edcba50c1ce5db95118","decimals":6},"wrappedDetails":[{"chainId":1,"address":"B2wfeYz5VtBnQVrX4M8F6FeDrprVrzKPws5qg1in8bzR","decimals":8},{"chainId":4,"address":"0x2B90E061a517dB2BbD7E39Ef7F733Fd234B494CA","decimals":6},{"chainId":7,"address":"0x05832a0905E516f29344ADBa1c2052a788B10129","decimals":6}]},{"symbol":"ROSE","displayName":"ROSE (Portal)","logo":"https://assets.coingecko.com/coins/images/13162/small/rose.png","coinGeckoId":"oasis-network","nativeDetails":{"chainId":7,"address":"0x21C718C22D52d0F3a789b752D4c2fD5908a8A733","decimals":18},"wrappedDetails":[{"chainId":1,"address":"S3SQfD6RheMXQ3EEYn1Z5sJsbtwfXdt7tSAVXPQFtYo","decimals":8},{"chainId":2,"address":"0x26B80FBfC01b71495f477d5237071242e0d959d7","decimals":18},{"chainId":4,"address":"0x6c6D604D3f07aBE287C1A3dF0281e999A83495C0","decimals":18},{"chainId":6,"address":"0x12AF5C1a232675f62F405b5812A80e7a6F75D746","decimals":18}]},{"symbol":"SWEAT","displayName":"Sweat Economy","logo":"https://assets.coingecko.com/coins/images/25057/small/fhD9Xs16_400x400.jpg?1649947000","coinGeckoId":"sweatcoin","nativeDetails":{"chainId":15,"address":"token.sweat","decimals":18},"wrappedDetails":[{"chainId":2,"address":"0xB4b9DC1C77bdbb135eA907fd5a08094d98883A35","decimals":18},{"chainId":4,"address":"0x510Ad22d8C956dCC20f68932861f54A591001283","decimals":18}]}] \ No newline at end of file From da09132aad0c659a1cd8b03512f371567c61d240 Mon Sep 17 00:00:00 2001 From: wormat Date: Fri, 14 Oct 2022 17:32:48 +0200 Subject: [PATCH 17/24] chore(ui): Update TS/ESLint configs for scripts --- apps/ui/.eslintrc.cjs | 10 +++++++++- apps/ui/scripts/tsconfig.json | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 apps/ui/scripts/tsconfig.json diff --git a/apps/ui/.eslintrc.cjs b/apps/ui/.eslintrc.cjs index 9eb2bca13..7d62d6d22 100644 --- a/apps/ui/.eslintrc.cjs +++ b/apps/ui/.eslintrc.cjs @@ -8,7 +8,7 @@ module.exports = { extends: ["@swim-io/eslint-config"], }, { - files: ["**/*.{cts,mts,ts,tsx}"], + files: ["src/**/*.{cts,mts,ts,tsx}"], extends: ["@swim-io/eslint-config/react"], parserOptions: { // Make sure correct `tsconfig.json` is found in monorepo @@ -85,5 +85,13 @@ module.exports = { }, ], }, + { + files: ["scripts/*.{cts,mts,ts,tsx}"], + extends: ["@swim-io/eslint-config"], + parserOptions: { + // Make sure correct `tsconfig.json` is found in monorepo + tsconfigRootDir: `${__dirname}/scripts`, + }, + }, ], }; diff --git a/apps/ui/scripts/tsconfig.json b/apps/ui/scripts/tsconfig.json new file mode 100644 index 000000000..04746c616 --- /dev/null +++ b/apps/ui/scripts/tsconfig.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@swim-io/tsconfig/tsconfig-base.json", + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "baseUrl": "./", + "noEmit": true + }, + "include": ["./"], + "ts-node": { + "compilerOptions": { + "module": "commonjs" + } + } +} From c892fb5642dd0c2c135fd3e5e84eece6618e6de0 Mon Sep 17 00:00:00 2001 From: wormat Date: Fri, 14 Oct 2022 17:40:48 +0200 Subject: [PATCH 18/24] style(ui): Fix lint issues --- apps/ui/scripts/processWormholeTokenData.ts | 10 +++++++--- apps/ui/src/components/WormholeForm.tsx | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/ui/scripts/processWormholeTokenData.ts b/apps/ui/scripts/processWormholeTokenData.ts index e9c8d09f5..0ba74925f 100644 --- a/apps/ui/scripts/processWormholeTokenData.ts +++ b/apps/ui/scripts/processWormholeTokenData.ts @@ -1,5 +1,7 @@ -import { CHAINS, ChainId, isEVMChain } from "@certusone/wormhole-sdk"; import fs from "fs"; + +import type { ChainId } from "@certusone/wormhole-sdk"; +import { CHAINS, isEVMChain } from "@certusone/wormhole-sdk"; import { parse } from "csv-parse"; type Source = @@ -166,7 +168,6 @@ const processRecord = ({ }); const main = async () => { - const processedRecords: WormholeToken[] = []; const parser = fs .createReadStream(`${__dirname}/../tmp/wormholeTokenData.csv`) .pipe( @@ -176,13 +177,16 @@ const main = async () => { }), ); + // eslint-disable-next-line functional/prefer-readonly-type + const processedRecords: WormholeToken[] = []; for await (const record of parser) { - const processedRecord = processRecord(record); + const processedRecord = processRecord(record as CsvRecord); const supportedChains = [ processedRecord.nativeDetails, ...processedRecord.wrappedDetails, ].filter((details) => isChainSupported(details.chainId)); if (supportedChains.length >= 2) { + // eslint-disable-next-line functional/immutable-data processedRecords.push(processedRecord); } } diff --git a/apps/ui/src/components/WormholeForm.tsx b/apps/ui/src/components/WormholeForm.tsx index b036e04fa..05d26f949 100644 --- a/apps/ui/src/components/WormholeForm.tsx +++ b/apps/ui/src/components/WormholeForm.tsx @@ -149,14 +149,14 @@ export const WormholeForm = (): ReactElement => { {txResults.length > 0 && ( <> -

Tx results

+

{"Tx results"}

- - + + {txResults.map(({ chainId, txId }) => ( - + From ab61bd27c8bd3a2e87d108eadc97332e48968bb8 Mon Sep 17 00:00:00 2001 From: wormat Date: Fri, 14 Oct 2022 17:41:39 +0200 Subject: [PATCH 19/24] fix(ui): Catch errors properly in scraper script --- apps/ui/scripts/processWormholeTokenData.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/ui/scripts/processWormholeTokenData.ts b/apps/ui/scripts/processWormholeTokenData.ts index 0ba74925f..36a8c8c4e 100644 --- a/apps/ui/scripts/processWormholeTokenData.ts +++ b/apps/ui/scripts/processWormholeTokenData.ts @@ -191,11 +191,11 @@ const main = async () => { } } - return new Promise((resolve) => { + return new Promise((resolve, reject) => { fs.writeFile( `${__dirname}/../src/config/wormholeTokens.json`, JSON.stringify(processedRecords), - resolve, + (err) => (err ? reject(err) : resolve()), ); }); }; From fd2751c71c8d4635a39095fe02b88c5f6ac53035 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 20 Oct 2022 16:38:41 +0200 Subject: [PATCH 20/24] refactor(ui): Update wormhole hooks for SDK client changes --- .../hooks/wormhole/useTransferEvmToEvmMutation.ts | 12 +++++------- .../hooks/wormhole/useTransferEvmToSolanaMutation.ts | 8 +++----- .../hooks/wormhole/useTransferSolanaToEvmMutation.ts | 8 ++++---- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts b/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts index 5323115a2..c8f002136 100644 --- a/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts +++ b/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts @@ -98,15 +98,13 @@ export const useTransferEvmToEvmMutation = () => { }), ); - const transferTxReceipt = await sourceClient.getTxReceiptOrThrow( - transferResponse, - ); + const transferTx = await sourceClient.getTx(transferResponse); onTxResult({ chainId: sourceDetails.chainId, - txId: transferTxReceipt.transactionHash, + txId: transferTx.id, }); const sequence = parseSequenceFromLogEth( - transferTxReceipt, + transferTx.receipt, sourceChain.wormhole.bridge, ); const retries = getWormholeRetries(sourceDetails.chainId); @@ -131,10 +129,10 @@ export const useTransferEvmToEvmMutation = () => { `Transaction not found: (unlock/mint on ${targetEcosystemId})`, ); } - const evmReceipt = await targetClient.getTxReceiptOrThrow(redeemResponse); + const redeemTx = await targetClient.getTx(redeemResponse); onTxResult({ chainId: targetDetails.chainId, - txId: evmReceipt.transactionHash, + txId: redeemTx.id, }); }, ); diff --git a/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts b/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts index 1aaa05e7f..5675638f3 100644 --- a/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts +++ b/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts @@ -113,15 +113,13 @@ export const useTransferEvmToSolanaMutation = () => { }), ); - const transferTxReceipt = await evmClient.getTxReceiptOrThrow( - transferResponse, - ); + const transferTx = await evmClient.getTx(transferResponse); onTxResult({ chainId: sourceDetails.chainId, - txId: transferTxReceipt.transactionHash, + txId: transferTx.id, }); const sequence = parseSequenceFromLogEth( - transferTxReceipt, + transferTx.receipt, evmChain.wormhole.bridge, ); diff --git a/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts b/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts index 87f4d8e70..f1482b9a3 100644 --- a/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts +++ b/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts @@ -92,8 +92,8 @@ export const useTransferSolanaToEvmMutation = () => { txId: transferSplTokenTxId, }); - const parsedTx = await solanaClient.getParsedTx(transferSplTokenTxId); - const sequence = parseSequenceFromLogSolana(parsedTx); + const solanaTx = await solanaClient.getTx(transferSplTokenTxId); + const sequence = parseSequenceFromLogSolana(solanaTx.parsedTx); const emitterAddress = await getEmitterAddressSolana( solanaChain.wormhole.portal, ); @@ -118,10 +118,10 @@ export const useTransferSolanaToEvmMutation = () => { `Transaction not found: (unlock/mint on ${evmChain.ecosystem})`, ); } - const evmReceipt = await evmClient.getTxReceiptOrThrow(redeemResponse); + const evmTx = await evmClient.getTx(redeemResponse); onTxResult({ chainId: targetDetails.chainId, - txId: evmReceipt.transactionHash, + txId: evmTx.id, }); }, ); From 9e00f2761aeb6e72fa8e0e203900a2908b30079f Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 20 Oct 2022 18:09:35 +0200 Subject: [PATCH 21/24] feat(ui): Add balance queries to basic Wormhole form --- apps/ui/src/components/WormholeForm.tsx | 97 +++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 5 deletions(-) diff --git a/apps/ui/src/components/WormholeForm.tsx b/apps/ui/src/components/WormholeForm.tsx index 05d26f949..add03a933 100644 --- a/apps/ui/src/components/WormholeForm.tsx +++ b/apps/ui/src/components/WormholeForm.tsx @@ -1,5 +1,26 @@ -import type { ChainId } from "@certusone/wormhole-sdk"; -import { CHAIN_ID_TO_NAME } from "@certusone/wormhole-sdk"; +import type { ChainId, EVMChainId } from "@certusone/wormhole-sdk"; +import { + CHAIN_ID_ACALA, + CHAIN_ID_ARBITRUM, + CHAIN_ID_AURORA, + CHAIN_ID_AVAX, + CHAIN_ID_BSC, + CHAIN_ID_CELO, + CHAIN_ID_ETH, + CHAIN_ID_ETHEREUM_ROPSTEN, + CHAIN_ID_FANTOM, + CHAIN_ID_GNOSIS, + CHAIN_ID_KARURA, + CHAIN_ID_KLAYTN, + CHAIN_ID_MOONBEAM, + CHAIN_ID_NEON, + CHAIN_ID_OASIS, + CHAIN_ID_OPTIMISM, + CHAIN_ID_POLYGON, + CHAIN_ID_SOLANA, + CHAIN_ID_TO_NAME, + isEVMChain, +} from "@certusone/wormhole-sdk"; import type { EuiSelectOption } from "@elastic/eui"; import { EuiButton, @@ -8,18 +29,43 @@ import { EuiSelect, EuiSpacer, } from "@elastic/eui"; +import { ERC20__factory } from "@swim-io/evm-contracts"; +import type { ReadonlyRecord } from "@swim-io/utils"; import { findOrThrow } from "@swim-io/utils"; import Decimal from "decimal.js"; +import { utils as ethersUtils } from "ethers"; import type { ReactElement } from "react"; import { useEffect, useMemo, useState } from "react"; +import type { UseQueryResult } from "react-query"; +import { useQuery } from "react-query"; import { wormholeTokens as rawWormholeTokens } from "../config"; -import { useWormholeTransfer } from "../hooks"; +import { useEvmWallet, useSplUserBalance, useWormholeTransfer } from "../hooks"; import type { TxResult, WormholeToken, WormholeTokenDetails } from "../models"; import { generateId } from "../models"; import { EuiFieldIntlNumber } from "./EuiFieldIntlNumber"; +const EVM_NETWORKS: ReadonlyRecord = { + [CHAIN_ID_ETH]: 1, + [CHAIN_ID_BSC]: 56, + [CHAIN_ID_POLYGON]: 137, + [CHAIN_ID_AVAX]: 43114, + [CHAIN_ID_OASIS]: 42262, + [CHAIN_ID_AURORA]: 1313161554, + [CHAIN_ID_FANTOM]: 250, + [CHAIN_ID_KARURA]: 686, + [CHAIN_ID_ACALA]: 787, + [CHAIN_ID_KLAYTN]: 8217, + [CHAIN_ID_CELO]: 42220, + [CHAIN_ID_MOONBEAM]: 1284, + [CHAIN_ID_NEON]: 245022934, + [CHAIN_ID_ARBITRUM]: 42161, + [CHAIN_ID_OPTIMISM]: 10, + [CHAIN_ID_GNOSIS]: 100, + [CHAIN_ID_ETHEREUM_ROPSTEN]: 3, +}; + const getDetailsByChainId = ( token: WormholeToken, chainId: ChainId, @@ -29,6 +75,37 @@ const getDetailsByChainId = ( (details) => details.chainId === chainId, ); +const useErc20BalanceQuery = ({ + chainId, + address, + decimals, +}: WormholeTokenDetails): UseQueryResult => { + const { wallet } = useEvmWallet(); + + return useQuery( + ["wormhole", "erc20Balance", chainId, address, wallet?.address], + async () => { + if (!wallet?.address || !isEVMChain(chainId)) { + return null; + } + const evmNetwork = EVM_NETWORKS[chainId]; + await wallet.switchNetwork(evmNetwork); + const { provider } = wallet.signer ?? {}; + if (!provider) { + return null; + } + const erc20Contract = ERC20__factory.connect(address, provider); + try { + const balance = await erc20Contract.balanceOf(wallet.address); + return new Decimal(ethersUtils.formatUnits(balance, decimals)); + } catch { + return new Decimal(0); + } + }, + {}, + ); +}; + export const WormholeForm = (): ReactElement => { const wormholeTokens = rawWormholeTokens as readonly WormholeToken[]; const [currentTokenSymbol, setCurrentTokenSymbol] = useState( @@ -78,6 +155,14 @@ export const WormholeForm = (): ReactElement => { const { mutateAsync: transfer, isLoading } = useWormholeTransfer(); + const sourceDetails = getDetailsByChainId(currentToken, sourceChainId); + const targetDetails = getDetailsByChainId(currentToken, targetChainId); + const splBalance = useSplUserBalance( + sourceChainId === CHAIN_ID_SOLANA ? sourceDetails : null, + { enabled: sourceChainId === CHAIN_ID_SOLANA }, + ); + const { data: erc20Balance = null } = useErc20BalanceQuery(sourceDetails); + const handleTxResult = (txResult: TxResult): void => { setTxResults((previousResults) => [...previousResults, txResult]); }; @@ -85,8 +170,6 @@ export const WormholeForm = (): ReactElement => { const handleSubmit = () => { (async (): Promise => { setTxResults([]); - const sourceDetails = getDetailsByChainId(currentToken, sourceChainId); - const targetDetails = getDetailsByChainId(currentToken, targetChainId); await transfer({ interactionId: generateId(), value: inputAmount, @@ -138,6 +221,10 @@ export const WormholeForm = (): ReactElement => { + + + + From e9ea32612f20f75509d860c93c07467994f26ba8 Mon Sep 17 00:00:00 2001 From: wormat Date: Thu, 20 Oct 2022 19:45:49 +0200 Subject: [PATCH 22/24] refactor(ui): Update Wormhole form/hooks for SDK client changes --- apps/ui/src/components/WormholeForm.tsx | 8 +- .../wormhole/useTransferEvmToEvmMutation.ts | 66 ++++++++-------- .../useTransferEvmToSolanaMutation.ts | 78 ++++++++++--------- .../useTransferSolanaToEvmMutation.ts | 39 ++++++---- 4 files changed, 100 insertions(+), 91 deletions(-) diff --git a/apps/ui/src/components/WormholeForm.tsx b/apps/ui/src/components/WormholeForm.tsx index add03a933..d3f106e7f 100644 --- a/apps/ui/src/components/WormholeForm.tsx +++ b/apps/ui/src/components/WormholeForm.tsx @@ -40,7 +40,11 @@ import type { UseQueryResult } from "react-query"; import { useQuery } from "react-query"; import { wormholeTokens as rawWormholeTokens } from "../config"; -import { useEvmWallet, useSplUserBalance, useWormholeTransfer } from "../hooks"; +import { + useEvmWallet, + useUserSolanaTokenBalance, + useWormholeTransfer, +} from "../hooks"; import type { TxResult, WormholeToken, WormholeTokenDetails } from "../models"; import { generateId } from "../models"; @@ -157,7 +161,7 @@ export const WormholeForm = (): ReactElement => { const sourceDetails = getDetailsByChainId(currentToken, sourceChainId); const targetDetails = getDetailsByChainId(currentToken, targetChainId); - const splBalance = useSplUserBalance( + const splBalance = useUserSolanaTokenBalance( sourceChainId === CHAIN_ID_SOLANA ? sourceDetails : null, { enabled: sourceChainId === CHAIN_ID_SOLANA }, ); diff --git a/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts b/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts index c8f002136..1e2765be8 100644 --- a/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts +++ b/apps/ui/src/hooks/wormhole/useTransferEvmToEvmMutation.ts @@ -2,7 +2,8 @@ import { getEmitterAddressEth, parseSequenceFromLogEth, } from "@certusone/wormhole-sdk"; -import { isEvmEcosystemId } from "@swim-io/evm"; +import type { EvmTx } from "@swim-io/evm"; +import { EvmTxType, isEvmEcosystemId } from "@swim-io/evm"; import { findOrThrow, humanToAtomic } from "@swim-io/utils"; import { useMutation } from "react-query"; import shallow from "zustand/shallow.js"; @@ -77,34 +78,35 @@ export const useTransferEvmToEvmMutation = () => { await evmWallet.switchNetwork(sourceChain.chainId); // Process transfer if transfer txId does not exist - const { approvalResponses, transferResponse } = - await sourceClient.initiateWormholeTransfer({ - atomicAmount: humanToAtomic(value, sourceDetails.decimals).toString(), - interactionId, - sourceAddress: sourceDetails.address, - targetAddress: formatWormholeAddress(Protocol.Evm, evmWalletAddress), - targetChainId: targetDetails.chainId, - wallet: evmWallet, - wrappedTokenInfo: getWrappedTokenInfoFromNativeDetails( - sourceDetails.chainId, - nativeDetails, - ), - }); + const sourceTxGenerator = sourceClient.generateInitiatePortalTransferTxs({ + atomicAmount: humanToAtomic(value, sourceDetails.decimals).toString(), + interactionId, + sourceAddress: sourceDetails.address, + targetAddress: formatWormholeAddress(Protocol.Evm, evmWalletAddress), + targetChainId: targetDetails.chainId, + wallet: evmWallet, + wrappedTokenInfo: getWrappedTokenInfoFromNativeDetails( + sourceDetails.chainId, + nativeDetails, + ), + }); - approvalResponses.forEach((response) => + let transferTx: EvmTx | null = null; + for await (const result of sourceTxGenerator) { + if (result.type === EvmTxType.PortalTransferTokens) { + transferTx = result.tx; + } onTxResult({ chainId: sourceDetails.chainId, - txId: response.hash, - }), - ); + txId: result.tx.id, + }); + } - const transferTx = await sourceClient.getTx(transferResponse); - onTxResult({ - chainId: sourceDetails.chainId, - txId: transferTx.id, - }); + if (transferTx === null) { + throw new Error("Missing source transaction"); + } const sequence = parseSequenceFromLogEth( - transferTx.receipt, + transferTx.original, sourceChain.wormhole.bridge, ); const retries = getWormholeRetries(sourceDetails.chainId); @@ -119,21 +121,17 @@ export const useTransferEvmToEvmMutation = () => { ); await evmWallet.switchNetwork(targetChain.chainId); - const redeemResponse = await targetClient.completeWormholeTransfer({ + const targetTxGenerator = targetClient.generateCompletePortalTransferTxs({ interactionId, vaa, wallet: evmWallet, }); - if (redeemResponse === null) { - throw new Error( - `Transaction not found: (unlock/mint on ${targetEcosystemId})`, - ); + for await (const result of targetTxGenerator) { + onTxResult({ + chainId: targetDetails.chainId, + txId: result.tx.id, + }); } - const redeemTx = await targetClient.getTx(redeemResponse); - onTxResult({ - chainId: targetDetails.chainId, - txId: redeemTx.id, - }); }, ); }; diff --git a/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts b/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts index 5675638f3..240791586 100644 --- a/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts +++ b/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts @@ -3,7 +3,8 @@ import { parseSequenceFromLogEth, } from "@certusone/wormhole-sdk"; import { Keypair } from "@solana/web3.js"; -import { isEvmEcosystemId } from "@swim-io/evm"; +import type { EvmTx } from "@swim-io/evm"; +import { EvmTxType, isEvmEcosystemId } from "@swim-io/evm"; import { SOLANA_ECOSYSTEM_ID, solana } from "@swim-io/solana"; import { findOrThrow, humanToAtomic } from "@swim-io/utils"; import { WormholeChainId } from "@swim-io/wormhole"; @@ -22,7 +23,7 @@ import { } from "../../models"; import { useWallets } from "../crossEcosystem"; import { useGetEvmClient } from "../evm"; -import { useSolanaClient, useSplTokenAccountsQuery } from "../solana"; +import { useSolanaClient, useUserSolanaTokenAccountsQuery } from "../solana"; export const useTransferEvmToSolanaMutation = () => { const queryClient = useQueryClient(); @@ -32,7 +33,7 @@ export const useTransferEvmToSolanaMutation = () => { const solanaClient = useSolanaClient(); const wallets = useWallets(); const solanaWallet = wallets[SOLANA_ECOSYSTEM_ID].wallet; - const { data: splTokenAccounts = [] } = useSplTokenAccountsQuery(); + const { data: splTokenAccounts = [] } = useUserSolanaTokenAccountsQuery(); return useMutation( async ({ @@ -89,37 +90,39 @@ export const useTransferEvmToSolanaMutation = () => { await evmWallet.switchNetwork(evmChain.chainId); // Process transfer if transfer txId does not exist - const { approvalResponses, transferResponse } = - await evmClient.initiateWormholeTransfer({ - atomicAmount: humanToAtomic(value, sourceDetails.decimals).toString(), - interactionId, - sourceAddress: sourceDetails.address, - targetAddress: formatWormholeAddress( - Protocol.Solana, - splTokenAccountAddress, - ), - targetChainId: solana.wormholeChainId, - wallet: evmWallet, - wrappedTokenInfo: getWrappedTokenInfoFromNativeDetails( - sourceDetails.chainId, - nativeDetails, - ), - }); + const evmTxGenerator = evmClient.generateInitiatePortalTransferTxs({ + atomicAmount: humanToAtomic(value, sourceDetails.decimals).toString(), + interactionId, + sourceAddress: sourceDetails.address, + targetAddress: formatWormholeAddress( + Protocol.Solana, + splTokenAccountAddress, + ), + targetChainId: solana.wormholeChainId, + wallet: evmWallet, + wrappedTokenInfo: getWrappedTokenInfoFromNativeDetails( + sourceDetails.chainId, + nativeDetails, + ), + }); - approvalResponses.forEach((response) => + let evmTransferTx: EvmTx | null = null; + for await (const result of evmTxGenerator) { + if (result.type === EvmTxType.PortalTransferTokens) { + evmTransferTx = result.tx; + } onTxResult({ chainId: sourceDetails.chainId, - txId: response.hash, - }), - ); + txId: result.tx.id, + }); + } + + if (evmTransferTx === null) { + throw new Error("Missing EVM transaction"); + } - const transferTx = await evmClient.getTx(transferResponse); - onTxResult({ - chainId: sourceDetails.chainId, - txId: transferTx.id, - }); const sequence = parseSequenceFromLogEth( - transferTx.receipt, + evmTransferTx.original, evmChain.wormhole.bridge, ); @@ -134,18 +137,17 @@ export const useTransferEvmToSolanaMutation = () => { undefined, retries, ); - const unlockSplTokenTxIdsGenerator = - solanaClient.generateCompleteWormholeTransferTxIds({ - interactionId, - vaa, - wallet: solanaWallet, - auxiliarySigner, - }); + const splTxGenerator = solanaClient.generateCompletePortalTransferTxs({ + interactionId, + vaa, + wallet: solanaWallet, + auxiliarySigner, + }); - for await (const txId of unlockSplTokenTxIdsGenerator) { + for await (const result of splTxGenerator) { onTxResult({ chainId: targetDetails.chainId, - txId, + txId: result.tx.id, }); } }, diff --git a/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts b/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts index f1482b9a3..06d7c222b 100644 --- a/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts +++ b/apps/ui/src/hooks/wormhole/useTransferSolanaToEvmMutation.ts @@ -1,6 +1,7 @@ import { getEmitterAddressSolana } from "@certusone/wormhole-sdk"; import { Keypair } from "@solana/web3.js"; import { isEvmEcosystemId } from "@swim-io/evm"; +import type { SolanaTx } from "@swim-io/solana"; import { SOLANA_ECOSYSTEM_ID, parseSequenceFromLogSolana, @@ -74,7 +75,7 @@ export const useTransferSolanaToEvmMutation = () => { } const auxiliarySigner = Keypair.generate(); - const transferSplTokenTxId = await solanaClient.initiateWormholeTransfer({ + const solanaTxGenerator = solanaClient.generateInitiatePortalTransferTxs({ atomicAmount: humanToAtomic(value, sourceDetails.decimals).toString(), interactionId, sourceAddress: sourceDetails.address, @@ -87,13 +88,20 @@ export const useTransferSolanaToEvmMutation = () => { nativeDetails, ), }); - onTxResult({ - chainId: sourceDetails.chainId, - txId: transferSplTokenTxId, - }); - const solanaTx = await solanaClient.getTx(transferSplTokenTxId); - const sequence = parseSequenceFromLogSolana(solanaTx.parsedTx); + let solanaTx: SolanaTx | null = null; + for await (const result of solanaTxGenerator) { + solanaTx = result.tx; + onTxResult({ + chainId: sourceDetails.chainId, + txId: result.tx.id, + }); + } + if (solanaTx === null) { + throw new Error("Missing Solana transaction"); + } + + const sequence = parseSequenceFromLogSolana(solanaTx.original); const emitterAddress = await getEmitterAddressSolana( solanaChain.wormhole.portal, ); @@ -108,21 +116,18 @@ export const useTransferSolanaToEvmMutation = () => { retries, ); await evmWallet.switchNetwork(evmChain.chainId); - const redeemResponse = await evmClient.completeWormholeTransfer({ + const evmTxGenerator = evmClient.generateCompletePortalTransferTxs({ interactionId, vaa, wallet: evmWallet, }); - if (redeemResponse === null) { - throw new Error( - `Transaction not found: (unlock/mint on ${evmChain.ecosystem})`, - ); + + for await (const result of evmTxGenerator) { + onTxResult({ + chainId: targetDetails.chainId, + txId: result.tx.id, + }); } - const evmTx = await evmClient.getTx(redeemResponse); - onTxResult({ - chainId: targetDetails.chainId, - txId: evmTx.id, - }); }, ); }; From a8e16410e2e23fde364e7ee1020ffcadf6fff6e1 Mon Sep 17 00:00:00 2001 From: wormat Date: Fri, 21 Oct 2022 11:14:04 +0200 Subject: [PATCH 23/24] fix(ui): Fix basic Wormhole form bugs --- apps/ui/src/components/WormholeForm.tsx | 18 ++++++++++++------ .../wormhole/useTransferEvmToSolanaMutation.ts | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/ui/src/components/WormholeForm.tsx b/apps/ui/src/components/WormholeForm.tsx index d3f106e7f..ddee5d793 100644 --- a/apps/ui/src/components/WormholeForm.tsx +++ b/apps/ui/src/components/WormholeForm.tsx @@ -34,7 +34,7 @@ import type { ReadonlyRecord } from "@swim-io/utils"; import { findOrThrow } from "@swim-io/utils"; import Decimal from "decimal.js"; import { utils as ethersUtils } from "ethers"; -import type { ReactElement } from "react"; +import type { FormEvent, ReactElement } from "react"; import { useEffect, useMemo, useState } from "react"; import type { UseQueryResult } from "react-query"; import { useQuery } from "react-query"; @@ -73,11 +73,10 @@ const EVM_NETWORKS: ReadonlyRecord = { const getDetailsByChainId = ( token: WormholeToken, chainId: ChainId, -): WormholeTokenDetails => - findOrThrow( - [token.nativeDetails, ...token.wrappedDetails], +): WormholeTokenDetails | null => + [token.nativeDetails, ...token.wrappedDetails].find( (details) => details.chainId === chainId, - ); + ) ?? null; const useErc20BalanceQuery = ({ chainId, @@ -160,6 +159,9 @@ export const WormholeForm = (): ReactElement => { const { mutateAsync: transfer, isLoading } = useWormholeTransfer(); const sourceDetails = getDetailsByChainId(currentToken, sourceChainId); + if (sourceDetails === null) { + throw new Error("Missing source details"); + } const targetDetails = getDetailsByChainId(currentToken, targetChainId); const splBalance = useUserSolanaTokenBalance( sourceChainId === CHAIN_ID_SOLANA ? sourceDetails : null, @@ -171,8 +173,12 @@ export const WormholeForm = (): ReactElement => { setTxResults((previousResults) => [...previousResults, txResult]); }; - const handleSubmit = () => { + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); (async (): Promise => { + if (targetDetails === null) { + throw new Error("Missing target details"); + } setTxResults([]); await transfer({ interactionId: generateId(), diff --git a/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts b/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts index 240791586..4a7c88514 100644 --- a/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts +++ b/apps/ui/src/hooks/wormhole/useTransferEvmToSolanaMutation.ts @@ -137,14 +137,14 @@ export const useTransferEvmToSolanaMutation = () => { undefined, retries, ); - const splTxGenerator = solanaClient.generateCompletePortalTransferTxs({ + const solanaTxGenerator = solanaClient.generateCompletePortalTransferTxs({ interactionId, vaa, wallet: solanaWallet, auxiliarySigner, }); - for await (const result of splTxGenerator) { + for await (const result of solanaTxGenerator) { onTxResult({ chainId: targetDetails.chainId, txId: result.tx.id, From 5e78fcea21ae21277d13f242e8505bc0cbe52629 Mon Sep 17 00:00:00 2001 From: wormat Date: Fri, 21 Oct 2022 15:00:25 +0200 Subject: [PATCH 24/24] chore(ui): Add Wormhole tokens list to .prettierignore --- apps/ui/.prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/ui/.prettierignore b/apps/ui/.prettierignore index 6a52b36fa..722517a76 100644 --- a/apps/ui/.prettierignore +++ b/apps/ui/.prettierignore @@ -1,4 +1,5 @@ # ignore auto-generated files build/ storybook-static/ +src/config/wormholeTokens.json src/keys/**/*.json
Chain IDTx ID{"Chain ID"}{"Tx ID"}
{chainId} {txId}
{"Source Chain"} {sourceChainId}
{"Balance"}{splBalance?.toString() ?? erc20Balance?.toString() ?? "-"}
{"Target Chain"} {targetChainId}