diff --git a/.github/scripts/data/baseline.json b/.github/scripts/data/baseline.json index b6d478963a2..f876a10b8f0 100644 --- a/.github/scripts/data/baseline.json +++ b/.github/scripts/data/baseline.json @@ -1,5 +1,5 @@ { - "timestamp": "2025-11-23T21:03:30Z", + "timestamp": "2026-02-08T21:05:44Z", "knownIds": [ "aptos-apt-usd", "aptos-btc-usd", @@ -14,12 +14,19 @@ "arbitrum-1inch-usd-premium-prod-v03", "arbitrum-aapl-usd", "arbitrum-aapl-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-aapl-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-aapl-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-aapl-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-aaplx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-aaplx-usd-streams-cexprice-mainnet-production", "arbitrum-aave-usd", "arbitrum-aave-usd-premium-prod", + "arbitrum-aave-usd-svr", "arbitrum-ab-usd", "arbitrum-abbv-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-abbv-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-abbv-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-abbv-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-abt-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-ace-usd-premium-prod-v03", "arbitrum-ada-usd", @@ -41,6 +48,9 @@ "arbitrum-amgn-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-amzn-usd", "arbitrum-amzn-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-amzn-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-amzn-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-amzn-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-amznx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-amznx-usd-streams-cexprice-mainnet-production", "arbitrum-anime-usd-premium-prod-v03", @@ -58,6 +68,8 @@ "arbitrum-ar-usd-refprice-ds-premium-global-003-prod", "arbitrum-arb-usd", "arbitrum-arb-usd-premium-prod", + "arbitrum-arb-usd-shared-svr", + "arbitrum-arb-usd-svr", "arbitrum-arkm-usd-premium-prod-v03", "arbitrum-aster-usd-streams-cexprice-mainnet-production", "arbitrum-astr-usd", @@ -69,6 +81,7 @@ "arbitrum-aud-usd", "arbitrum-aud-usd-refprice-timestamped-mainnet-production", "arbitrum-aud-usd-rwa-prod-v04", + "arbitrum-ausd-usd-streams-dexprice-mainnet-production", "arbitrum-avax-usd", "arbitrum-avax-usd-premium-prod", "arbitrum-avgo-usd-streams-equityprice-timestamped-mainnet-production", @@ -94,9 +107,13 @@ "arbitrum-blue-usd-refprice-mainnet-production", "arbitrum-blur-usd-premium-prod-v03", "arbitrum-bmnr-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-bmnr-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-bmnr-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-bmnr-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-bnb-usd", "arbitrum-bnb-usd-premium-prod", "arbitrum-bnsol-usd-refprice-mainnet-production", + "arbitrum-bob-usd-streams-cexprice-mainnet-production", "arbitrum-bome-usd-refprice-ds-premium-global-003-prod", "arbitrum-bone-usd", "arbitrum-bone-usd-refprice-mainnet-production", @@ -106,10 +123,13 @@ "arbitrum-brl-usd", "arbitrum-bsol-usd-refprice-mainnet-production", "arbitrum-bsv-usd-refprice-mainnet-production", + "arbitrum-btc-b-usd-streams-dexprice-mainnet-production", "arbitrum-btc-eth", "arbitrum-btc-usd", "arbitrum-btc-usd-marketcap", "arbitrum-btc-usd-premium-prod", + "arbitrum-btc-usd-shared-svr", + "arbitrum-btc-usd-svr", "arbitrum-btr-usd-streams-cexprice-mainnet-production", "arbitrum-btt-usd-refprice-mainnet-production", "arbitrum-c98-usd-premium-prod-v03", @@ -121,6 +141,8 @@ "arbitrum-cbbtc-usd-refprice-mainnet-production", "arbitrum-cbeth-eth", "arbitrum-cbeth-eth-exchange", + "arbitrum-cbtc-por-datalink-proofofreserves-mainnet-production", + "arbitrum-cc-usd-streams-cexprice-mainnet-production", "arbitrum-celo-usd-refprice-mainnet-production", "arbitrum-cfx-usd-refprice-mainnet-production", "arbitrum-chf-usd", @@ -129,6 +151,9 @@ "arbitrum-cny-usd", "arbitrum-coin-usd", "arbitrum-coin-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-coin-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-coin-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-coin-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-coinx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-coinx-usd-streams-cexprice-mainnet-production", "arbitrum-comp-usd", @@ -138,6 +163,9 @@ "arbitrum-core-usd-refprice-mainnet-production", "arbitrum-cost-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-crcl-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-crcl-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-crcl-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-crcl-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-crclx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-crclx-usd-streams-cexprice-mainnet-production", "arbitrum-crm-usd-streams-equityprice-timestamped-mainnet-production", @@ -149,14 +177,18 @@ "arbitrum-csco-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-ctc-usd-refprice-mainnet-production", "arbitrum-cusdo-usd-streams-dexprice-mainnet-production", + "arbitrum-cusdo-usdo-streams-exchangerate-mainnet-production", "arbitrum-cvx-usd", "arbitrum-cvx-usd-refprice-mainnet-production", "arbitrum-cvx-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-cyber-usd-premium-prod-v03", "arbitrum-dai-usd", "arbitrum-dai-usd-premium-prod", + "arbitrum-dai-usd-shared-svr", + "arbitrum-dai-usd-svr", "arbitrum-dash-usd-refprice-mainnet-production", "arbitrum-deep-usd-refprice-mainnet-production", + "arbitrum-degen-usd-streams-cexprice-mainnet-production", "arbitrum-deusd-usd", "arbitrum-dodo-usd", "arbitrum-dodo-usd-refprice-mainnet-production", @@ -172,6 +204,7 @@ "arbitrum-dusk-usd-refprice-mainnet-production", "arbitrum-dydx-usd-refprice-ds-premium-global-003-prod", "arbitrum-dym-usd-refprice-mainnet-production", + "arbitrum-eden-usd-streams-cexprice-mainnet-production", "arbitrum-edu-usd-premium-prod-v03", "arbitrum-efa-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-egeth-eth-exchange-rate", @@ -185,12 +218,17 @@ "arbitrum-eth-usd", "arbitrum-eth-usd-marketcap", "arbitrum-eth-usd-premium-prod", + "arbitrum-eth-usd-shared-svr", + "arbitrum-eth-usd-svr", "arbitrum-ethfi-usd-premium-prod", "arbitrum-ethx-eth-exchange-rate", "arbitrum-eur-usd", "arbitrum-eur-usd-refprice-timestamped-mainnet-production", "arbitrum-eur-usd-rwa-prod-v04", "arbitrum-eurc-usd", + "arbitrum-eurc-usd-shared-svr", + "arbitrum-eurc-usd-streams-dexprice-mainnet-production", + "arbitrum-eurc-usd-svr", "arbitrum-eusx-usx-streams-exchangerate-mainnet-production", "arbitrum-ewj-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-ezeth-eth", @@ -200,6 +238,7 @@ "arbitrum-ezu-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-fartcoin-usd-premium-prod-v03", "arbitrum-fbtc-btc-exchange-rate", + "arbitrum-fbtc-btc-streams-exchangerate-mainnet-production", "arbitrum-fbtc-por", "arbitrum-fdusd-usd-refprice-mainnet-production", "arbitrum-fet-usd-refprice-ds-premium-global-003-prod", @@ -212,6 +251,8 @@ "arbitrum-fragsol-sol-exchange-rate", "arbitrum-frax-usd", "arbitrum-frax-usd-refprice-mainnet-production", + "arbitrum-frax-usd-shared-svr", + "arbitrum-frax-usd-svr", "arbitrum-frxeth-eth-high", "arbitrum-frxeth-eth-low", "arbitrum-frxusd-usd", @@ -225,6 +266,7 @@ "arbitrum-ge-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-gho-usd", "arbitrum-gho-usd-refprice-mainnet-production", + "arbitrum-gho-usd-svr", "arbitrum-giga-usd-refprice-mainnet-production", "arbitrum-gld-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-gm-btc-usd-wbtc-wbtc", @@ -240,6 +282,9 @@ "arbitrum-goat-usd-premium-prod-v03", "arbitrum-googl-usd", "arbitrum-googl-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-googl-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-googl-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-googl-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-googlx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-googlx-usd-streams-cexprice-mainnet-production", "arbitrum-grass-usd", @@ -255,6 +300,9 @@ "arbitrum-hmstr-usd-premium-prod-v03", "arbitrum-hnt-usd-refprice-mainnet-production", "arbitrum-hood-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-hood-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-hood-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-hood-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-hoodx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-hoodx-usd-streams-cexprice-mainnet-production", "arbitrum-hook-usd-premium-prod-v03", @@ -305,6 +353,7 @@ "arbitrum-kava-usd-refprice-mainnet-production", "arbitrum-kcs-usd-refprice-mainnet-production", "arbitrum-khype-usd-refprice-mainnet-production", + "arbitrum-kmhype-hype-streams-exchangerate-mainnet-production", "arbitrum-kmno-usd-refprice-mainnet-production", "arbitrum-knc-usd", "arbitrum-ko-usd-streams-equityprice-timestamped-mainnet-production", @@ -322,7 +371,10 @@ "arbitrum-link-eth", "arbitrum-link-usd", "arbitrum-link-usd-premium-prod", + "arbitrum-link-usd-shared-svr", + "arbitrum-link-usd-svr", "arbitrum-lista-usd-premium-prod-v03", + "arbitrum-lit-usd-streams-cexprice-mainnet-production", "arbitrum-lly-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-low-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-lpt-usd-refprice-mainnet-production", @@ -333,6 +385,8 @@ "arbitrum-ltc-usd-premium-prod", "arbitrum-lusd-usd", "arbitrum-lusd-usd-refprice-mainnet-production", + "arbitrum-lusd-usd-shared-svr", + "arbitrum-lusd-usd-svr", "arbitrum-m-nav-arbitrum", "arbitrum-m-usd-streams-cexprice-mainnet-production", "arbitrum-ma-usd-streams-equityprice-timestamped-mainnet-production", @@ -350,8 +404,12 @@ "arbitrum-melania-usd-premium-prod-v03", "arbitrum-meme-usd-premium-prod", "arbitrum-merl-usd-premium-prod-v03", + "arbitrum-met-usd-streams-cexprice-mainnet-production", "arbitrum-meta-usd", "arbitrum-meta-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-meta-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-meta-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-meta-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-metax-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-metax-usd-streams-cexprice-mainnet-production", "arbitrum-metis-usd-refprice-mainnet-production", @@ -365,18 +423,30 @@ "arbitrum-mnt-usd", "arbitrum-mnt-usd-refprice-mainnet-production", "arbitrum-mog-usd-premium-prod-v03", + "arbitrum-mon-usd", + "arbitrum-mon-usd-streams-cexprice-mainnet-production", "arbitrum-moodeng-usd-premium-prod-v03", "arbitrum-morpho-usd-refprice-mainnet-production", "arbitrum-mplx-usd-streams-cexprice-mainnet-production", "arbitrum-mrk-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-mrk-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-mrk-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-mrk-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-ms-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-msft-usd", "arbitrum-msft-usd-refprice-timestamped-mainnet-production", + "arbitrum-msft-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-msft-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-msft-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-msftx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-msol-usd-refprice-mainnet-production", "arbitrum-mstr-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-mstr-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-mstr-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-mstr-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-mstrx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-mstrx-usd-streams-cexprice-mainnet-production", + "arbitrum-musd-usd-streams-dexprice-mainnet-production", "arbitrum-mvi-usd", "arbitrum-myx-usd-streams-cexprice-mainnet-production", "arbitrum-near-usd", @@ -388,6 +458,9 @@ "arbitrum-not-usd-refprice-ds-premium-global-003-prod", "arbitrum-nvda-usd", "arbitrum-nvda-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-nvda-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-nvda-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-nvda-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-nvdax-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-nvdax-usd-streams-cexprice-mainnet-production", "arbitrum-nzd-usd-refprice-timestamped-mainnet-production", @@ -400,6 +473,9 @@ "arbitrum-op-usd-premium-prod", "arbitrum-orca-usd-refprice-mainnet-production", "arbitrum-orcl-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-orcl-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-orcl-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-orcl-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-order-usd", "arbitrum-order-usd-premium-prod-v03", "arbitrum-ordi-usd", @@ -420,6 +496,10 @@ "arbitrum-php-usd", "arbitrum-pi-usd-refprice-mainnet-production", "arbitrum-pixel-usd-premium-prod-v03", + "arbitrum-pltr-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-pltr-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-pltr-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-pltr-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-plume-usd", "arbitrum-plume-usd-refprice-mainnet-production", "arbitrum-pm-usd-streams-equityprice-timestamped-mainnet-production", @@ -434,10 +514,14 @@ "arbitrum-pump-usd", "arbitrum-pump-usd-refprice-mainnet-production", "arbitrum-pyth-usd-premium-prod-v03", + "arbitrum-pyusd-usd", "arbitrum-pyusd-usd-refprice-mainnet-production", "arbitrum-qcom-usd-streams-equityprice-timestamped-mainnet-production", "arbitrum-qnt-usd-refprice-ds-premium-global-003-prod", "arbitrum-qqq-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-qqq-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-qqq-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-qqq-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-qqqx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-qqqx-usd-streams-cexprice-mainnet-production", "arbitrum-qtum-usd-refprice-mainnet-production", @@ -449,6 +533,7 @@ "arbitrum-real-gdp-level", "arbitrum-real-gdp-percentage", "arbitrum-render-usd-refprice-ds-premium-global-003-prod", + "arbitrum-resolv-usd-streams-cexprice-mainnet-production", "arbitrum-reth-eth", "arbitrum-reth-eth-exchange-rate", "arbitrum-rez-usd-premium-prod-v03", @@ -490,11 +575,15 @@ "arbitrum-sol-usd", "arbitrum-sol-usd-premium-prod", "arbitrum-solvbtc-btc", + "arbitrum-solvbtc-btc-streams-exchangerate-mainnet-production", "arbitrum-spell-usd", "arbitrum-spk-usd-refprice-mainnet-production", "arbitrum-spx-usd-refprice-mainnet-production", "arbitrum-spy-usd", "arbitrum-spy-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-spy-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-spy-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-spy-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-spyx-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-spyx-usd-streams-cexprice-mainnet-production", "arbitrum-stafi-staked-eth-reth-eth-exchange-rate", @@ -545,16 +634,22 @@ "arbitrum-ton-usd-premium-prod", "arbitrum-toshi-usd-refprice-mainnet-production", "arbitrum-trb-usd-refprice-mainnet-production", + "arbitrum-trex-usd-streams-dexprice-mainnet-production", "arbitrum-tru-usd-refprice-mainnet-production", "arbitrum-trump-usd", "arbitrum-trump-usd-premium-prod-v03", "arbitrum-trx-usd-premium-prod", "arbitrum-try-usd", + "arbitrum-try-usd-streams-forexprice-timestamped-mainnet-production", "arbitrum-tsla-usd", "arbitrum-tsla-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-tsla-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-tsla-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-tsla-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-tslax-usd-datalink-backed-totalreturnmultiplier-timestamped-mainnet-production", "arbitrum-tslax-usd-streams-cexprice-mainnet-production", "arbitrum-turbo-usd-premium-prod-v03", + "arbitrum-turtle-usd-streams-cexprice-mainnet-production", "arbitrum-tusd-usd", "arbitrum-twt-usd-refprice-mainnet-production", "arbitrum-txn-usd-streams-equityprice-timestamped-mainnet-production", @@ -563,6 +658,9 @@ "arbitrum-ulti-usd", "arbitrum-ultraeths-eth-exchange-rate", "arbitrum-unh-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-unh-usd-streams-extendedhoursequityprice-mainnet-production", + "arbitrum-unh-usd-streams-overnighthoursequityprice-mainnet-production", + "arbitrum-unh-usd-streams-regularhoursequityprice-mainnet-production", "arbitrum-uni-usd", "arbitrum-uni-usd-premium-prod", "arbitrum-unibtc-btc-exchange-rate", @@ -570,6 +668,7 @@ "arbitrum-unibtc-btc-streams-exchangerate-mainnet-production", "arbitrum-unieth-eth-exchange-rate", "arbitrum-unp-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-uscc-nav-smartdata-netassetvalue-mainnet-production", "arbitrum-usd-cad-refprice-timestamped-mainnet-production", "arbitrum-usd-cad-rwa-prod-v04", "arbitrum-usd-chf-refprice-timestamped-mainnet-production", @@ -585,20 +684,28 @@ "arbitrum-usdai-usd", "arbitrum-usdc-usd", "arbitrum-usdc-usd-premium-prod", + "arbitrum-usdc-usd-shared-svr", + "arbitrum-usdc-usd-svr", "arbitrum-usdd-usd", "arbitrum-usde-usd", "arbitrum-usde-usd-premium-prod", "arbitrum-usdf-usd-streams-dexprice-mainnet-production", "arbitrum-usdg-usd", + "arbitrum-usdm-usd-streams-dexprice-mainnet-production", "arbitrum-usds-usd", "arbitrum-usds-usd-refprice-mainnet-production", "arbitrum-usdt-usd", "arbitrum-usdt-usd-premium-prod", + "arbitrum-usdt-usd-shared-svr", + "arbitrum-usdt-usd-svr", + "arbitrum-usdt0-usd-streams-dexprice-mainnet-production", + "arbitrum-usdtb-usd-streams-dexprice-mainnet-production", "arbitrum-usol-usd-streams-cexprice-mainnet-production", "arbitrum-usr-usd", "arbitrum-usr-usd-exchange-rate", "arbitrum-usr-usd-refprice-mainnet-production", "arbitrum-usr-usd-streams-exchangerate-mainnet-production", + "arbitrum-ustb-nav-smartdata-netassetvalue-mainnet-production", "arbitrum-usual-usd-refprice-mainnet-production", "arbitrum-usx-usd-streams-dexprice-mainnet-production", "arbitrum-v-usd-streams-equityprice-timestamped-mainnet-production", @@ -625,6 +732,7 @@ "arbitrum-wen-usd-refprice-mainnet-production", "arbitrum-weth-uniswap-usd-streams-dexprice-mainnet-production", "arbitrum-wfc-usd-streams-equityprice-timestamped-mainnet-production", + "arbitrum-whitewhale-usd-streams-cexprice-mainnet-production", "arbitrum-wif-usd", "arbitrum-wif-usd-premium-prod", "arbitrum-wld-usd-refprice-ds-premium-global-003-prod", @@ -638,6 +746,7 @@ "arbitrum-wsrusd-rusd-streams-exchangerate-mainnet-production", "arbitrum-wsteth-eth", "arbitrum-wsteth-steth exchangerate", + "arbitrum-wsteth-steth-streams-exchangerate-mainnet-production", "arbitrum-wsteth-usd-refprice-mainnet-production", "arbitrum-wstusr-stusr", "arbitrum-wstusr-stusr-exchange-rate", @@ -720,6 +829,7 @@ "avalanche-fsbtc-reserves", "avalanche-fxs-usd", "avalanche-gho-usd", + "avalanche-glv-[avax-usdc]-usd", "avalanche-gmx-usd", "avalanche-ion-digital-total-reserve", "avalanche-joe-usd", @@ -750,6 +860,7 @@ "avalanche-solvbtc-btc", "avalanche-solvbtc.bbn-solvbtc-exchange-rate", "avalanche-spell-usd", + "avalanche-spsei-sei-exchange-rate", "avalanche-susde-usd", "avalanche-susde-usde-exchange-rate", "avalanche-sushi-usd", @@ -775,6 +886,7 @@ "avalanche-wstpol-pol-exchange-rate", "avalanche-xag-usd", "avalanche-xau-usd", + "avalanche-xcu-usd", "avalanche-xsolvbtc-nav", "avalanche-ybtc-btc-exchange-rate", "avalanche-ybtc.b-btc", @@ -788,6 +900,7 @@ "base-anon-usd", "base-apt-usd", "base-arkb-reserves", + "base-arsx-base-por", "base-aud-usd", "base-avail-usd", "base-avax-usd", @@ -796,6 +909,7 @@ "base-bnb-usd", "base-brl-usd", "base-btc-usd", + "base-btc-usd-shared-svr", "base-btc-usd-svr", "base-cad-usd", "base-cbbtc-por", @@ -814,12 +928,15 @@ "base-doge-usd", "base-dola-usd", "base-eth-usd", + "base-eth-usd-shared-svr", "base-eth-usd-svr", "base-eur-usd", "base-eurc-usd", + "base-eurc-usd-shared-svr", "base-eurc-usd-svr", "base-ezeth-eth", "base-ezeth-eth-exchange-rate", + "base-ezeth-eth-exchange-rate-svr", "base-gbp-usd", "base-gho-usd", "base-gho-usd-svr", @@ -862,6 +979,7 @@ "base-reth-eth-exchange-rate", "base-rseth-eth", "base-rseth-eth-exchange-rate", + "base-rseth-eth-exchange-rate-svr", "base-rsr-usd", "base-rsweth-eth", "base-rsweth-eth-exchange-rate", @@ -891,20 +1009,25 @@ "base-try-usd", "base-ultraeths-eth-exchange-rate", "base-unibtc-btc-exchange-rate", + "base-usd+-usd", "base-usdai-usd", "base-usdc-usd", + "base-usdc-usd-shared-svr", "base-usdc-usd-svr", "base-usde-usd", "base-usdo-por", "base-usds-usd", "base-usdt-usd", + "base-usdt-usd-shared-svr", "base-usdt-usd-svr", + "base-usdz-usd", "base-usr-usd", "base-virtual-usd", "base-vvv-usd", "base-vyusd-usd-exchange-rate", "base-wbtc-usd", "base-weeth-eeth-exchange-rate", + "base-weeth-eeth-exchange-rate-svr", "base-weeth-eth", "base-well-usd", "base-wif-usd", @@ -913,6 +1036,7 @@ "base-wrseth-eth-exchange-rate", "base-wsteth-eth", "base-wsteth-steth exchangerate", + "base-wsteth-steth-exchange-rate-svr", "base-wstusr-stusr-exchange-rate", "base-xau-usd", "base-xrp-usd", @@ -929,8 +1053,10 @@ "bnb-chain-1inch-usd", "bnb-chain-aapl-usd", "bnb-chain-aave-usd", + "bnb-chain-aave-usd-shared-svr", "bnb-chain-ada-bnb", "bnb-chain-ada-usd", + "bnb-chain-ada-usd-shared-svr", "bnb-chain-alpaca-usd", "bnb-chain-amzn-usd", "bnb-chain-aster-usd", @@ -942,16 +1068,22 @@ "bnb-chain-band-usd", "bnb-chain-bch-bnb", "bnb-chain-bch-usd", + "bnb-chain-bch-usd-shared-svr", "bnb-chain-bnb-usd", + "bnb-chain-bnb-usd-shared-svr", + "bnb-chain-bnb-usd-svr", "bnb-chain-br-usd", "bnb-chain-brl-usd", "bnb-chain-bsw-usd", "bnb-chain-btc-bnb", "bnb-chain-btc-eth", "bnb-chain-btc-usd", + "bnb-chain-btc-usd-shared-svr", + "bnb-chain-btc-usd-svr", "bnb-chain-c98-usd", "bnb-chain-cake-bnb", "bnb-chain-cake-usd", + "bnb-chain-cake-usd-shared-svr", "bnb-chain-calculated-bnbx-usd", "bnb-chain-calculated-savax-usd", "bnb-chain-cashplus-nav", @@ -963,8 +1095,10 @@ "bnb-chain-crv-usd", "bnb-chain-dai-bnb", "bnb-chain-dai-usd", + "bnb-chain-dai-usd-shared-svr", "bnb-chain-dodo-usd", "bnb-chain-doge-usd", + "bnb-chain-doge-usd-shared-svr", "bnb-chain-dot-bnb", "bnb-chain-dot-usd", "bnb-chain-enzobtc-por", @@ -972,12 +1106,16 @@ "bnb-chain-eos-usd", "bnb-chain-eth-bnb", "bnb-chain-eth-usd", + "bnb-chain-eth-usd-shared-svr", + "bnb-chain-eth-usd-svr", "bnb-chain-eur-usd", "bnb-chain-ezeth-eth", "bnb-chain-ezeth-eth-exchange-rate", "bnb-chain-fdusd-usd", + "bnb-chain-fdusd-usd-shared-svr", "bnb-chain-fet-usd", "bnb-chain-fil-usd", + "bnb-chain-fil-usd-shared-svr", "bnb-chain-frax-usd", "bnb-chain-fxs-usd", "bnb-chain-gbp-usd", @@ -996,9 +1134,11 @@ "bnb-chain-lina-usd", "bnb-chain-link-bnb", "bnb-chain-link-usd", + "bnb-chain-link-usd-shared-svr", "bnb-chain-lista-usd", "bnb-chain-ltc-bnb", "bnb-chain-ltc-usd", + "bnb-chain-ltc-usd-shared-svr", "bnb-chain-mask-usd", "bnb-chain-matic-usd", "bnb-chain-meta-usd", @@ -1030,6 +1170,7 @@ "bnb-chain-sgd-usd", "bnb-chain-shib-usd", "bnb-chain-sol-usd", + "bnb-chain-sol-usd-shared-svr", "bnb-chain-solv-por", "bnb-chain-solvbtc-btc", "bnb-chain-solvbtc.bbn-solvbtc-exchange-rate", @@ -1040,25 +1181,39 @@ "bnb-chain-susd1+-usd1-exchange-rate", "bnb-chain-susdd-usdd-exchange-rate", "bnb-chain-susde-usde-exchange-rate", + "bnb-chain-susde-usde-exchange-rate-shared-svr", "bnb-chain-susdf-usdf-exchange-rate", "bnb-chain-sushi-usd", "bnb-chain-sxp-usd", + "bnb-chain-syrupusdt-usdt-exchange-rate", "bnb-chain-tree-usd", "bnb-chain-trx-usd", + "bnb-chain-trx-usd-shared-svr", "bnb-chain-tsla-usd", "bnb-chain-tusd-usd", + "bnb-chain-tusd-usd-shared-svr", "bnb-chain-twt-bnb", + "bnb-chain-twt-bnb-shared-svr", + "bnb-chain-u-usd", "bnb-chain-uni-bnb", "bnb-chain-uni-usd", + "bnb-chain-uni-usd-shared-svr", "bnb-chain-unibtc-btc-exchange-rate", "bnb-chain-usd1-usd", + "bnb-chain-usd1-usd-shared-svr", "bnb-chain-usdc-bnb", "bnb-chain-usdc-usd", + "bnb-chain-usdc-usd-shared-svr", + "bnb-chain-usdc-usd-svr", "bnb-chain-usdd-usdc-exchange-rate", "bnb-chain-usdd-usdt-exchange-rate", "bnb-chain-usde-usd", + "bnb-chain-usde-usd-shared-svr", "bnb-chain-usdt-bnb", "bnb-chain-usdt-usd", + "bnb-chain-usdt-usd-shared-svr", + "bnb-chain-usdt-usd-svr", + "bnb-chain-usdu-por", "bnb-chain-usr-usd", "bnb-chain-vet-usd", "bnb-chain-weeth-eeth-exchange-rate", @@ -1068,6 +1223,7 @@ "bnb-chain-woo-usd", "bnb-chain-wsrusd-rusd-exchange-rate", "bnb-chain-wsteth-steth-exchange-rate", + "bnb-chain-wsteth-steth-exchange-rate-svr", "bnb-chain-wsteth-usd", "bnb-chain-wstusr-stusr-exchange-rate", "bnb-chain-wti-usd", @@ -1076,11 +1232,14 @@ "bnb-chain-xlm-usd", "bnb-chain-xrp-bnb", "bnb-chain-xrp-usd", + "bnb-chain-xrp-usd-shared-svr", "bnb-chain-xsolvbtc-nav", + "bnb-chain-xsolvbtc-solvbtc-exchange-rate-shared-svr", "bnb-chain-xtz-bnb", "bnb-chain-xtz-usd", "bnb-chain-xvs-bnb", "bnb-chain-xvs-usd", + "bnb-chain-xvs-usd-shared-svr", "bnb-chain-ybtc-btc-exchange-rate", "bnb-chain-yeth-eth-exchange-rate", "bnb-chain-yfi-bnb", @@ -1089,6 +1248,7 @@ "bnb-chain-zar-usd", "bnb-chain-zbu-usd", "bob-baby-usd", + "bob-bob-usd", "bob-btc-usd", "bob-eth-usd", "bob-lbtc-btc", @@ -1151,6 +1311,7 @@ "celo-ngn-usd", "celo-ngn-usd-fx", "celo-php-usd", + "celo-stcelo-celo-exchange-rate", "celo-usdc-usd", "celo-usdt-usd", "celo-xof-usd", @@ -1183,6 +1344,7 @@ "ethereum-c3m-eur", "ethereum-cad-usd", "ethereum-calc-xsushi-eth", + "ethereum-calculated-ethplus-usd", "ethereum-cashplus-nav", "ethereum-cbbtc-por", "ethereum-cbbtc-usd", @@ -1197,6 +1359,7 @@ "ethereum-crv-usd", "ethereum-crvusd-usd", "ethereum-cspx-usd", + "ethereum-cusdo-usd", "ethereum-cvx-eth", "ethereum-cvx-usd", "ethereum-dai-eth", @@ -1247,6 +1410,7 @@ "ethereum-link-usd", "ethereum-link-usd-shared-svr", "ethereum-link-usd-svr", + "ethereum-lombard-por", "ethereum-lrc-eth", "ethereum-lseth-eth-exchange-rate", "ethereum-lusd-usd", @@ -1292,6 +1456,8 @@ "ethereum-rsr-usd", "ethereum-rsweth-eth", "ethereum-sand-usd", + "ethereum-savbtc-avbtc-exchange-rate", + "ethereum-savusd-avusd-exchange-rate", "ethereum-sgd-usd", "ethereum-shib-eth", "ethereum-shv-usd", @@ -1354,6 +1520,7 @@ "ethereum-usdt-usd", "ethereum-usdt-usd-shared-svr", "ethereum-usdt-usd-svr", + "ethereum-usdtb-usd", "ethereum-usr-usd", "ethereum-ustb-aum", "ethereum-ustb-nav", @@ -1460,29 +1627,48 @@ "hedera-usdt-usd", "hedera-xrp-usd", "hyperevm-behype-hype-exchange-rate", + "hyperevm-behype-hype-exchange-rate-shared-svr", "hyperevm-btc-usd", + "hyperevm-btc-usd-shared-svr", "hyperevm-eth-usd", + "hyperevm-eth-usd-shared-svr", + "hyperevm-feusd-usd", "hyperevm-hype-usd", + "hyperevm-hype-usd-shared-svr", "hyperevm-hyped-hype-exchange-rate", "hyperevm-khype-hype-exchange-rate", + "hyperevm-khype-hype-exchange-rate-shared-svr", "hyperevm-khype-usd", + "hyperevm-khype-usd-shared-svr", "hyperevm-lhype-khype-exchange-rate", "hyperevm-lhype-sthype-exchange-rate", + "hyperevm-purr-usd", "hyperevm-sol-usd", + "hyperevm-sol-usd-shared-svr", "hyperevm-susde-usd", "hyperevm-thbill-usd", + "hyperevm-thbill-usd-shared-svr", "hyperevm-ubtc-usd", + "hyperevm-ubtc-usd-shared-svr", "hyperevm-ueth-usd", "hyperevm-usdc-usd", + "hyperevm-usdc-usd-shared-svr", "hyperevm-usde-usd", + "hyperevm-usde-usd-shared-svr", "hyperevm-usdh-usd", + "hyperevm-usdh-usd-shared-svr", + "hyperevm-usdhl-usd", "hyperevm-usdt-usd", + "hyperevm-usdt-usd-shared-svr", "hyperevm-usol-usd", + "hyperevm-usol-usd-shared-svr", "hyperevm-usr-usd", "hyperevm-whlp-usdt0-exchange-rate", "hyperevm-wsthype-sthype-exchange-rate", + "hyperevm-wsthype-sthype-exchange-rate-shared-svr", "hyperevm-wsthype-usd", "hyperevm-xaut-usd", + "hyperevm-xaut-usd-shared-svr", "linea-aave-usd", "linea-ageth-eth-exchange-rate", "linea-arb-usd", @@ -1499,6 +1685,7 @@ "linea-linea-usd", "linea-link-eth", "linea-link-usd", + "linea-m-nav-linea", "linea-matic-usd", "linea-musd-usd", "linea-oseth-eth-exchange-rate", @@ -1512,6 +1699,7 @@ "linea-rseth-eth", "linea-rsweth-eth-exchange-rate", "linea-savbtc-avbtc-exchange-rate", + "linea-saveth-aveth-exchange-rate", "linea-savusd-avusd-exchange-rate", "linea-ultraeths-eth-exchange-rate", "linea-usd1-usd", @@ -1543,12 +1731,39 @@ "mantle-real-final-sales-to-private-domestic-purchasers-percentage", "mantle-real-gdp-level", "mantle-real-gdp-percentage", + "mantle-rseth-eth-exchange-rate", "mantle-susde-usd", + "mantle-susde-usde-exchange-rate", + "mantle-syrupusdc-usdc-exchange-rate", + "mantle-syrupusdt-usdt-exchange-rate", "mantle-usd1-usd", "mantle-usdc-usd", "mantle-usde-usd", "mantle-usdt-usd", "mantle-ynethx-eth-exchange-rate", + "megaeth-btc-usd", + "megaeth-btc.b-usd", + "megaeth-eth-usd", + "megaeth-eth-usd-old", + "megaeth-ezeth-eth-exchange-rate", + "megaeth-hype-usd", + "megaeth-lbtc-btc-exchange-rate", + "megaeth-lbtc-usd", + "megaeth-musd-usd", + "megaeth-rseth-eth-exchange-rate", + "megaeth-sol-usd", + "megaeth-stcapusd-capusd-exchange-rate", + "megaeth-susde-usde-exchange-rate", + "megaeth-usdc-usd", + "megaeth-usdc-usd-old", + "megaeth-usde-usd", + "megaeth-usdm-usd", + "megaeth-usdt-usd", + "megaeth-usdt-usd-old", + "megaeth-usdt0-usd", + "megaeth-usdtb-usd", + "megaeth-wsrusd-rusd-exchange-rate", + "megaeth-wsteth-steth-exchange-rate", "metis-aave-usd", "metis-btc-usd", "metis-dai-usd", @@ -1557,6 +1772,7 @@ "metis-frxeth-eth-exchange-rate-low", "metis-link-usd", "metis-metis-usd", + "metis-mimatic-usd", "metis-sfrxeth-frxeth-exchange-rate", "metis-usdc-usd", "metis-usdt-usd", @@ -1591,6 +1807,7 @@ "optimism-ada-usd", "optimism-ageth-eth-exchange-rate", "optimism-algo-usd", + "optimism-ankr-usd", "optimism-ankreth-eth-exchange-rate", "optimism-anon-usd", "optimism-ape-usd", @@ -1621,11 +1838,13 @@ "optimism-etc-usd", "optimism-eth-btc", "optimism-eth-usd", + "optimism-ethx-eth", "optimism-eur-usd", "optimism-ezeth-eth-exchange-rate", "optimism-fil-usd", "optimism-flow-usd", "optimism-frax-usd", + "optimism-ftm-usd", "optimism-fxs-usd", "optimism-gmx-usd", "optimism-grt-usd", @@ -1701,10 +1920,12 @@ "optimism-virtune-avax-etp-por", "optimism-virtune-btc-etp-por", "optimism-virtune-btc-prime-etp-por", + "optimism-virtune-dot-etp-por", "optimism-virtune-link-etp-por", "optimism-virtune-pol-etp-por", "optimism-virtune-sol-etp-por", "optimism-virtune-staked-eth-etp-por", + "optimism-virtune-xlm-etp-por", "optimism-virtune-xrp-etp-por", "optimism-vyusd-usd-exchange-rate", "optimism-wbtc-usd", @@ -1776,6 +1997,7 @@ "polygon-aave-eth", "polygon-aave-usd", "polygon-ada-usd", + "polygon-ageur-usd", "polygon-alcx-usd", "polygon-algo-usd", "polygon-amzn-usd", @@ -1841,6 +2063,7 @@ "polygon-grt-usd", "polygon-hbar-usd", "polygon-icp-usd", + "polygon-idr-usd", "polygon-ils-usd", "polygon-ilv-eth", "polygon-inr-usd", @@ -1868,6 +2091,7 @@ "polygon-pln-usd", "polygon-qnt-usd", "polygon-quick-usd", + "polygon-rcusd+-nav", "polygon-rdnt-usd", "polygon-ryt-nav", "polygon-ryt-polygon", @@ -1918,6 +2142,7 @@ "polygon-yeth-eth-exchange-rate", "polygon-yfi-eth", "polygon-yfi-usd", + "polygon-zar-usd", "polygon-zec-usd", "polygonkatana-ausd-usd", "polygonkatana-btc-usd", @@ -2013,6 +2238,8 @@ "solana-dai-usd", "solana-eth-usd", "solana-eurc-usd", + "solana-jlp-usd", + "solana-jup-usd", "solana-lbtc-btc-exchange-rate", "solana-link-usd", "solana-matic-usd", @@ -2020,9 +2247,11 @@ "solana-msol-usd", "solana-op-usd", "solana-sol-usd", + "solana-solvbtc-btc-exchange-rate", "solana-syrupusdc-usdc-exchange-rate", "solana-usdc-usd", "solana-usdt-usd", + "solana-wbtc-usd", "solana-zbtc-por", "soneium-astr-usd", "soneium-btc-usd", @@ -2090,6 +2319,7 @@ "sonic-ybtc-btc", "sonic-yeth-eth", "sonic-yusd-usd-exchange-rate", + "sonic-zar-usd", "starknet-btc-usd", "starknet-dai-usd", "starknet-eth-usd", diff --git a/.github/scripts/data/detect-data.sh b/.github/scripts/data/detect-data.sh index d48e3f7c068..ae3b9f944b4 100755 --- a/.github/scripts/data/detect-data.sh +++ b/.github/scripts/data/detect-data.sh @@ -156,7 +156,7 @@ node <- + --root-dir $GITHUB_WORKSPACE/.vercel/output/static + --config lychee.toml + '.vercel/output/static/**/*.html' + fail: true + format: markdown + jobSummary: true # Job 4: Check Types typecheck: @@ -173,7 +189,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '20' + node-version: ${{ env.NODE_VERSION }} cache: 'npm' cache-dependency-path: '**/package-lock.json' @@ -205,19 +221,15 @@ jobs: jest: needs: [setup] runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.x] - fail-fast: false steps: - name: Checkout Repo uses: actions/checkout@v6 - - name: Setup Node.js ${{ matrix.node-version }} + - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: ${{ matrix.node-version }} + node-version: ${{ env.NODE_VERSION }} cache: 'npm' cache-dependency-path: '**/package-lock.json' @@ -242,6 +254,6 @@ jobs: if: always() uses: actions/upload-artifact@v5 with: - name: coverage-report-node-${{ matrix.node-version }} + name: coverage-report-node-${{ env.NODE_VERSION }} path: coverage/ retention-days: 30 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4e2f3dac873..25ad8c0628e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ dist/ node_modules/ temp/ +reports/ # logs npm-debug.log* diff --git a/LICENSE b/LICENSE index 764519dc3fa..e7195c674c4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 SmartContract Chainlink Limited SEZC +Copyright (c) 2026 SmartContract Chainlink Limited SEZC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/astro.config.ts b/astro.config.ts index bafbd5b77a2..9d551d4f88b 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -13,7 +13,10 @@ import yaml from "@rollup/plugin-yaml" import { ccipRedirects } from "./src/config/redirects/ccip" import trailingSlashMiddleware from "./src/integrations/trailing-slash-middleware" import redirectsJson from "./src/features/redirects/redirects.json" +import tailwind from "@astrojs/tailwind" import { extractCanonicalUrlsWithLanguageVariants } from "./src/utils/sidebar" +import remarkCodeFenceFilename from "./src/lib/markdown/remarkCodeFenceFilename" +import rehypeCodeSampleFences from "./src/lib/markdown/rehypeCodeSampleFences" config() // Load .env file @@ -46,6 +49,7 @@ export default defineConfig({ ...ccipRedirects, }, integrations: [ + tailwind(), trailingSlashMiddleware(), preact({ include: ["**/preact/*"], @@ -103,9 +107,13 @@ export default defineConfig({ return item }, }), - mdx(), + // Ensure our fence-meta parser runs for `.mdx` pages (in addition to `markdown.remarkPlugins`). + mdx({ + remarkPlugins: [remarkCodeFenceFilename], + }), ], markdown: { + remarkPlugins: [remarkCodeFenceFilename], rehypePlugins: [ rehypeSlug, // Required for autolink to work properly [ @@ -116,6 +124,7 @@ export default defineConfig({ ], // Wrap tables in div with overflow supported [rehypeWrapAll, { selector: "table", wrapper: "div.overflow-wrapper" }], + rehypeCodeSampleFences, ] as RehypePlugins, syntaxHighlight: "prism", smartypants: false, diff --git a/context7.json b/context7.json new file mode 100644 index 00000000000..89021e03ca0 --- /dev/null +++ b/context7.json @@ -0,0 +1,4 @@ +{ + "url": "https://context7.com/smartcontractkit/documentation", + "public_key": "pk_nsBvFzEpWNJq5XpYfKBFc" +} diff --git a/jest.config.cjs b/jest.config.cjs index fba12927624..74c6196488c 100644 --- a/jest.config.cjs +++ b/jest.config.cjs @@ -13,6 +13,7 @@ module.exports = { extensionsToTreatAsEsm: [".ts", ".tsx"], moduleFileExtensions: ["js", "jsx", "ts", "tsx", "json", "node"], moduleNameMapper: { + "^(\\.{1,2}/.*)\\.js$": "$1", "\\.(css)$": "/src/__mocks__/styleMock.ts", "^~/(.*)$": "/src/$1", "^@api/(.*)$": "/src/pages/api/$1", @@ -29,6 +30,7 @@ module.exports = { "^@variables$": "/src/config/markdown-variables.ts", "^@abi$": "/src/features/abi/index.ts", "^@lib$": "/src/lib/index.ts", + "^@lib/(.*)\\.js$": "/src/lib/$1", "^@lib/(.*)$": "/src/lib/$1", "\\.ya?ml$": "/src/__mocks__/yamlMock.ts", }, diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 00000000000..e0ebbf2d985 --- /dev/null +++ b/lychee.toml @@ -0,0 +1,41 @@ +# Lychee Link Checker Configuration +# https://lychee.cli.rs/ + +# Only check local files (no network requests) +offline = true + +# Check links in code blocks +include_verbatim = true + +# Don't show progress bar (better for CI) +no_progress = true + +# Patterns to exclude from link checking +exclude = [ + # CSS files + 'assets/.*\.css$', + '_astro/.*\.css$', + + # Dynamic pages with query params + '/ccip/directory/.*', + '/data-feeds/price-feeds/addresses\?.*', + '/data-feeds/smartdata/addresses\?.*', + + # Other files + 'sitemap-index\.xml', + '@vite/client', + + # Database connection strings + 'postgresql:', + 'mysql:', +] + +# Paths to exclude from scanning (won't check links on these pages) +exclude_path = [ + 'ccip/api-reference/evm/v162/.*', + 'ccip/api-reference/evm/v163/.*', +] + +# TODO: Re-enable fragment checking once Astro slug generation compatibility is resolved +# include_fragments = true +# Astro's heading ID generation and lychee's GitHub-style kebab-case expectations \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 878480f9781..370c2bbe4fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,14 +10,18 @@ "license": "ISC", "dependencies": { "@11ty/eleventy-fetch": "^4.0.1", - "@astro-community/astro-embed-youtube": "^0.5.9", - "@astrojs/mdx": "^4.3.12", + "@algolia/client-search": "^5.41.0", + "@apollo/client": "^3.14.0", + "@astro-community/astro-embed-youtube": "^0.5.10", + "@astrojs/mdx": "^4.3.13", "@astrojs/partytown": "^2.1.4", "@astrojs/preact": "^4.1.3", "@astrojs/prism": "^3.3.0", "@astrojs/react": "^4.4.2", - "@astrojs/sitemap": "^3.6.0", + "@astrojs/sitemap": "^3.7.0", + "@astrojs/tailwind": "^6.0.2", "@astrojs/vercel": "^8.2.11", + "@chainlink/blocks": "^1.3.1", "@chainlink/cl-search-frontend": "^0.12.1", "@chainlink/components": "^0.4.18", "@chainlink/contracts": "1.5.0", @@ -27,43 +31,44 @@ "@chainlink/local": "0.2.7-beta", "@chainlink/solana-sdk": "^0.2.2", "@metamask/providers": "^22.1.1", - "@nanostores/persistent": "^1.1.0", + "@nanostores/persistent": "^1.3.3", "@nanostores/preact": "^0.5.2", "@nanostores/react": "^0.8.4", "@openzeppelin/contracts": "5.4.0", - "@solana-program/compute-budget": "^0.11.0", + "@solana-program/compute-budget": "^0.12.0", "@solana-program/system": "^0.10.0", "@solana-program/token": "^0.9.0", - "@solana-program/token-2022": "^0.6.1", - "@solana/kit": "^5.0.0", - "@solana/react": "^5.0.0", + "@solana-program/token-2022": "^0.8.0", + "@solana/kit": "^5.5.1", + "@solana/react": "^5.5.1", "@solana/wallet-adapter-base": "^0.9.27", "@solana/wallet-adapter-coinbase": "^0.1.23", "@solana/wallet-adapter-react": "^0.15.39", "@solana/wallet-adapter-react-ui": "^0.9.39", "@solana/wallet-adapter-solflare": "^0.6.32", "@solana/wallet-adapter-trust": "^0.1.17", - "@supabase/supabase-js": "^2.84.0", - "astro": "^5.16.0", + "@supabase/supabase-js": "^2.95.3", + "astro": "^5.17.1", "bignumber.js": "^9.3.1", "bs58": "^6.0.0", "clipboard": "^2.0.11", "dotenv": "^16.6.1", - "ethers": "^6.15.0", - "focus-trap-react": "^11.0.4", + "ethers": "^6.16.0", + "focus-trap-react": "^11.0.6", "github-slugger": "^2.0.0", - "lodash": "^4.17.21", + "lodash": "^4.17.23", "marked": "^15.0.12", "nanostores": "^0.11.4", + "next": "14.2.35", "pino": "^9.14.0", - "preact": "^10.27.2", - "react-instantsearch": "^7.20.0", + "preact": "^10.28.3", + "react-instantsearch": "^7.23.1", "rehype-autolink-headings": "^7.1.0", "rehype-slug": "^6.0.0", "rehype-wrap-all": "^1.1.0", "remark-directive": "^3.0.1", - "swagger-ui-dist": "^5.30.1", - "swagger-ui-react": "^5.30.1", + "swagger-ui-dist": "^5.31.0", + "swagger-ui-react": "^5.31.0", "tweetnacl": "^1.0.3", "uuid": "^11.1.0" }, @@ -73,11 +78,11 @@ "@project-serum/anchor": "^0.26.0", "@rollup/plugin-yaml": "^4.1.2", "@types/jest": "^29.5.14", - "@types/lodash": "^4.17.21", - "@types/node": "^20.19.25", + "@types/lodash": "^4.17.23", + "@types/node": "^20.19.33", "@types/node-fetch": "^2.6.13", "@types/prismjs": "^1.26.5", - "@types/react": "^19.2.7", + "@types/react": "^19.2.13", "@types/react-dom": "^19.2.3", "@types/swagger-ui-dist": "^3.30.6", "@types/swagger-ui-react": "^5.18.0", @@ -88,28 +93,31 @@ "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.32.0", "eslint-plugin-n": "^15.7.0", - "eslint-plugin-prettier": "^5.5.0", + "eslint-plugin-prettier": "^5.5.5", "eslint-plugin-promise": "^6.1.1", "husky": "^9.1.7", "jest-yaml-transform": "^0.2.0", - "knip": "^5.70.1", + "knip": "^5.83.1", "lint-staged": "^15.5.2", "openapi-types": "^12.1.3", - "pino-pretty": "^13.1.2", - "prettier": "^3.5.3", + "pino-pretty": "^13.1.3", + "prettier": "^3.8.1", "prettier-plugin-astro": "^0.14.1", + "prettier-plugin-solidity": "^1.4.3", "remark-gfm": "^4.0.0", "remark-mdx": "^3.1.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", - "solhint": "^6.0.1", + "solhint": "^6.0.3", "solhint-plugin-chainlink-solidity": "github:smartcontractkit/chainlink-solhint-rules#v1.3.0", - "ts-jest": "^29.4.5", + "solhint-plugin-prettier": "^0.1.0", + "tailwindcss": "^3.4.18", + "ts-jest": "^29.4.6", "tsconfig-paths": "^4.2.0", - "tsx": "^4.20.6", + "tsx": "^4.21.0", "typescript": "^5.9.3", "unified": "^11.0.4", - "unist-util-visit": "^5.0.0", + "unist-util-visit": "^5.1.0", "vite": "^6.4.1" }, "engines": { @@ -141,176 +149,121 @@ "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", "license": "MIT" }, - "node_modules/@ai-sdk/gateway": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-2.0.15.tgz", - "integrity": "sha512-i1YVKzC1dg9LGvt+GthhD7NlRhz9J4+ZRj3KELU14IZ/MHPsOBiFeEoCCIDLR+3tqT8/+5nIsK3eZ7DFRfMfdw==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "2.0.0", - "@ai-sdk/provider-utils": "3.0.17", - "@vercel/oidc": "3.0.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/gateway/node_modules/@vercel/oidc": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.0.5.tgz", - "integrity": "sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==", - "license": "Apache-2.0", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@ai-sdk/provider": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", - "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", - "license": "Apache-2.0", - "dependencies": { - "json-schema": "^0.4.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ai-sdk/provider-utils": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.17.tgz", - "integrity": "sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "2.0.0", - "@standard-schema/spec": "^1.0.0", - "eventsource-parser": "^3.0.6" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, "node_modules/@algolia/abtesting": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.11.0.tgz", - "integrity": "sha512-a7oQ8dwiyoyVmzLY0FcuBqyqcNSq78qlcOtHmNBumRlHCSnXDcuoYGBGPN1F6n8JoGhviDDsIaF/oQrzTzs6Lg==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.14.0.tgz", + "integrity": "sha512-cZfj+1Z1dgrk3YPtNQNt0H9Rr67P8b4M79JjUKGS0d7/EbFbGxGgSu6zby5f22KXo3LT0LZa4O2c6VVbupJuDg==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-abtesting": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.45.0.tgz", - "integrity": "sha512-WTW0VZA8xHMbzuQD5b3f41ovKZ0MNTIXkWfm0F2PU+XGcLxmxX15UqODzF2sWab0vSbi3URM1xLhJx+bXbd1eQ==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.48.0.tgz", + "integrity": "sha512-n17WSJ7vazmM6yDkWBAjY12J8ERkW9toOqNgQ1GEZu/Kc4dJDJod1iy+QP5T/UlR3WICgZDi/7a/VX5TY5LAPQ==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.45.0.tgz", - "integrity": "sha512-I3g7VtvG/QJOH3tQO7E7zWTwBfK/nIQXShFLR8RvPgWburZ626JNj332M3wHCYcaAMivN9WJG66S2JNXhm6+Xg==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.48.0.tgz", + "integrity": "sha512-v5bMZMEqW9U2l40/tTAaRyn4AKrYLio7KcRuHmLaJtxuJAhvZiE7Y62XIsF070juz4MN3eyvfQmI+y5+OVbZuA==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.45.0.tgz", - "integrity": "sha512-/nTqm1tLiPtbUr+8kHKyFiCOfhRfgC+JxLvOCq471gFZZOlsh6VtFRiKI60/zGmHTojFC6B0mD80PB7KeK94og==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.48.0.tgz", + "integrity": "sha512-7H3DgRyi7UByScc0wz7EMrhgNl7fKPDjKX9OcWixLwCj7yrRXDSIzwunykuYUUO7V7HD4s319e15FlJ9CQIIFQ==", "license": "MIT", "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-insights": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.45.0.tgz", - "integrity": "sha512-suQTx/1bRL1g/K2hRtbK3ANmbzaZCi13487sxxmqok+alBDKKw0/TI73ZiHjjFXM2NV52inwwcmW4fUR45206Q==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.48.0.tgz", + "integrity": "sha512-tXmkB6qrIGAXrtRYHQNpfW0ekru/qymV02bjT0w5QGaGw0W91yT+53WB6dTtRRsIrgS30Al6efBvyaEosjZ5uw==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.45.0.tgz", - "integrity": "sha512-CId/dbjpzI3eoUhPU6rt/z4GrRsDesqFISEMOwrqWNSrf4FJhiUIzN42Ac+Gzg69uC0RnzRYy60K1y4Na5VSMw==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.48.0.tgz", + "integrity": "sha512-4tXEsrdtcBZbDF73u14Kb3otN+xUdTVGop1tBjict+Rc/FhsJQVIwJIcTrOJqmvhtBfc56Bu65FiVOnpAZCxcw==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.45.0.tgz", - "integrity": "sha512-tjbBKfA8fjAiFtvl9g/MpIPiD6pf3fj7rirVfh1eMIUi8ybHP4ovDzIaE216vHuRXoePQVCkMd2CokKvYq1CLw==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.48.0.tgz", + "integrity": "sha512-unzSUwWFpsDrO8935RhMAlyK0Ttua/5XveVIwzfjs5w+GVBsHgIkbOe8VbBJccMU/z1LCwvu1AY3kffuSLAR5Q==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.45.0.tgz", - "integrity": "sha512-nxuCid+Nszs4xqwIMDw11pRJPes2c+Th1yup/+LtpjFH8QWXkr3SirNYSD3OXAeM060HgWWPLA8/Fxk+vwxQOA==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.48.0.tgz", + "integrity": "sha512-RB9bKgYTVUiOcEb5bOcZ169jiiVW811dCsJoLT19DcbbFmU4QaK0ghSTssij35QBQ3SCOitXOUrHcGgNVwS7sQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" @@ -323,84 +276,84 @@ "license": "MIT" }, "node_modules/@algolia/ingestion": { - "version": "1.45.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.45.0.tgz", - "integrity": "sha512-t+1doBzhkQTeOOjLHMlm4slmXBhvgtEGQhOmNpMPTnIgWOyZyESWdm+XD984qM4Ej1i9FRh8VttOGrdGnAjAng==", + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.48.0.tgz", + "integrity": "sha512-rhoSoPu+TDzDpvpk3cY/pYgbeWXr23DxnAIH/AkN0dUC+GCnVIeNSQkLaJ+CL4NZ51cjLIjksrzb4KC5Xu+ktw==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.45.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.45.0.tgz", - "integrity": "sha512-IaX3ZX1A/0wlgWZue+1BNWlq5xtJgsRo7uUk/aSiYD7lPbJ7dFuZ+yTLFLKgbl4O0QcyHTj1/mSBj9ryF1Lizg==", + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.48.0.tgz", + "integrity": "sha512-aSe6jKvWt+8VdjOaq2ERtsXp9+qMXNJ3mTyTc1VMhNfgPl7ArOhRMRSQ8QBnY8ZL4yV5Xpezb7lAg8pdGrrulg==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.45.0.tgz", - "integrity": "sha512-1jeMLoOhkgezCCPsOqkScwYzAAc1Jr5T2hisZl0s32D94ZV7d1OHozBukgOjf8Dw+6Hgi6j52jlAdUWTtkX9Mg==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.48.0.tgz", + "integrity": "sha512-p9tfI1bimAaZrdiVExL/dDyGUZ8gyiSHsktP1ZWGzt5hXpM3nhv4tSjyHtXjEKtA0UvsaHKwSfFE8aAAm1eIQA==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/client-common": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/client-common": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.45.0.tgz", - "integrity": "sha512-46FIoUkQ9N7wq4/YkHS5/W9Yjm4Ab+q5kfbahdyMpkBPJ7IBlwuNEGnWUZIQ6JfUZuJVojRujPRHMihX4awUMg==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.48.0.tgz", + "integrity": "sha512-XshyfpsQB7BLnHseMinp3fVHOGlTv6uEHOzNK/3XrEF9mjxoZAcdVfY1OCXObfwRWX5qXZOq8FnrndFd44iVsQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.45.0" + "@algolia/client-common": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.45.0.tgz", - "integrity": "sha512-XFTSAtCwy4HdBhSReN2rhSyH/nZOM3q3qe5ERG2FLbYId62heIlJBGVyAPRbltRwNlotlydbvSJ+SQ0ruWC2cw==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.48.0.tgz", + "integrity": "sha512-Q4XNSVQU89bKNAPuvzSYqTH9AcbOOiIo6AeYMQTxgSJ2+uvT78CLPMG89RIIloYuAtSfE07s40OLV50++l1Bbw==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.45.0" + "@algolia/client-common": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.45.0.tgz", - "integrity": "sha512-8mTg6lHx5i44raCU52APsu0EqMsdm4+7Hch/e4ZsYZw0hzwkuaMFh826ngnkYf9XOl58nHoou63aZ874m8AbpQ==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.48.0.tgz", + "integrity": "sha512-ZgxV2+5qt3NLeUYBTsi6PLyHcENQWC0iFppFZekHSEDA2wcLdTUjnaJzimTEULHIvJuLRCkUs4JABdhuJktEag==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.45.0" + "@algolia/client-common": "5.48.0" }, "engines": { "node": ">= 14.0.0" @@ -472,6 +425,47 @@ "openapi-types": ">=7" } }, + "node_modules/@apollo/client": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.14.0.tgz", + "integrity": "sha512-0YQKKRIxiMlIou+SekQqdCo0ZTHxOcES+K8vKB53cIDpwABNR0P0yRzPgsbgcj3zRJniD93S/ontsnZsCLZrxQ==", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@wry/caches": "^1.0.0", + "@wry/equality": "^0.5.6", + "@wry/trie": "^0.5.0", + "graphql-tag": "^2.12.6", + "hoist-non-react-statics": "^3.3.2", + "optimism": "^0.18.0", + "prop-types": "^15.7.2", + "rehackt": "^0.1.0", + "symbol-observable": "^4.0.0", + "ts-invariant": "^0.10.3", + "tslib": "^2.3.0", + "zen-observable-ts": "^1.2.5" + }, + "peerDependencies": { + "graphql": "^15.0.0 || ^16.0.0", + "graphql-ws": "^5.5.5 || ^6.0.3", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc", + "subscriptions-transport-ws": "^0.9.0 || ^0.11.0" + }, + "peerDependenciesMeta": { + "graphql-ws": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "subscriptions-transport-ws": { + "optional": true + } + } + }, "node_modules/@arbitrum/nitro-contracts": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@arbitrum/nitro-contracts/-/nitro-contracts-3.0.0.tgz", @@ -499,15 +493,12 @@ "license": "MIT" }, "node_modules/@astro-community/astro-embed-youtube": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/@astro-community/astro-embed-youtube/-/astro-embed-youtube-0.5.9.tgz", - "integrity": "sha512-8Uk2SKbyZVb+jxwqSAMoEpQo+063XYwCI3yRy9cbkyHpu09mDabGZNTF5XrL8CKr3NtR5haBkeYK/kSuKUkJ/g==", + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@astro-community/astro-embed-youtube/-/astro-embed-youtube-0.5.10.tgz", + "integrity": "sha512-hVlx77KQLjKzElVQnrU5znQ5/E60keVSAPrhuWvQQHuqva5auJtt8YBpOThkwDMuEKXjQybEF1/3C07RZ8MAOQ==", "license": "MIT", "dependencies": { "lite-youtube-embed": "^0.3.4" - }, - "peerDependencies": { - "astro": "^2.0.0 || ^3.0.0-beta || ^4.0.0-beta || ^5.0.0-beta" } }, "node_modules/@astrojs/compiler": { @@ -523,9 +514,9 @@ "license": "MIT" }, "node_modules/@astrojs/markdown-remark": { - "version": "6.3.9", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.9.tgz", - "integrity": "sha512-hX2cLC/KW74Io1zIbn92kI482j9J7LleBLGCVU9EP3BeH5MVrnFawOnqD0t/q6D1Z+ZNeQG2gNKMslCcO36wng==", + "version": "6.3.10", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.10.tgz", + "integrity": "sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==", "license": "MIT", "dependencies": { "@astrojs/internal-helpers": "0.7.5", @@ -534,7 +525,7 @@ "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", @@ -542,8 +533,8 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", - "shiki": "^3.13.0", - "smol-toml": "^1.4.2", + "shiki": "^3.19.0", + "smol-toml": "^1.5.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", @@ -552,12 +543,12 @@ } }, "node_modules/@astrojs/mdx": { - "version": "4.3.12", - "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.3.12.tgz", - "integrity": "sha512-pL3CVPtuQrPnDhWjy7zqbOibNyPaxP4VpQS8T8spwKqKzauJ4yoKyNkVTD8jrP7EAJHmBhZ7PTmUGZqOpKKp8g==", + "version": "4.3.13", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.3.13.tgz", + "integrity": "sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q==", "license": "MIT", "dependencies": { - "@astrojs/markdown-remark": "6.3.9", + "@astrojs/markdown-remark": "6.3.10", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.15.0", "es-module-lexer": "^1.7.0", @@ -639,16 +630,59 @@ } }, "node_modules/@astrojs/sitemap": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.6.0.tgz", - "integrity": "sha512-4aHkvcOZBWJigRmMIAJwRQXBS+ayoP5z40OklTXYXhUDhwusz+DyDl+nSshY6y9DvkVEavwNcFO8FD81iGhXjg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.0.tgz", + "integrity": "sha512-+qxjUrz6Jcgh+D5VE1gKUJTA3pSthuPHe6Ao5JCxok794Lewx8hBFaWHtOnN0ntb2lfOf7gvOi9TefUswQ/ZVA==", "license": "MIT", "dependencies": { - "sitemap": "^8.0.0", + "sitemap": "^8.0.2", "stream-replace-string": "^2.0.0", "zod": "^3.25.76" } }, + "node_modules/@astrojs/tailwind": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/tailwind/-/tailwind-6.0.2.tgz", + "integrity": "sha512-j3mhLNeugZq6A8dMNXVarUa8K6X9AW+QHU9u3lKNrPLMHhOQ0S7VeWhHwEeJFpEK1BTKEUY1U78VQv2gN6hNGg==", + "license": "MIT", + "dependencies": { + "autoprefixer": "^10.4.21", + "postcss": "^8.5.3", + "postcss-load-config": "^4.0.2" + }, + "peerDependencies": { + "astro": "^3.0.0 || ^4.0.0 || ^5.0.0", + "tailwindcss": "^3.0.24" + } + }, + "node_modules/@astrojs/tailwind/node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/@astrojs/telemetry": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", @@ -1288,17 +1322,525 @@ "peer": true }, "node_modules/@capsizecss/unpack": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-3.0.1.tgz", - "integrity": "sha512-8XqW8xGn++Eqqbz3e9wKuK7mxryeRjs4LOHLxbh2lwKeSbuNR4NFifDZT4KzvjU6HMOPbiNTsWpniK5EJfTWkg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.0.tgz", + "integrity": "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==", "license": "MIT", "dependencies": { - "fontkit": "^2.0.2" + "fontkitten": "^1.0.0" }, "engines": { "node": ">=18" } }, + "node_modules/@chainlink/blocks": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@chainlink/blocks/-/blocks-1.3.1.tgz", + "integrity": "sha512-0Px46fJA7aIm7cFuF/6CgV1ZSbkNKfe+QBA0XO7j9Ld8cevlIF/r4GsqR5zDbSaHPejvRloMQJVZoBsU9qINnA==", + "license": "ISC", + "dependencies": { + "@floating-ui/react": "0.22.2", + "@hookform/resolvers": "3.9.1", + "@radix-ui/react-accordion": "1.2.1", + "@radix-ui/react-checkbox": "1.1.2", + "@radix-ui/react-dialog": "1.1.6", + "@radix-ui/react-dropdown-menu": "2.0.6", + "@radix-ui/react-label": "2.1.0", + "@radix-ui/react-navigation-menu": "1.1.3", + "@radix-ui/react-popover": "1.1.1", + "@radix-ui/react-radio-group": "1.2.1", + "@radix-ui/react-select": "2.1.2", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-switch": "1.1.1", + "@radix-ui/react-tabs": "1.1.3", + "@radix-ui/react-toast": "1.2.4", + "@radix-ui/react-toggle": "1.1.9", + "@radix-ui/react-toggle-group": "1.1.9", + "@radix-ui/react-tooltip": "1.0.7", + "@tailwindcss/container-queries": "0.1.1", + "@tanstack/react-query": "5.69.0", + "@tanstack/react-table": "8.20.5", + "apexcharts": "4.5.0", + "class-variance-authority": "0.7.0", + "clsx": "2.1.1", + "lucide-react": "0.390.0", + "react": "18.3.1", + "react-apexcharts": "1.7.0", + "react-dom": "18.3.1", + "react-hook-form": "7.53.1", + "react-modal": "3.16.1", + "react-transition-group": "4.4.5", + "sonner": "1.7.3", + "tailwind-merge": "2.3.0", + "tailwindcss": "3.4.4", + "tailwindcss-animate": "1.0.7", + "zod": "3.25.76" + }, + "peerDependencies": { + "react": ">=18.0.0 <19.0.0", + "react-dom": ">=18.0.0 <19.0.0", + "tailwindcss": ">=3.0.0 <4.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": false + }, + "react-dom": { + "optional": false + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz", + "integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz", + "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz", + "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-id/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz", + "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", + "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-controllable-state/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@chainlink/blocks/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/@chainlink/blocks/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@chainlink/blocks/node_modules/tailwindcss": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", + "integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@chainlink/cl-search-frontend": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@chainlink/cl-search-frontend/-/cl-search-frontend-0.12.1.tgz", @@ -1366,43 +1908,68 @@ ], "license": "MIT", "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/sha2": "^5.8.0" + } + }, + "node_modules/@chainlink/components/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/@chainlink/components/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@chainlink/components/node_modules/tailwindcss": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", + "integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" } }, "node_modules/@chainlink/contracts": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-1.5.0.tgz", "integrity": "sha512-1fGJwjvivqAxvVOTqZUEXGR54CATtg0vjcXgSIk4Cfoad2nUhSG/qaWHXjLg1CkNTeOoteoxGQcpP/HiA5HsUA==", - "license": "BUSL-1.1", "dependencies": { "@arbitrum/nitro-contracts": "3.0.0", "@changesets/cli": "^2.29.6", @@ -1659,25 +2226,6 @@ "bn.js": "^5.2.1" } }, - "node_modules/@chainlink/contracts-1.4.0/node_modules/@ethersproject/bytes": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", - "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, "node_modules/@chainlink/contracts-1.4.0/node_modules/@ethersproject/constants": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", @@ -1837,22 +2385,6 @@ "js-sha3": "0.8.0" } }, - "node_modules/@chainlink/contracts-1.4.0/node_modules/@ethersproject/logger": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", - "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT" - }, "node_modules/@chainlink/contracts-1.4.0/node_modules/@ethersproject/networks": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", @@ -1872,46 +2404,6 @@ "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@chainlink/contracts-1.4.0/node_modules/@ethersproject/pbkdf2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", - "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/sha2": "^5.8.0" - } - }, - "node_modules/@chainlink/contracts-1.4.0/node_modules/@ethersproject/properties": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", - "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, "node_modules/@chainlink/contracts-1.4.0/node_modules/@ethersproject/providers": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.8.0.tgz", @@ -1992,28 +2484,6 @@ "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@chainlink/contracts-1.4.0/node_modules/@ethersproject/sha2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", - "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "hash.js": "1.1.7" - } - }, "node_modules/@chainlink/contracts-1.4.0/node_modules/@ethersproject/signing-key": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", @@ -2587,25 +3057,6 @@ "bn.js": "^5.2.1" } }, - "node_modules/@chainlink/contracts-ccip/node_modules/@ethersproject/bytes": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", - "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, "node_modules/@chainlink/contracts-ccip/node_modules/@ethersproject/constants": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", @@ -2765,22 +3216,6 @@ "js-sha3": "0.8.0" } }, - "node_modules/@chainlink/contracts-ccip/node_modules/@ethersproject/logger": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", - "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT" - }, "node_modules/@chainlink/contracts-ccip/node_modules/@ethersproject/networks": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", @@ -2800,46 +3235,6 @@ "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@chainlink/contracts-ccip/node_modules/@ethersproject/pbkdf2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", - "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/sha2": "^5.8.0" - } - }, - "node_modules/@chainlink/contracts-ccip/node_modules/@ethersproject/properties": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", - "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, "node_modules/@chainlink/contracts-ccip/node_modules/@ethersproject/providers": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.8.0.tgz", @@ -2920,28 +3315,6 @@ "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@chainlink/contracts-ccip/node_modules/@ethersproject/sha2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", - "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "hash.js": "1.1.7" - } - }, "node_modules/@chainlink/contracts-ccip/node_modules/@ethersproject/signing-key": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", @@ -3235,7 +3608,6 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3399,8 +3771,8 @@ }, "node_modules/@chainlink/contracts/node_modules/@ethersproject/basex": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.8.0.tgz", - "integrity": "sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", + "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", "funding": [ { "type": "individual", @@ -3414,8 +3786,7 @@ "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/properties": "^5.8.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@chainlink/contracts/node_modules/@ethersproject/bignumber": { @@ -3439,25 +3810,6 @@ "bn.js": "^5.2.1" } }, - "node_modules/@chainlink/contracts/node_modules/@ethersproject/bytes": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", - "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, "node_modules/@chainlink/contracts/node_modules/@ethersproject/constants": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", @@ -3617,22 +3969,6 @@ "js-sha3": "0.8.0" } }, - "node_modules/@chainlink/contracts/node_modules/@ethersproject/logger": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", - "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT" - }, "node_modules/@chainlink/contracts/node_modules/@ethersproject/networks": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", @@ -3652,46 +3988,6 @@ "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@chainlink/contracts/node_modules/@ethersproject/pbkdf2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", - "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/sha2": "^5.8.0" - } - }, - "node_modules/@chainlink/contracts/node_modules/@ethersproject/properties": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", - "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, "node_modules/@chainlink/contracts/node_modules/@ethersproject/providers": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.8.0.tgz", @@ -3772,28 +4068,6 @@ "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@chainlink/contracts/node_modules/@ethersproject/sha2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", - "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "hash.js": "1.1.7" - } - }, "node_modules/@chainlink/contracts/node_modules/@ethersproject/signing-key": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", @@ -4116,6 +4390,60 @@ "tailwindcss-animate": "1.0.7" } }, + "node_modules/@chainlink/design-system/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/@chainlink/design-system/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@chainlink/design-system/node_modules/tailwindcss": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", + "integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@chainlink/local": { "version": "0.2.7-beta", "resolved": "https://registry.npmjs.org/@chainlink/local/-/local-0.2.7-beta.tgz", @@ -5639,9 +5967,9 @@ } }, "node_modules/@ethersproject/bytes": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", - "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", "funding": [ { "type": "individual", @@ -5652,9 +5980,8 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { - "@ethersproject/logger": "^5.7.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/constants": { @@ -5731,73 +6058,6 @@ "@ethersproject/strings": "^5.7.0" } }, - "node_modules/@ethersproject/hdnode": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", - "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, - "node_modules/@ethersproject/json-wallets": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", - "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "license": "MIT" - }, "node_modules/@ethersproject/keccak256": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", @@ -5819,9 +6079,9 @@ } }, "node_modules/@ethersproject/logger": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", "funding": [ { "type": "individual", @@ -5831,8 +6091,7 @@ "type": "individual", "url": "https://www.buymeacoffee.com/ricmoo" } - ], - "license": "MIT" + ] }, "node_modules/@ethersproject/networks": { "version": "5.7.1", @@ -5854,9 +6113,9 @@ } }, "node_modules/@ethersproject/pbkdf2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", - "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", + "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", "funding": [ { "type": "individual", @@ -5867,16 +6126,16 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", + "peer": true, "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/sha2": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/sha2": "^5.8.0" } }, "node_modules/@ethersproject/properties": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", - "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", + "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", "funding": [ { "type": "individual", @@ -5887,9 +6146,8 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { - "@ethersproject/logger": "^5.7.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/providers": { @@ -5992,9 +6250,9 @@ } }, "node_modules/@ethersproject/sha2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", - "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", + "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", "funding": [ { "type": "individual", @@ -6005,10 +6263,9 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", "hash.js": "1.1.7" } }, @@ -6036,30 +6293,6 @@ "hash.js": "1.1.7" } }, - "node_modules/@ethersproject/solidity": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", - "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, "node_modules/@ethersproject/strings": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", @@ -6108,60 +6341,6 @@ "@ethersproject/signing-key": "^5.7.0" } }, - "node_modules/@ethersproject/units": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", - "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/wallet": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", - "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/json-wallets": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, "node_modules/@ethersproject/web": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", @@ -6185,29 +6364,6 @@ "@ethersproject/strings": "^5.7.0" } }, - "node_modules/@ethersproject/wordlists": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", - "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, "node_modules/@floating-ui/core": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", @@ -6261,6 +6417,24 @@ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "license": "MIT", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@hookform/resolvers": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.1.tgz", + "integrity": "sha512-ud2HqmGBM0P0IABqoskKWI6PEf6ZDDBZkFqe2Vnl+mTHCEHzr3ISjjZyCwTjC/qpL25JC9aIDkloQejvMeq0ug==", + "license": "MIT", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -8418,9 +8592,9 @@ } }, "node_modules/@nanostores/persistent": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@nanostores/persistent/-/persistent-1.2.0.tgz", - "integrity": "sha512-kf5WOLpVI9Pk+AwXHIax4in3pesNe8299BEGQ2H8kgI05SZw7KKWCDv7bt2FOlND8E5y7rO5PRW34q0UCAl/DA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@nanostores/persistent/-/persistent-1.3.3.tgz", + "integrity": "sha512-+b4I8xrmjhKE3hQ9V7/b4Xa+MBMkM2P4Ulv33zFEF/+2Hucsb24vTjYiWR8R97y8YdRptmRKlL5Qwy0q1Jj5nQ==", "funding": [ { "type": "github", @@ -8474,24 +8648,23 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", - "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.0.tgz", + "integrity": "sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "node_modules/@next/env": { - "version": "14.2.33", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.33.tgz", - "integrity": "sha512-CgVHNZ1fRIlxkLhIX22flAZI/HmpDaZ8vwyJ/B0SDPTBuLZ1PJ+DWMjCHhqnExfmSQzA/PbZi8OAc7PAq2w9IA==", - "license": "MIT", - "peer": true + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.35.tgz", + "integrity": "sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==", + "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { "version": "14.2.33", @@ -8505,7 +8678,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 10" } @@ -8522,7 +8694,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 10" } @@ -8539,7 +8710,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10" } @@ -8556,7 +8726,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10" } @@ -8573,7 +8742,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10" } @@ -8590,7 +8758,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10" } @@ -8607,7 +8774,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 10" } @@ -8624,7 +8790,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 10" } @@ -8641,7 +8806,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 10" } @@ -8730,15 +8894,6 @@ "integrity": "sha512-+wuegAMaLcZnLCJIvrVUDzA9z/Wp93f0Dla/4jJvIhijRrPabjQbZe6fWiECLaJyfn5ci9fqf9vTw3xpQOad2A==", "license": "MIT" }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/@openzeppelin/contracts": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.4.0.tgz", @@ -8793,9 +8948,9 @@ "license": "MIT" }, "node_modules/@oxc-resolver/binding-android-arm-eabi": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.14.0.tgz", - "integrity": "sha512-jB47iZ/thvhE+USCLv+XY3IknBbkKr/p7OBsQDTHode/GPw+OHRlit3NQ1bjt1Mj8V2CS7iHdSDYobZ1/0gagQ==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.15.0.tgz", + "integrity": "sha512-Q+lWuFfq7whNelNJIP1dhXaVz4zO9Tu77GcQHyxDWh3MaCoO2Bisphgzmsh4ZoUe2zIchQh6OvQL99GlWHg9Tw==", "cpu": [ "arm" ], @@ -8807,9 +8962,9 @@ ] }, "node_modules/@oxc-resolver/binding-android-arm64": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.14.0.tgz", - "integrity": "sha512-XFJ9t7d/Cz+dWLyqtTy3Xrekz+qqN4hmOU2iOUgr7u71OQsPUHIIeS9/wKanEK0l413gPwapIkyc5x9ltlOtyw==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.15.0.tgz", + "integrity": "sha512-vbdBttesHR0W1oJaxgWVTboyMUuu+VnPsHXJ6jrXf4czELzB6GIg5DrmlyhAmFBhjwov+yJH/DfTnHS+2sDgOw==", "cpu": [ "arm64" ], @@ -8821,9 +8976,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-arm64": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.14.0.tgz", - "integrity": "sha512-gwehBS9smA1mzK8frDsmUCHz+6baJVwkKF6qViHhoqA3kRKvIZ3k6WNP4JmF19JhOiGxRcoPa8gZRfzNgXwP2A==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.15.0.tgz", + "integrity": "sha512-R67lsOe1UzNjqVBCwCZX1rlItTsj/cVtBw4Uy19CvTicqEWvwaTn8t34zLD75LQwDDPCY3C8n7NbD+LIdw+ZoA==", "cpu": [ "arm64" ], @@ -8835,9 +8990,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-x64": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.14.0.tgz", - "integrity": "sha512-5wwJvfuoahKiAqqAsMLOI28rqdh3P2K7HkjIWUXNMWAZq6ErX0L5rwJzu6T32+Zxw3k18C7R9IS4wDq/3Ar+6w==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.15.0.tgz", + "integrity": "sha512-77mya5F8WV0EtCxI0MlVZcqkYlaQpfNwl/tZlfg4jRsoLpFbaTeWv75hFm6TE84WULVlJtSgvf7DhoWBxp9+ZQ==", "cpu": [ "x64" ], @@ -8849,9 +9004,9 @@ ] }, "node_modules/@oxc-resolver/binding-freebsd-x64": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.14.0.tgz", - "integrity": "sha512-MWTt+LOQNcQ6fa+Uu5VikkihLi1PSIrQqqp0QD44k2AORasNWl0jRGBTcMSBIgNe82qEQWYvlGzvOEEOBp01Og==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.15.0.tgz", + "integrity": "sha512-X1Sz7m5PC+6D3KWIDXMUtux+0Imj6HfHGdBStSvgdI60OravzI1t83eyn6eN0LPTrynuPrUgjk7tOnOsBzSWHw==", "cpu": [ "x64" ], @@ -8863,9 +9018,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.14.0.tgz", - "integrity": "sha512-b6/IBqYrS3o0XiLVBsnex/wK8pTTK+hbGfAMOHVU6p7DBpwPPLgC/tav4IXoOIUCssTFz7aWh/xtUok0swn8VQ==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.15.0.tgz", + "integrity": "sha512-L1x/wCaIRre+18I4cH/lTqSAymlV0k4HqfSYNNuI9oeL28Ks86lI6O5VfYL6sxxWYgjuWB98gNGo7tq7d4GarQ==", "cpu": [ "arm" ], @@ -8877,9 +9032,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.14.0.tgz", - "integrity": "sha512-o2Qh5+y5YoqVK6YfzkalHdpmQ5bkbGGxuLg1pZLQ1Ift0x+Vix7DaFEpdCl5Z9xvYXogd/TwOlL0TPl4+MTFLA==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.15.0.tgz", + "integrity": "sha512-abGXd/zMGa0tH8nKlAXdOnRy4G7jZmkU0J85kMKWns161bxIgGn/j7zxqh3DKEW98wAzzU9GofZMJ0P5YCVPVw==", "cpu": [ "arm" ], @@ -8891,9 +9046,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.14.0.tgz", - "integrity": "sha512-lk8mCSg0Tg4sEG73RiPjb7keGcEPwqQnBHX3Z+BR2SWe+qNHpoHcyFMNafzSvEC18vlxC04AUSoa6kJl/C5zig==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.15.0.tgz", + "integrity": "sha512-SVjjjtMW66Mza76PBGJLqB0KKyFTBnxmtDXLJPbL6ZPGSctcXVmujz7/WAc0rb9m2oV0cHQTtVjnq6orQnI/jg==", "cpu": [ "arm64" ], @@ -8905,9 +9060,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-musl": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.14.0.tgz", - "integrity": "sha512-KykeIVhCM7pn93ABa0fNe8vk4XvnbfZMELne2s6P9tdJH9KMBsCFBi7a2BmSdUtTqWCAJokAcm46lpczU52Xaw==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.15.0.tgz", + "integrity": "sha512-JDv2/AycPF2qgzEiDeMJCcSzKNDm3KxNg0KKWipoKEMDFqfM7LxNwwSVyAOGmrYlE4l3dg290hOMsr9xG7jv9g==", "cpu": [ "arm64" ], @@ -8919,9 +9074,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.14.0.tgz", - "integrity": "sha512-QqPPWAcZU/jHAuam4f3zV8OdEkYRPD2XR0peVet3hoMMgsihR3Lhe7J/bLclmod297FG0+OgBYQVMh2nTN6oWA==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.15.0.tgz", + "integrity": "sha512-zbu9FhvBLW4KJxo7ElFvZWbSt4vP685Qc/Gyk/Ns3g2gR9qh2qWXouH8PWySy+Ko/qJ42+HJCLg+ZNcxikERfg==", "cpu": [ "ppc64" ], @@ -8933,9 +9088,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.14.0.tgz", - "integrity": "sha512-DunWA+wafeG3hj1NADUD3c+DRvmyVNqF5LSHVUWA2bzswqmuEZXl3VYBSzxfD0j+UnRTFYLxf27AMptoMsepYg==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.15.0.tgz", + "integrity": "sha512-Kfleehe6B09C2qCnyIU01xLFqFXCHI4ylzkicfX/89j+gNHh9xyNdpEvit88Kq6i5tTGdavVnM6DQfOE2qNtlg==", "cpu": [ "riscv64" ], @@ -8947,9 +9102,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.14.0.tgz", - "integrity": "sha512-4SRvwKTTk2k67EQr9Ny4NGf/BhlwggCI1CXwBbA9IV4oP38DH8b+NAPxDY0ySGRsWbPkG92FYOqM4AWzG4GSgA==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.15.0.tgz", + "integrity": "sha512-J7LPiEt27Tpm8P+qURDwNc8q45+n+mWgyys4/V6r5A8v5gDentHRGUx3iVk5NxdKhgoGulrzQocPTZVosq25Eg==", "cpu": [ "riscv64" ], @@ -8961,9 +9116,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.14.0.tgz", - "integrity": "sha512-hZKvkbsurj4JOom//R1Ab2MlC4cGeVm5zzMt4IsS3XySQeYjyMJ5TDZ3J5rQ8bVj3xi4FpJU2yFZ72GApsHQ6A==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.15.0.tgz", + "integrity": "sha512-+8/d2tAScPjVJNyqa7GPGnqleTB/XW9dZJQ2D/oIM3wpH3TG+DaFEXBbk4QFJ9K9AUGBhvQvWU2mQyhK/yYn3Q==", "cpu": [ "s390x" ], @@ -8975,9 +9130,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-gnu": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.14.0.tgz", - "integrity": "sha512-hABxQXFXJurivw+0amFdeEcK67cF1BGBIN1+sSHzq3TRv4RoG8n5q2JE04Le2n2Kpt6xg4Y5+lcv+rb2mCJLgQ==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.15.0.tgz", + "integrity": "sha512-xtvSzH7Nr5MCZI2FKImmOdTl9kzuQ51RPyLh451tvD2qnkg3BaqI9Ox78bTk57YJhlXPuxWSOL5aZhKAc9J6qg==", "cpu": [ "x64" ], @@ -8989,9 +9144,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-musl": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.14.0.tgz", - "integrity": "sha512-Ln73wUB5migZRvC7obAAdqVwvFvk7AUs2JLt4g9QHr8FnqivlsjpUC9Nf2ssrybdjyQzEMjttUxPZz6aKPSAHw==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.15.0.tgz", + "integrity": "sha512-14YL1zuXj06+/tqsuUZuzL0T425WA/I4nSVN1kBXeC5WHxem6lQ+2HGvG+crjeJEqHgZUT62YIgj88W+8E7eyg==", "cpu": [ "x64" ], @@ -9002,10 +9157,24 @@ "linux" ] }, + "node_modules/@oxc-resolver/binding-openharmony-arm64": { + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.15.0.tgz", + "integrity": "sha512-/7Qli+1Wk93coxnrQaU8ySlICYN8HsgyIrzqjgIkQEpI//9eUeaeIHZptNl2fMvBGeXa7k2QgLbRNaBRgpnvMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@oxc-resolver/binding-wasm32-wasi": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.14.0.tgz", - "integrity": "sha512-z+NbELmCOKNtWOqEB5qDfHXOSWB3kGQIIehq6nHtZwHLzdVO2oBq6De/ayhY3ygriC1XhgaIzzniY7jgrNl4Kw==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.15.0.tgz", + "integrity": "sha512-q5rn2eIMQLuc/AVGR2rQKb2EVlgreATGG8xXg8f4XbbYCVgpxaq+dgMbiPStyNywW1MH8VU2T09UEm30UtOQvg==", "cpu": [ "wasm32" ], @@ -9013,16 +9182,16 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.7" + "@napi-rs/wasm-runtime": "^1.1.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.14.0.tgz", - "integrity": "sha512-Ft0+qd7HSO61qCTLJ4LCdBGZkpKyDj1rG0OVSZL1DxWQoh97m7vEHd7zAvUtw8EcWjOMBQuX4mfRap/x2MOCpQ==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.15.0.tgz", + "integrity": "sha512-yCAh2RWjU/8wWTxQDgGPgzV9QBv0/Ojb5ej1c/58iOjyTuy/J1ZQtYi2SpULjKmwIxLJdTiCHpMilauWimE31w==", "cpu": [ "arm64" ], @@ -9034,9 +9203,9 @@ ] }, "node_modules/@oxc-resolver/binding-win32-ia32-msvc": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-11.14.0.tgz", - "integrity": "sha512-o54jYNSfGdPxHSvXEhZg8FOV3K99mJ1f7hb1alRFb+Yec1GQXNrJXxZPIxNMYeFT13kwAWB7zuQ0HZLnDHFxfw==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-11.15.0.tgz", + "integrity": "sha512-lmXKb6lvA6M6QIbtYfgjd+AryJqExZVSY2bfECC18OPu7Lv1mHFF171Mai5l9hG3r4IhHPPIwT10EHoilSCYeA==", "cpu": [ "ia32" ], @@ -9048,9 +9217,9 @@ ] }, "node_modules/@oxc-resolver/binding-win32-x64-msvc": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.14.0.tgz", - "integrity": "sha512-j97icaORyM6A7GjgmUzfn7V+KGzVvctRA+eAlJb0c2OQNaETFxl6BXZdnGBDb+6oA0Y4Sr/wnekd1kQ0aVyKGg==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.15.0.tgz", + "integrity": "sha512-HZsfne0s/tGOcJK9ZdTGxsNU2P/dH0Shf0jqrPvsC6wX0Wk+6AyhSpHFLQCnLOuFQiHHU0ePfM8iYsoJb5hHpQ==", "cpu": [ "x64" ], @@ -9219,6 +9388,18 @@ "vite": ">=2.0.0" } }, + "node_modules/@prettier/sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.3.0.tgz", + "integrity": "sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw==", + "dev": true, + "funding": { + "url": "https://github.com/prettier/prettier-synchronized?sponsor=1" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, "node_modules/@project-serum/anchor": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.26.0.tgz", @@ -9297,6 +9478,12 @@ "node": ">=18.0.0" } }, + "node_modules/@radix-ui/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", + "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==", + "license": "MIT" + }, "node_modules/@radix-ui/primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", @@ -9306,6 +9493,236 @@ "@babel/runtime": "^7.13.10" } }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.1.tgz", + "integrity": "sha512-bg/l7l5QzUjgsh8kjwDFommzAshnUsuVMV5NM56QVCm+7ZckYdd9P/ExR8xG/Oup0OajVxNLaHJ1tb8mXk+nzQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collapsible": "1.1.1", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-arrow": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz", @@ -9330,6 +9747,415 @@ } } }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.2.tgz", + "integrity": "sha512-/i0fl686zaJbDQLNKrkCbMyDm6FQMt4jg323k7HuqitoANm9sE23Ql8yOK3Wusk34HSLKDChhMux05FnP6KUkw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-presence": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", + "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-previous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.1.tgz", + "integrity": "sha512-1///SnrfQHJEofLokyczERxQbWfCGQlQ2XsCZMucVs6it+lq9iw4vXy+uDn1edlb58cOZOWSldnfPAYcT4O/Yg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-presence": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", + "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz", @@ -9594,6 +10420,85 @@ } } }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", + "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-menu": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.6.tgz", @@ -10292,28 +11197,1731 @@ } } }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.2.1.tgz", + "integrity": "sha512-kdbv54g4vfRjja9DNWPMxKvXblzqbpEC8kspEkZ6dVP7kQksGCn+iZHkcCz2nb00+lPdRvxrqy4WrvvV1cNqrQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-presence": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", + "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", + "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-previous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-roving-focus": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz", "integrity": "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.1", - "@radix-ui/react-collection": "1.0.3", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-context": "1.0.1", - "@radix-ui/react-direction": "1.0.1", - "@radix-ui/react-id": "1.0.1", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-use-callback-ref": "1.0.1", - "@radix-ui/react-use-controllable-state": "1.0.1" + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.2.tgz", + "integrity": "sha512-rZJtWmorC7dFRi0owDmoijm6nSJH1tVw64QGiNIZ9PNLyBDtG+iAq+XGsya052At4BfarzY/Dhv9wrrUr6IMZA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.6.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz", + "integrity": "sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", + "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz", + "integrity": "sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-previous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", + "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-select/node_modules/react-remove-scroll": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz", + "integrity": "sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.6", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", + "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.1.tgz", + "integrity": "sha512-diPqDDoBcZPSicYoMWdWx+bCPuTRH4QSp9J+65IvtdS0Kuzt67bI6n32vCj8q6NZmYW/ah+2orOtMwcX5eQwIg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-previous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.3.tgz", + "integrity": "sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-collection": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz", + "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz", + "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", + "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.4.tgz", + "integrity": "sha512-Sch9idFJHJTMH9YNpxxESqABcAFweJG4tKv+0zo0m5XBvUSL8FM5xKcJLFLXononpePs8IclyX1KieL5SDUNgA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.3", + "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-collection": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz", + "integrity": "sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz", + "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-portal": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", + "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz", + "integrity": "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.9.tgz", + "integrity": "sha512-ZoFkBBz9zv9GWer7wIjvdRxmh2wyc2oKWw6C6CseWd6/yq1DK/l5lJ+wnsmFwJZbBYqr02mrf8A2q/CVCuM3ZA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.9.tgz", + "integrity": "sha512-HJ6gXdYVN38q/5KDdCcd+JTuXUyFZBMJbwXaU/82/Gi+V2ps6KpiZ2sQecAeZCV80POGRfkUBdUIj6hIdF6/MQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-roving-focus": "1.1.9", + "@radix-ui/react-toggle": "1.1.8", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -10324,18 +12932,336 @@ } } }, - "node_modules/@radix-ui/react-slot": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", - "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==", + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-collection": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.6.tgz", + "integrity": "sha512-PbhRFK4lIEw9ADonj48tiYWzkllz81TM7KVYyyMMw2cwHO7D5h4XKEblL8NlaRisTK3QTe6tBEhDccFUryxHBQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.1" + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-slot": "1.2.2" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-primitive": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.2.tgz", + "integrity": "sha512-uHa+l/lKfxuDD2zjN/0peM/RhhSmRjr5YWdk/37EnSv1nJ88uvG85DPexSm8HdFQROd2VdERJ6ynXbkCFi+APw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.9.tgz", + "integrity": "sha512-ZzrIFnMYHHCNqSNCsuN6l7wlewBEq0O0BCSBkabJMFXVO51LRUTq71gLP1UxFvmrXElqmPjA5VX7IqC9VpazAQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.6", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-slot": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.2.tgz", + "integrity": "sha512-y7TBO4xN4Y94FvcWIOIh18fM4R1A8S4q1jhoz4PNzOoHsFcN8pogcFmZrTYAm4F9VRUrWP/Mw7xSKybIeRI+CQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-toggle": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.8.tgz", + "integrity": "sha512-hrpa59m3zDnsa35LrTOH5s/a3iGv/VD+KKQjjiCTo/W4r0XwPpiWQvAv6Xl1nupSoaZeNNxW6sJH9ZydsjKdYQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -10415,6 +13341,39 @@ } } }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-escape-keydown": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz", @@ -11212,60 +14171,60 @@ } }, "node_modules/@shikijs/core": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.15.0.tgz", - "integrity": "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.21.0.tgz", + "integrity": "sha512-AXSQu/2n1UIQekY8euBJlvFYZIw0PHY63jUzGbrOma4wPxzznJXTXkri+QcHeBNaFxiiOljKxxJkVSoB3PjbyA==", "license": "MIT", "dependencies": { - "@shikijs/types": "3.15.0", + "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "node_modules/@shikijs/engine-javascript": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.15.0.tgz", - "integrity": "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.21.0.tgz", + "integrity": "sha512-ATwv86xlbmfD9n9gKRiwuPpWgPENAWCLwYCGz9ugTJlsO2kOzhOkvoyV/UD+tJ0uT7YRyD530x6ugNSffmvIiQ==", "license": "MIT", "dependencies": { - "@shikijs/types": "3.15.0", + "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2", - "oniguruma-to-es": "^4.3.3" + "oniguruma-to-es": "^4.3.4" } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.15.0.tgz", - "integrity": "sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.21.0.tgz", + "integrity": "sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==", "license": "MIT", "dependencies": { - "@shikijs/types": "3.15.0", + "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@shikijs/langs": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.15.0.tgz", - "integrity": "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.21.0.tgz", + "integrity": "sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==", "license": "MIT", "dependencies": { - "@shikijs/types": "3.15.0" + "@shikijs/types": "3.21.0" } }, "node_modules/@shikijs/themes": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.15.0.tgz", - "integrity": "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.21.0.tgz", + "integrity": "sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==", "license": "MIT", "dependencies": { - "@shikijs/types": "3.15.0" + "@shikijs/types": "3.21.0" } }, "node_modules/@shikijs/types": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.15.0.tgz", - "integrity": "sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.21.0.tgz", + "integrity": "sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==", "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", @@ -11932,10 +14891,157 @@ "react-native": "^0.0.0-0 || >=0.60 <1.0" } }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/assets-registry": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.83.1.tgz", + "integrity": "sha512-AT7/T6UwQqO39bt/4UL5EXvidmrddXrt0yJa7ENXndAv+8yBzMsZn6fyiax6+ERMt9GLzAECikv3lj22cn2wJA==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/codegen": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.83.1.tgz", + "integrity": "sha512-FpRxenonwH+c2a5X5DZMKUD7sCudHxB3eSQPgV9R+uxd28QWslyAWrpnJM/Az96AEksHnymDzEmzq2HLX5nb+g==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.25.3", + "glob": "^7.1.1", + "hermes-parser": "0.32.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "yargs": "^17.6.2" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/community-cli-plugin": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.83.1.tgz", + "integrity": "sha512-FqR1ftydr08PYlRbrDF06eRiiiGOK/hNmz5husv19sK6iN5nHj1SMaCIVjkH/a5vryxEddyFhU6PzO/uf4kOHg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@react-native/dev-middleware": "0.83.1", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.83.3", + "metro-config": "^0.83.3", + "metro-core": "^0.83.3", + "semver": "^7.1.3" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "*" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } + } + }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/debugger-frontend": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.83.1.tgz", + "integrity": "sha512-01Rn3goubFvPjHXONooLmsW0FLxJDKIUJNOlOS0cPtmmTIx9YIjxhe/DxwHXGk7OnULd7yl3aYy7WlBsEd5Xmg==", + "license": "BSD-3-Clause", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/debugger-shell": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.83.1.tgz", + "integrity": "sha512-d+0w446Hxth5OP/cBHSSxOEpbj13p2zToUy6e5e3tTERNJ8ueGlW7iGwGTrSymNDgXXFjErX+dY4P4/3WokPIQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "fb-dotslash": "0.5.8" + }, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/dev-middleware": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.83.1.tgz", + "integrity": "sha512-QJaSfNRzj3Lp7MmlCRgSBlt1XZ38xaBNXypXAp/3H3OdFifnTZOeYOpFmcpjcXYnDqkxetuwZg8VL65SQhB8dg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.83.1", + "@react-native/debugger-shell": "0.83.1", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.2.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^7.5.10" + }, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/gradle-plugin": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.83.1.tgz", + "integrity": "sha512-6ESDnwevp1CdvvxHNgXluil5OkqbjkJAkVy7SlpFsMGmVhrSxNAgD09SSRxMNdKsnLtzIvMsFCzyHLsU/S4PtQ==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/js-polyfills": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.83.1.tgz", + "integrity": "sha512-qgPpdWn/c5laA+3WoJ6Fak8uOm7CG50nBsLlPsF8kbT7rUHIVB9WaP6+GPsoKV/H15koW7jKuLRoNVT7c3Ht3w==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/normalize-colors": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.83.1.tgz", + "integrity": "sha512-84feABbmeWo1kg81726UOlMKAhcQyFXYz2SjRKYkS78QmfhVDhJ2o/ps1VjhFfBz0i/scDwT1XNv9GwmRIghkg==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/@react-native/virtualized-lists": { - "version": "0.82.1", - "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.82.1.tgz", - "integrity": "sha512-f5zpJg9gzh7JtCbsIwV+4kP3eI0QBuA93JGmwFRd4onQ3DnCjV2J5pYqdWtM95sjSKK1dyik59Gj01lLeKqs1Q==", + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.83.1.tgz", + "integrity": "sha512-MdmoAbQUTOdicCocm5XAFDJWsswxk7hxa6ALnm6Y88p01HFML0W593hAn6qOt9q6IM1KbAcebtH6oOd4gcQy8w==", "license": "MIT", "optional": true, "peer": true, @@ -11947,7 +15053,7 @@ "node": ">= 20.19.4" }, "peerDependencies": { - "@types/react": "^19.1.1", + "@types/react": "^19.2.0", "react": "*", "react-native": "*" }, @@ -12067,6 +15173,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/hermes-compiler": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-0.14.0.tgz", + "integrity": "sha512-clxa193o+GYYwykWVFfpHduCATz8fR5jvU7ngXpfKHj+E9hr9vjLNtdLSEe8MUbObvVexV3wcyxQ00xTPIrB1Q==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/istanbul-lib-instrument": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", @@ -12171,9 +15285,9 @@ } }, "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", "optional": true, "peer": true, @@ -12182,21 +15296,21 @@ } }, "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/react-native": { - "version": "0.82.1", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.82.1.tgz", - "integrity": "sha512-tFAqcU7Z4g49xf/KnyCEzI4nRTu1Opcx05Ov2helr8ZTg1z7AJR/3sr2rZ+AAVlAs2IXk+B0WOxXGmdD3+4czA==", + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.83.1.tgz", + "integrity": "sha512-mL1q5HPq5cWseVhWRLl+Fwvi5z1UO+3vGOpjr+sHFwcUletPRZ5Kv+d0tUfqHmvi73/53NjlQqX1Pyn4GguUfA==", "license": "MIT", "optional": true, "peer": true, "dependencies": { "@jest/create-cache-key-function": "^29.7.0", - "@react-native/assets-registry": "0.82.1", - "@react-native/codegen": "0.82.1", - "@react-native/community-cli-plugin": "0.82.1", - "@react-native/gradle-plugin": "0.82.1", - "@react-native/js-polyfills": "0.82.1", - "@react-native/normalize-colors": "0.82.1", - "@react-native/virtualized-lists": "0.82.1", + "@react-native/assets-registry": "0.83.1", + "@react-native/codegen": "0.83.1", + "@react-native/community-cli-plugin": "0.83.1", + "@react-native/gradle-plugin": "0.83.1", + "@react-native/js-polyfills": "0.83.1", + "@react-native/normalize-colors": "0.83.1", + "@react-native/virtualized-lists": "0.83.1", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", @@ -12206,23 +15320,23 @@ "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", - "hermes-compiler": "0.0.0", + "hermes-compiler": "0.14.0", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", - "metro-runtime": "^0.83.1", - "metro-source-map": "^0.83.1", + "metro-runtime": "^0.83.3", + "metro-source-map": "^0.83.3", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", - "scheduler": "0.26.0", + "scheduler": "0.27.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", - "ws": "^6.2.3", + "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { @@ -12233,7 +15347,7 @@ }, "peerDependencies": { "@types/react": "^19.1.1", - "react": "^19.1.1" + "react": "^19.2.0" }, "peerDependenciesMeta": { "@types/react": { @@ -12253,9 +15367,9 @@ } }, "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT", "optional": true, "peer": true @@ -12315,14 +15429,26 @@ } }, "node_modules/@solana-mobile/wallet-adapter-mobile/node_modules/ws": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", - "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "license": "MIT", "optional": true, "peer": true, - "dependencies": { - "async-limiter": "~1.0.0" + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/@solana-mobile/wallet-standard-mobile": { @@ -12885,9 +16011,9 @@ } }, "node_modules/@solana-program/compute-budget": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@solana-program/compute-budget/-/compute-budget-0.11.0.tgz", - "integrity": "sha512-7f1ePqB/eURkTwTOO9TNIdUXZcyrZoX3Uy2hNo7cXMfNhPFWp9AVgIyRNBc2jf15sdUa9gNpW+PfP2iV8AYAaw==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@solana-program/compute-budget/-/compute-budget-0.12.0.tgz", + "integrity": "sha512-ysHNVfctUyuY9+mHzJqt97en9ly2quR4n1pvJMQjYf4olwoCqB7+E9b+XZmlj91lFQuAs5z48aw5qDekg78DbQ==", "license": "Apache-2.0", "peerDependencies": { "@solana/kit": "^5.0" @@ -12912,9 +16038,9 @@ } }, "node_modules/@solana-program/token-2022": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@solana-program/token-2022/-/token-2022-0.6.1.tgz", - "integrity": "sha512-Ex02cruDMGfBMvZZCrggVR45vdQQSI/unHVpt/7HPt/IwFYB4eTlXtO8otYZyqV/ce5GqZ8S6uwyRf0zy6fdbA==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@solana-program/token-2022/-/token-2022-0.8.0.tgz", + "integrity": "sha512-2K/eJjGJQ1LPTCdbytfleTcwyZBjojPIzu/vsvTxixwRxCgsEMvu+gNjvfxo/mi2liRHp0xsm2MR4XQJTM2OVQ==", "license": "Apache-2.0", "peerDependencies": { "@solana/kit": "^5.0", @@ -12922,57 +16048,72 @@ } }, "node_modules/@solana/accounts": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-5.0.0.tgz", - "integrity": "sha512-0JzBdEobgp8NBdhhu+GgwNDh7e8KkHDsSTVZAnNQgvT3taOz0Mwv5E48MuEeDhW6DLFwWVAx/FO3pvibG/NGwA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-5.5.1.tgz", + "integrity": "sha512-TfOY9xixg5rizABuLVuZ9XI2x2tmWUC/OoN556xwfDlhBHBjKfszicYYOyD6nbFmwTGYarCmyGIdteXxTXIdhQ==", "license": "MIT", "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/codecs-core": "5.0.0", - "@solana/codecs-strings": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/rpc-spec": "5.0.0", - "@solana/rpc-types": "5.0.0" + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/rpc-spec": "5.5.1", + "@solana/rpc-types": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/addresses": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-5.0.0.tgz", - "integrity": "sha512-bVk+khc1ZZQHMri25csosM/ikuyPcB/CZidDM/ZMBX0CoJErpHJnmcID5mYOmv4/UHbqo2OANuEaGcFO0Q37sw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-5.5.1.tgz", + "integrity": "sha512-5xoah3Q9G30HQghu/9BiHLb5pzlPKRC3zydQDmE3O9H//WfayxTFppsUDCL6FjYUHqj/wzK6CWHySglc2RkpdA==", "license": "MIT", "dependencies": { - "@solana/assertions": "5.0.0", - "@solana/codecs-core": "5.0.0", - "@solana/codecs-strings": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/nominal-types": "5.0.0" + "@solana/assertions": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/nominal-types": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/assertions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-5.0.0.tgz", - "integrity": "sha512-2kIykk90kYciQW6bp+KaE6jRd1Y2CgHPeJxxlc5chQnjhoG6eiD8VXvocs6AvqPTht0p/SoEj9jH5tT4oG/bcg==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-5.5.1.tgz", + "integrity": "sha512-YTCSWAlGwSlVPnWtWLm3ukz81wH4j2YaCveK+TjpvUU88hTy6fmUqxi0+hvAMAe4zKXpJyj3Az7BrLJRxbIm4Q==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0" + "@solana/errors": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/buffer-layout": { @@ -12988,98 +16129,126 @@ } }, "node_modules/@solana/codecs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-5.0.0.tgz", - "integrity": "sha512-KOw0gFUSBxIMDWLJ3AkVFkEci91dw0Rpx3C6y83Our7fSW+SEP8vRZklCElieYR85LHVB1QIEhoeHR7rc+Ifkw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-5.5.1.tgz", + "integrity": "sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g==", "license": "MIT", "dependencies": { - "@solana/codecs-core": "5.0.0", - "@solana/codecs-data-structures": "5.0.0", - "@solana/codecs-numbers": "5.0.0", - "@solana/codecs-strings": "5.0.0", - "@solana/options": "5.0.0" + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/options": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/codecs-core": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-5.0.0.tgz", - "integrity": "sha512-rCG2d8OaamVF2/J//YyCgDqNJpUytVVltw9C8mJtEz5c6Se/LR6BFuG8g4xeJswq/ab4RFk5/HFdgbvNjKgQjA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-5.5.1.tgz", + "integrity": "sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0" + "@solana/errors": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/codecs-data-structures": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-5.0.0.tgz", - "integrity": "sha512-y503Pqmv0LHcfcf0vQJGaxDvydQJbyCo8nK3nxn56EhFj5lBQ1NWb3WvTd83epigwuZurW2MhJARrpikfhQglQ==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-5.5.1.tgz", + "integrity": "sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w==", "license": "MIT", "dependencies": { - "@solana/codecs-core": "5.0.0", - "@solana/codecs-numbers": "5.0.0", - "@solana/errors": "5.0.0" + "@solana/codecs-core": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/errors": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/codecs-numbers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-5.0.0.tgz", - "integrity": "sha512-a2+skRLuUK02f/XFe4L0e1+wHCyfK25PkyseFps1v1l4pvevukFwth/EhSyrs6w5CsTJRVoR7MuE3E00PM4egw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-5.5.1.tgz", + "integrity": "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw==", "license": "MIT", "dependencies": { - "@solana/codecs-core": "5.0.0", - "@solana/errors": "5.0.0" + "@solana/codecs-core": "5.5.1", + "@solana/errors": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/codecs-strings": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-5.0.0.tgz", - "integrity": "sha512-ALkRwpV8bGR6qjAYw0YXZwp2YI4wzvKOJGmx04Ut8gMdbaUx7qOcJkhEQKI6ZVC3lAWSIS1N1wGccUZDwvfKxw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-5.5.1.tgz", + "integrity": "sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A==", "license": "MIT", "dependencies": { - "@solana/codecs-core": "5.0.0", - "@solana/codecs-numbers": "5.0.0", - "@solana/errors": "5.0.0" + "@solana/codecs-core": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/errors": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { "fastestsmallesttextencoderdecoder": "^1.0.22", - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "fastestsmallesttextencoderdecoder": { + "optional": true + }, + "typescript": { + "optional": true + } } }, "node_modules/@solana/errors": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-5.0.0.tgz", - "integrity": "sha512-gTuhzO6E+ydfAAzqmqdPcvFyJwAzFKKIrqtnZPpgAuomcPYu+HSo0tuwSM/cTX0djmHt+GoOsf/julph+nvs2w==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-5.5.1.tgz", + "integrity": "sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg==", "license": "MIT", "dependencies": { "chalk": "5.6.2", - "commander": "14.0.1" + "commander": "14.0.2" }, "bin": { "errors": "bin/cli.mjs" @@ -13088,7 +16257,12 @@ "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/errors/node_modules/chalk": { @@ -13103,192 +16277,300 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@solana/errors/node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, "node_modules/@solana/fast-stable-stringify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-5.0.0.tgz", - "integrity": "sha512-sGTbu7a4/olL+8EIOOJ7IZjzqOOpCJcK1UaVJ6015sRgo9vwGf4jg9KtXEYv5LVhLCTYmAb50L4BaIUcBph/Ig==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-5.5.1.tgz", + "integrity": "sha512-Ni7s2FN33zTzhTFgRjEbOVFO+UAmK8qi3Iu0/GRFYK4jN696OjKHnboSQH/EacQ+yGqS54bfxf409wU5dsLLCw==", "license": "MIT", "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/functional": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-5.0.0.tgz", - "integrity": "sha512-UNBrpfzBL4dKD2iucjNnrkFbnjz5ZYDu2OvrIBAcCSQsxxgHMamUj1n3EDe6kl1us49YG1r05Ho8QLqNrbkVbw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-5.5.1.tgz", + "integrity": "sha512-tTHoJcEQq3gQx5qsdsDJ0LEJeFzwNpXD80xApW9o/PPoCNimI3SALkZl+zNW8VnxRrV3l3yYvfHWBKe/X3WG3w==", "license": "MIT", "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/instruction-plans": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/instruction-plans/-/instruction-plans-5.0.0.tgz", - "integrity": "sha512-n9oFOMFUPYKEhsXzrXT97QBQ2WvOTar+5SFEj/IOtRuCn4gl2kh0369cjXZpFwUdE3tmKr1zfYFNwbtiNx5pvg==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/instruction-plans/-/instruction-plans-5.5.1.tgz", + "integrity": "sha512-7z3CB7YMcFKuVvgcnNY8bY6IsZ8LG61Iytbz7HpNVGX2u1RthOs1tRW8luTzSG1MPL0Ox7afyAVMYeFqSPHnaQ==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0", - "@solana/instructions": "5.0.0", - "@solana/promises": "5.0.0", - "@solana/transaction-messages": "5.0.0", - "@solana/transactions": "5.0.0" + "@solana/errors": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/promises": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/instructions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-5.0.0.tgz", - "integrity": "sha512-12dbrmwERT1o6NTr/Uvrjj/ZsiteSXoT5Gi+dnjIeRNHWg9H+gEFuFzJvTDVKlNg34CZ71xdvbVdbV0V8gKGvg==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-5.5.1.tgz", + "integrity": "sha512-h0G1CG6S+gUUSt0eo6rOtsaXRBwCq1+Js2a+Ps9Bzk9q7YHNFA75/X0NWugWLgC92waRp66hrjMTiYYnLBoWOQ==", "license": "MIT", "dependencies": { - "@solana/codecs-core": "5.0.0", - "@solana/errors": "5.0.0" + "@solana/codecs-core": "5.5.1", + "@solana/errors": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-5.0.0.tgz", - "integrity": "sha512-kWkR7NslpTttk5i1BhBNCDtVQDkEtgkdsM3Jp9TGPk0GFjBjBwrQStw3vvwLe8itEIvRFGFZU6JHEk8HLS0WLQ==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-5.5.1.tgz", + "integrity": "sha512-KRD61cL7CRL+b4r/eB9dEoVxIf/2EJ1Pm1DmRYhtSUAJD2dJ5Xw8QFuehobOGm9URqQ7gaQl+Fkc1qvDlsWqKg==", "license": "MIT", "dependencies": { - "@solana/assertions": "5.0.0", - "@solana/codecs-core": "5.0.0", - "@solana/codecs-strings": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/nominal-types": "5.0.0" + "@solana/assertions": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/nominal-types": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/kit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-5.0.0.tgz", - "integrity": "sha512-3ahtzmmMgU+1l2YMhQJSKKm14IdvCycOE/m4XNMu/4icBIptmBgZxrmgRpPHqBilBa+Krp/hBuTg4HWl9IAgWw==", - "license": "MIT", - "dependencies": { - "@solana/accounts": "5.0.0", - "@solana/addresses": "5.0.0", - "@solana/codecs": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/functional": "5.0.0", - "@solana/instruction-plans": "5.0.0", - "@solana/instructions": "5.0.0", - "@solana/keys": "5.0.0", - "@solana/programs": "5.0.0", - "@solana/rpc": "5.0.0", - "@solana/rpc-parsed-types": "5.0.0", - "@solana/rpc-spec-types": "5.0.0", - "@solana/rpc-subscriptions": "5.0.0", - "@solana/rpc-types": "5.0.0", - "@solana/signers": "5.0.0", - "@solana/sysvars": "5.0.0", - "@solana/transaction-confirmation": "5.0.0", - "@solana/transaction-messages": "5.0.0", - "@solana/transactions": "5.0.0" + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-5.5.1.tgz", + "integrity": "sha512-irKUGiV2yRoyf+4eGQ/ZeCRxa43yjFEL1DUI5B0DkcfZw3cr0VJtVJnrG8OtVF01vT0OUfYOcUn6zJW5TROHvQ==", + "license": "MIT", + "dependencies": { + "@solana/accounts": "5.5.1", + "@solana/addresses": "5.5.1", + "@solana/codecs": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/instruction-plans": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/offchain-messages": "5.5.1", + "@solana/plugin-core": "5.5.1", + "@solana/programs": "5.5.1", + "@solana/rpc": "5.5.1", + "@solana/rpc-api": "5.5.1", + "@solana/rpc-parsed-types": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/rpc-subscriptions": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/signers": "5.5.1", + "@solana/sysvars": "5.5.1", + "@solana/transaction-confirmation": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/nominal-types": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-5.0.0.tgz", - "integrity": "sha512-Qn7xH4UG2rDAv+wAyheP4jWvX3oQmbZ/woxFZwug7PaRLvyjUswGr38Hil+SjiQyFDo+un1UqWM9N9yusUeeZQ==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-5.5.1.tgz", + "integrity": "sha512-I1ImR+kfrLFxN5z22UDiTWLdRZeKtU0J/pkWkO8qm/8WxveiwdIv4hooi8pb6JnlR4mSrWhq0pCIOxDYrL9GIQ==", "license": "MIT", "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/offchain-messages": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/offchain-messages/-/offchain-messages-5.5.1.tgz", + "integrity": "sha512-g+xHH95prTU+KujtbOzj8wn+C7ZNoiLhf3hj6nYq3MTyxOXtBEysguc97jJveUZG0K97aIKG6xVUlMutg5yxhw==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/nominal-types": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/options": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/options/-/options-5.0.0.tgz", - "integrity": "sha512-ezHVBFb9FXVSn8LUVRD2tLb6fejU0x8KtGEYyCYh0J0pQuXSITV0IQCjcEopvu/ZxWdXOJyzjvmymnhz90on5A==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-5.5.1.tgz", + "integrity": "sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A==", "license": "MIT", "dependencies": { - "@solana/codecs-core": "5.0.0", - "@solana/codecs-data-structures": "5.0.0", - "@solana/codecs-numbers": "5.0.0", - "@solana/codecs-strings": "5.0.0", - "@solana/errors": "5.0.0" + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/plugin-core": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/plugin-core/-/plugin-core-5.5.1.tgz", + "integrity": "sha512-VUZl30lDQFJeiSyNfzU1EjYt2QZvoBFKEwjn1lilUJw7KgqD5z7mbV7diJhT+dLFs36i0OsjXvq5kSygn8YJ3A==", + "license": "MIT", + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/programs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-5.0.0.tgz", - "integrity": "sha512-BKOfBDrSUCJGZ+qKk2aFLu0nU9/84o6z/VDCJkLjaNNuTv8nOlSYq5flNzo1eyJmnpyW372qNvqqRN3AS23+FQ==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-5.5.1.tgz", + "integrity": "sha512-7U9kn0Jsx1NuBLn5HRTFYh78MV4XN145Yc3WP/q5BlqAVNlMoU9coG5IUTJIG847TUqC1lRto3Dnpwm6T4YRpA==", "license": "MIT", "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/errors": "5.0.0" + "@solana/addresses": "5.5.1", + "@solana/errors": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/promises": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-5.0.0.tgz", - "integrity": "sha512-Qmg3UfYfWINEUvBQL3DkPOq34tTg5cfrkPlDtJmi8RVifsPqb6hksbKZGu7ASLZohxIDGmnYQY6oELI7Me+5yw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-5.5.1.tgz", + "integrity": "sha512-T9lfuUYkGykJmppEcssNiCf6yiYQxJkhiLPP+pyAc2z84/7r3UVIb2tNJk4A9sucS66pzJnVHZKcZVGUUp6wzA==", "license": "MIT", "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/react": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/react/-/react-5.0.0.tgz", - "integrity": "sha512-OY5WsmFGxRCXuysG1uy9WmL3DlYOKwjvwynstXWbi+aks804BidBaTcyM9oxSvsbH3rHzCK/MtHH/ux0AGQ5Qg==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/keys": "5.0.0", - "@solana/promises": "5.0.0", - "@solana/signers": "5.0.0", - "@solana/transaction-messages": "5.0.0", - "@solana/transactions": "5.0.0", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/react/-/react-5.5.1.tgz", + "integrity": "sha512-kJE6XWWXnf74wTXrfWDRchfZ9WgI1ii1WsIftUd44rN1UP/C4sqrf9ltbr/u3j8OrErI3MEt3coyphq3gPicVg==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/promises": "5.5.1", + "@solana/signers": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1", "@solana/wallet-standard-features": "^1.3.0", "@wallet-standard/base": "^1.1.0", "@wallet-standard/errors": "^0.1.1", + "@wallet-standard/react": "^1.0.1", "@wallet-standard/ui": "^1.0.1", "@wallet-standard/ui-registry": "^1.0.1" }, @@ -13297,362 +16579,458 @@ }, "peerDependencies": { "react": ">=18" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } } }, "node_modules/@solana/rpc": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-5.0.0.tgz", - "integrity": "sha512-Myx/ZBmMHkgh9Di3tLzc+vd30f+6YC1JXr9+YmIHKEeqN/+iTHkDJU2E/hGRLy8vTOBOU7+2466A+dLnSVuGkg==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-5.5.1.tgz", + "integrity": "sha512-ku8zTUMrkCWci66PRIBC+1mXepEnZH/q1f3ck0kJZ95a06bOTl5KU7HeXWtskkyefzARJ5zvCs54AD5nxjQJ+A==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0", - "@solana/fast-stable-stringify": "5.0.0", - "@solana/functional": "5.0.0", - "@solana/rpc-api": "5.0.0", - "@solana/rpc-spec": "5.0.0", - "@solana/rpc-spec-types": "5.0.0", - "@solana/rpc-transformers": "5.0.0", - "@solana/rpc-transport-http": "5.0.0", - "@solana/rpc-types": "5.0.0" + "@solana/errors": "5.5.1", + "@solana/fast-stable-stringify": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/rpc-api": "5.5.1", + "@solana/rpc-spec": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/rpc-transformers": "5.5.1", + "@solana/rpc-transport-http": "5.5.1", + "@solana/rpc-types": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-api": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-5.0.0.tgz", - "integrity": "sha512-IJbZZnX2B1ldXPok1NhneXTYq9ZvdJbE5Pryr03pZTlPJaWGqDcZuQ14nwR4s6PoUUgdT+p87QlLZqLb8MusoQ==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-5.5.1.tgz", + "integrity": "sha512-XWOQQPhKl06Vj0xi3RYHAc6oEQd8B82okYJ04K7N0Vvy3J4PN2cxeK7klwkjgavdcN9EVkYCChm2ADAtnztKnA==", "license": "MIT", "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/codecs-core": "5.0.0", - "@solana/codecs-strings": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/keys": "5.0.0", - "@solana/rpc-parsed-types": "5.0.0", - "@solana/rpc-spec": "5.0.0", - "@solana/rpc-transformers": "5.0.0", - "@solana/rpc-types": "5.0.0", - "@solana/transaction-messages": "5.0.0", - "@solana/transactions": "5.0.0" + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/rpc-parsed-types": "5.5.1", + "@solana/rpc-spec": "5.5.1", + "@solana/rpc-transformers": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-parsed-types": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-5.0.0.tgz", - "integrity": "sha512-fU9uqlOYAaBqgk2qCl+ntenBm7wuSFBRbIO/rVjeBPd/qPCvNZU+qFET+ERLK6wbCTSz0MmdHqPn1V8KCMOvZQ==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-5.5.1.tgz", + "integrity": "sha512-HEi3G2nZqGEsa3vX6U0FrXLaqnUCg4SKIUrOe8CezD+cSFbRTOn3rCLrUmJrhVyXlHoQVaRO9mmeovk31jWxJg==", "license": "MIT", "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-spec": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-5.0.0.tgz", - "integrity": "sha512-1LD2SYEQ5bYhiBumznAPzymtxSX4nYLZd6u+FA0bAxNBVzHDvUUQzVSXHAoWROhlGrCyvtALTs9u0DIDlgZHCA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-5.5.1.tgz", + "integrity": "sha512-m3LX2bChm3E3by4mQrH4YwCAFY57QBzuUSWqlUw7ChuZ+oLLOq7b2czi4i6L4Vna67j3eCmB3e+4tqy1j5wy7Q==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0", - "@solana/rpc-spec-types": "5.0.0" + "@solana/errors": "5.5.1", + "@solana/rpc-spec-types": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-spec-types": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-5.0.0.tgz", - "integrity": "sha512-B0P/ylXVaCG5oSIV+kB88s2qoW996D8iKhc7RyF0C/AyYvklF6kCwv0N9ZVrWp0ibjlQ8St290WbBHJyo7QZkA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-5.5.1.tgz", + "integrity": "sha512-6OFKtRpIEJQs8Jb2C4OO8KyP2h2Hy1MFhatMAoXA+0Ik8S3H+CicIuMZvGZ91mIu/tXicuOOsNNLu3HAkrakrw==", "license": "MIT", "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-subscriptions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-5.0.0.tgz", - "integrity": "sha512-cziOSzom/bwFZXViR9J+MxDsdLMcfvrXGw5Icng7dYODFKuVqfsDrQoG8uekJc4fREnbPEM2U+u9YnYSYbFbww==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-5.5.1.tgz", + "integrity": "sha512-CTMy5bt/6mDh4tc6vUJms9EcuZj3xvK0/xq8IQ90rhkpYvate91RjBP+egvjgSayUg9yucU9vNuUpEjz4spM7w==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0", - "@solana/fast-stable-stringify": "5.0.0", - "@solana/functional": "5.0.0", - "@solana/promises": "5.0.0", - "@solana/rpc-spec-types": "5.0.0", - "@solana/rpc-subscriptions-api": "5.0.0", - "@solana/rpc-subscriptions-channel-websocket": "5.0.0", - "@solana/rpc-subscriptions-spec": "5.0.0", - "@solana/rpc-transformers": "5.0.0", - "@solana/rpc-types": "5.0.0", - "@solana/subscribable": "5.0.0" + "@solana/errors": "5.5.1", + "@solana/fast-stable-stringify": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/promises": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/rpc-subscriptions-api": "5.5.1", + "@solana/rpc-subscriptions-channel-websocket": "5.5.1", + "@solana/rpc-subscriptions-spec": "5.5.1", + "@solana/rpc-transformers": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/subscribable": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-subscriptions-api": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-5.0.0.tgz", - "integrity": "sha512-DGUn3C12swV2FConOlLFN14npIrCtnxehtMLjszMC7g6p/P6WNIz5uAgF7YcIkLBDV8uTeWhM0azmK+V8Qqhvg==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-5.5.1.tgz", + "integrity": "sha512-5Oi7k+GdeS8xR2ly1iuSFkAv6CZqwG0Z6b1QZKbEgxadE1XGSDrhM2cn59l+bqCozUWCqh4c/A2znU/qQjROlw==", "license": "MIT", "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/keys": "5.0.0", - "@solana/rpc-subscriptions-spec": "5.0.0", - "@solana/rpc-transformers": "5.0.0", - "@solana/rpc-types": "5.0.0", - "@solana/transaction-messages": "5.0.0", - "@solana/transactions": "5.0.0" + "@solana/addresses": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/rpc-subscriptions-spec": "5.5.1", + "@solana/rpc-transformers": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-subscriptions-channel-websocket": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-5.0.0.tgz", - "integrity": "sha512-vsYXyjVX/kExfpr91zfMKTmWKKFCM+dkhXQDAz5aEE7kAF3KSZDiOGeYvN8Rc85lbIt9QK6BLAT+NBMv4/N9Qg==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-5.5.1.tgz", + "integrity": "sha512-7tGfBBrYY8TrngOyxSHoCU5shy86iA9SRMRrPSyBhEaZRAk6dnbdpmUTez7gtdVo0BCvh9nzQtUycKWSS7PnFQ==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0", - "@solana/functional": "5.0.0", - "@solana/rpc-subscriptions-spec": "5.0.0", - "@solana/subscribable": "5.0.0" + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/rpc-subscriptions-spec": "5.5.1", + "@solana/subscribable": "5.5.1", + "ws": "^8.19.0" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3", - "ws": "^8.18.0" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-subscriptions-spec": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-5.0.0.tgz", - "integrity": "sha512-erRLvZMncwnciJP6I1SlAk0CyRGIgt83PyHWOVCRXENP9Q5dZbZ9pm4lar2yIp8EjIMnodGHsQWIlKc1hlCQlQ==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-5.5.1.tgz", + "integrity": "sha512-iq+rGq5fMKP3/mKHPNB6MC8IbVW41KGZg83Us/+LE3AWOTWV1WT20KT2iH1F1ik9roi42COv/TpoZZvhKj45XQ==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0", - "@solana/promises": "5.0.0", - "@solana/rpc-spec-types": "5.0.0", - "@solana/subscribable": "5.0.0" + "@solana/errors": "5.5.1", + "@solana/promises": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/subscribable": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-transformers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-5.0.0.tgz", - "integrity": "sha512-EMHhSgfF6/T4FfHbLaBP08SIj1ZAjxJr6WPNZMHLV7Cup8UfiB9TNV+bPQkum7JbVQNhUKzkKEEmyYqPfQoV9w==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-5.5.1.tgz", + "integrity": "sha512-OsWqLCQdcrRJKvHiMmwFhp9noNZ4FARuMkHT5us3ustDLXaxOjF0gfqZLnMkulSLcKt7TGXqMhBV+HCo7z5M8Q==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0", - "@solana/functional": "5.0.0", - "@solana/nominal-types": "5.0.0", - "@solana/rpc-spec-types": "5.0.0", - "@solana/rpc-types": "5.0.0" + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/nominal-types": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/rpc-types": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-transport-http": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-5.0.0.tgz", - "integrity": "sha512-RoIEvWp7yc7rIRzNkOyjLs2UQF0odIEMWj87dbD4Ir4hwTCGo/TSTfQF/8KDV2etdke3Fa1K+W1NkpG2POqWFg==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-5.5.1.tgz", + "integrity": "sha512-yv8GoVSHqEV0kUJEIhkdOVkR2SvJ6yoWC51cJn2rSV7plr6huLGe0JgujCmB7uZhhaLbcbP3zxXxu9sOjsi7Fg==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0", - "@solana/rpc-spec": "5.0.0", - "@solana/rpc-spec-types": "5.0.0", - "undici-types": "^7.16.0" + "@solana/errors": "5.5.1", + "@solana/rpc-spec": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "undici-types": "^7.19.2" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/rpc-types": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-5.0.0.tgz", - "integrity": "sha512-JMbhwnV6nX4ezJv/KmaElOR0r/MZTKzKpaz6cv7FopLNuPrYCBrRCZKuM2XQh6gUbt9Mey08/KBOmOGmzTbL/g==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-5.5.1.tgz", + "integrity": "sha512-bibTFQ7PbHJJjGJPmfYC2I+/5CRFS4O2p9WwbFraX1Keeel+nRrt/NBXIy8veP5AEn2sVJIyJPpWBRpCx1oATA==", "license": "MIT", "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/codecs-core": "5.0.0", - "@solana/codecs-numbers": "5.0.0", - "@solana/codecs-strings": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/nominal-types": "5.0.0" + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/nominal-types": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/signers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-5.0.0.tgz", - "integrity": "sha512-9Hw6HekSEzj5O7UBBFPrxk96W5e8tMI3n7KbW7/QiKBDpuvYw9WtnjOsWUE7LqQoc1P0JjGEsrmxE9raQBLvuQ==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-5.5.1.tgz", + "integrity": "sha512-FY0IVaBT2kCAze55vEieR6hag4coqcuJ31Aw3hqRH7mv6sV8oqwuJmUrx+uFwOp1gwd5OEAzlv6N4hOOple4sQ==", "license": "MIT", "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/codecs-core": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/instructions": "5.0.0", - "@solana/keys": "5.0.0", - "@solana/nominal-types": "5.0.0", - "@solana/transaction-messages": "5.0.0", - "@solana/transactions": "5.0.0" + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/nominal-types": "5.5.1", + "@solana/offchain-messages": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/subscribable": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-5.0.0.tgz", - "integrity": "sha512-C2TydIRRd5XUJ8asbARi67Sj/3DRLubWalnNoafBhDsrb88jsRVylntvwXgBw/+lwJdEPEsUnxvcdgdm+3lFlw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-5.5.1.tgz", + "integrity": "sha512-9K0PsynFq0CsmK1CDi5Y2vUIJpCqkgSS5yfDN0eKPgHqEptLEaia09Kaxc90cSZDZU5mKY/zv1NBmB6Aro9zQQ==", "license": "MIT", "dependencies": { - "@solana/errors": "5.0.0" + "@solana/errors": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/sysvars": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-5.0.0.tgz", - "integrity": "sha512-F/GEb2rS8mrgDd79lDPyu8za9jGE6cRlS4jHNeKCkvOCJxdKQbX34JIzx4kwzjtvk7O8/yrDHfGdpA8nBg/l4w==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-5.5.1.tgz", + "integrity": "sha512-k3Quq87Mm+geGUu1GWv6knPk0ALsfY6EKSJGw9xUJDHzY/RkYSBnh0RiOrUhtFm2TDNjOailg8/m0VHmi3reFA==", "license": "MIT", "dependencies": { - "@solana/accounts": "5.0.0", - "@solana/codecs": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/rpc-types": "5.0.0" + "@solana/accounts": "5.5.1", + "@solana/codecs": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/rpc-types": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/transaction-confirmation": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-5.0.0.tgz", - "integrity": "sha512-LpusTopYIuQC8hBCloExkTr4Z5/zdp5f4IIbzD5XFeW3xXPZytS3H1IDMGk4bmLdZi9zQNA4lnNHKra5IncRbw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-5.5.1.tgz", + "integrity": "sha512-j4mKlYPHEyu+OD7MBt3jRoX4ScFgkhZC6H65on4Fux6LMScgivPJlwnKoZMnsgxFgWds0pl+BYzSiALDsXlYtw==", "license": "MIT", "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/codecs-strings": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/keys": "5.0.0", - "@solana/promises": "5.0.0", - "@solana/rpc": "5.0.0", - "@solana/rpc-subscriptions": "5.0.0", - "@solana/rpc-types": "5.0.0", - "@solana/transaction-messages": "5.0.0", - "@solana/transactions": "5.0.0" + "@solana/addresses": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/promises": "5.5.1", + "@solana/rpc": "5.5.1", + "@solana/rpc-subscriptions": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/transaction-messages": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-5.0.0.tgz", - "integrity": "sha512-rJLe1wUGW5DovQFV0gjXHXnriPxTBgZ3TvGWnjCu2OIBU8mcQkQVJ7zzVZY2IAYlmJ6OSF9nvzhSt/ncPbkJPg==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-5.5.1.tgz", + "integrity": "sha512-aXyhMCEaAp3M/4fP0akwBBQkFPr4pfwoC5CLDq999r/FUwDax2RE/h4Ic7h2Xk+JdcUwsb+rLq85Y52hq84XvQ==", "license": "MIT", "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/codecs-core": "5.0.0", - "@solana/codecs-data-structures": "5.0.0", - "@solana/codecs-numbers": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/functional": "5.0.0", - "@solana/instructions": "5.0.0", - "@solana/nominal-types": "5.0.0", - "@solana/rpc-types": "5.0.0" + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/nominal-types": "5.5.1", + "@solana/rpc-types": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/transactions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-5.0.0.tgz", - "integrity": "sha512-4TcsqH7JtgRKGGBIRRGz0n+tXu4h5TPPC49kkV0ygIndQaHW7FOZUYTwQ0epq0A5h9KYi+ClNbzF9xiuDbAD5Q==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-5.5.1.tgz", + "integrity": "sha512-8hHtDxtqalZ157pnx6p8k10D7J/KY/biLzfgh9R09VNLLY3Fqi7kJvJCr7M2ik3oRll56pxhraAGCC9yIT6eOA==", "license": "MIT", "dependencies": { - "@solana/addresses": "5.0.0", - "@solana/codecs-core": "5.0.0", - "@solana/codecs-data-structures": "5.0.0", - "@solana/codecs-numbers": "5.0.0", - "@solana/codecs-strings": "5.0.0", - "@solana/errors": "5.0.0", - "@solana/functional": "5.0.0", - "@solana/instructions": "5.0.0", - "@solana/keys": "5.0.0", - "@solana/nominal-types": "5.0.0", - "@solana/rpc-types": "5.0.0", - "@solana/transaction-messages": "5.0.0" + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/nominal-types": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/transaction-messages": "5.5.1" }, "engines": { "node": ">=20.18.0" }, "peerDependencies": { - "typescript": ">=5.3.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@solana/wallet-adapter-base": { @@ -14118,16 +17496,10 @@ "dev": true, "license": "MIT" }, - "node_modules/@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", - "license": "MIT" - }, "node_modules/@supabase/auth-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.84.0.tgz", - "integrity": "sha512-J6XKbqqg1HQPMfYkAT9BrC8anPpAiifl7qoVLsYhQq5B/dnu/lxab1pabnxtJEsvYG5rwI5HEVEGXMjoQ6Wz2Q==", + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.95.3.tgz", + "integrity": "sha512-vD2YoS8E2iKIX0F7EwXTmqhUpaNsmbU6X2R0/NdFcs02oEfnHyNP/3M716f3wVJ2E5XHGiTFXki6lRckhJ0Thg==", "license": "MIT", "dependencies": { "tslib": "2.8.1" @@ -14137,9 +17509,9 @@ } }, "node_modules/@supabase/functions-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.84.0.tgz", - "integrity": "sha512-2oY5QBV4py/s64zMlhPEz+4RTdlwxzmfhM1k2xftD2v1DruRZKfoe7Yn9DCz1VondxX8evcvpc2udEIGzHI+VA==", + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.95.3.tgz", + "integrity": "sha512-uTuOAKzs9R/IovW1krO0ZbUHSJnsnyJElTXIRhjJTqymIVGcHzkAYnBCJqd7468Fs/Foz1BQ7Dv6DCl05lr7ig==", "license": "MIT", "dependencies": { "tslib": "2.8.1" @@ -14149,9 +17521,9 @@ } }, "node_modules/@supabase/postgrest-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.84.0.tgz", - "integrity": "sha512-oplc/3jfJeVW4F0J8wqywHkjIZvOVHtqzF0RESijepDAv5Dn/LThlGW1ftysoP4+PXVIrnghAbzPHo88fNomPQ==", + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.95.3.tgz", + "integrity": "sha512-LTrRBqU1gOovxRm1vRXPItSMPBmEFqrfTqdPTRtzOILV4jPSueFz6pES5hpb4LRlkFwCPRmv3nQJ5N625V2Xrg==", "license": "MIT", "dependencies": { "tslib": "2.8.1" @@ -14161,9 +17533,9 @@ } }, "node_modules/@supabase/realtime-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.84.0.tgz", - "integrity": "sha512-ThqjxiCwWiZAroHnYPmnNl6tZk6jxGcG2a7Hp/3kcolPcMj89kWjUTA3cHmhdIWYsP84fHp8MAQjYWMLf7HEUg==", + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.95.3.tgz", + "integrity": "sha512-D7EAtfU3w6BEUxDACjowWNJo/ZRo7sDIuhuOGKHIm9FHieGeoJV5R6GKTLtga/5l/6fDr2u+WcW/m8I9SYmaIw==", "license": "MIT", "dependencies": { "@types/phoenix": "^1.6.6", @@ -14176,11 +17548,12 @@ } }, "node_modules/@supabase/storage-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.84.0.tgz", - "integrity": "sha512-vXvAJ1euCuhryOhC6j60dG8ky+lk0V06ubNo+CbhuoUv+sl39PyY0lc+k+qpQhTk/VcI6SiM0OECLN83+nyJ5A==", + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.95.3.tgz", + "integrity": "sha512-4GxkJiXI3HHWjxpC3sDx1BVrV87O0hfX+wvJdqGv67KeCu+g44SPnII8y0LL/Wr677jB7tpjAxKdtVWf+xhc9A==", "license": "MIT", "dependencies": { + "iceberg-js": "^0.8.1", "tslib": "2.8.1" }, "engines": { @@ -14188,21 +17561,77 @@ } }, "node_modules/@supabase/supabase-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.84.0.tgz", - "integrity": "sha512-byMqYBvb91sx2jcZsdp0qLpmd4Dioe80e4OU/UexXftCkpTcgrkoENXHf5dO8FCSai8SgNeq16BKg10QiDI6xg==", + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.95.3.tgz", + "integrity": "sha512-Fukw1cUTQ6xdLiHDJhKKPu6svEPaCEDvThqCne3OaQyZvuq2qjhJAd91kJu3PXLG18aooCgYBaB6qQz35hhABg==", "license": "MIT", "dependencies": { - "@supabase/auth-js": "2.84.0", - "@supabase/functions-js": "2.84.0", - "@supabase/postgrest-js": "2.84.0", - "@supabase/realtime-js": "2.84.0", - "@supabase/storage-js": "2.84.0" + "@supabase/auth-js": "2.95.3", + "@supabase/functions-js": "2.95.3", + "@supabase/postgrest-js": "2.95.3", + "@supabase/realtime-js": "2.95.3", + "@supabase/storage-js": "2.95.3" }, "engines": { "node": ">=20.0.0" } }, + "node_modules/@svgdotjs/svg.draggable.js": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.draggable.js/-/svg.draggable.js-3.0.6.tgz", + "integrity": "sha512-7iJFm9lL3C40HQcqzEfezK2l+dW2CpoVY3b77KQGqc8GXWa6LhhmX5Ckv7alQfUXBuZbjpICZ+Dvq1czlGx7gA==", + "license": "MIT", + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4" + } + }, + "node_modules/@svgdotjs/svg.filter.js": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.filter.js/-/svg.filter.js-3.0.9.tgz", + "integrity": "sha512-/69XMRCDoam2HgC4ldHIaDgeQf1ViHIsa0Ld4uWgiXtZ+E24DWHe/9Ib6kbNiZ7WRIdlVokUDR1Fg0kjIpkfbw==", + "license": "MIT", + "dependencies": { + "@svgdotjs/svg.js": "^3.2.4" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@svgdotjs/svg.js": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.js/-/svg.js-3.2.5.tgz", + "integrity": "sha512-/VNHWYhNu+BS7ktbYoVGrCmsXDh+chFMaONMwGNdIBcFHrWqk2jY8fNyr3DLdtQUIalvkPfM554ZSFa3dm3nxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Fuzzyma" + } + }, + "node_modules/@svgdotjs/svg.resize.js": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.resize.js/-/svg.resize.js-2.0.5.tgz", + "integrity": "sha512-4heRW4B1QrJeENfi7326lUPYBCevj78FJs8kfeDxn5st0IYPIRXoTtOSYvTzFWgaWWXd3YCDE6ao4fmv91RthA==", + "license": "MIT", + "engines": { + "node": ">= 14.18" + }, + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4", + "@svgdotjs/svg.select.js": "^4.0.1" + } + }, + "node_modules/@svgdotjs/svg.select.js": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.select.js/-/svg.select.js-4.0.3.tgz", + "integrity": "sha512-qkMgso1sd2hXKd1FZ1weO7ANq12sNmQJeGDjs46QwDVsxSRcHmvWKL2NDF7Yimpwf3sl5esOLkPqtV2bQ3v/Jg==", + "license": "MIT", + "engines": { + "node": ">= 14.18" + }, + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4" + } + }, "node_modules/@swagger-api/apidom-ast": { "version": "1.0.0-rc.3", "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ast/-/apidom-ast-1.0.0-rc.3.tgz", @@ -14787,8 +18216,7 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/@swc/helpers": { "version": "0.5.17", @@ -14821,6 +18249,65 @@ "tailwindcss": ">=3.2.0" } }, + "node_modules/@tanstack/query-core": { + "version": "5.69.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.69.0.tgz", + "integrity": "sha512-Kn410jq6vs1P8Nm+ZsRj9H+U3C0kjuEkYLxbiCyn3MDEiYor1j2DGVULqAz62SLZtUZ/e9Xt6xMXiJ3NJ65WyQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.69.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.69.0.tgz", + "integrity": "sha512-Ift3IUNQqTcaFa1AiIQ7WCb/PPy8aexZdq9pZWLXhfLcLxH0+PZqJ2xFImxCpdDZrFRZhLJrh76geevS5xjRhA==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.69.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-table": { + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.5.tgz", + "integrity": "sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.20.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.5.tgz", + "integrity": "sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -14927,15 +18414,6 @@ "@types/estree": "*" } }, - "node_modules/@types/fontkit": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@types/fontkit/-/fontkit-2.0.8.tgz", - "integrity": "sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/google.maps": { "version": "3.58.1", "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz", @@ -15023,9 +18501,9 @@ "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", "license": "MIT" }, "node_modules/@types/mdast": { @@ -15059,9 +18537,9 @@ } }, "node_modules/@types/node": { - "version": "20.19.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz", - "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==", + "version": "20.19.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", + "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -15085,9 +18563,9 @@ "license": "MIT" }, "node_modules/@types/phoenix": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz", - "integrity": "sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", + "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==", "license": "MIT" }, "node_modules/@types/prismjs": { @@ -15112,9 +18590,9 @@ } }, "node_modules/@types/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", - "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "version": "19.2.13", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.13.tgz", + "integrity": "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==", "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -16028,6 +19506,18 @@ "node": ">=18" } }, + "node_modules/@wallet-standard/experimental-features": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@wallet-standard/experimental-features/-/experimental-features-0.2.0.tgz", + "integrity": "sha512-B6fBLgouurN3IAoqhh8/1Mm33IAWIErQXVyvMcyBJM+elOD6zkNDUjew5QMG19qCbJ+ZiZUZmdOUC5PxxWw69w==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/base": "^1.1.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@wallet-standard/features": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@wallet-standard/features/-/features-1.1.0.tgz", @@ -16040,6 +19530,40 @@ "node": ">=16" } }, + "node_modules/@wallet-standard/react": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@wallet-standard/react/-/react-1.0.1.tgz", + "integrity": "sha512-StpPv234R94MmJCCUZurQvQSsX6Xe1eOd2lNgwVonvSVdPqCNVS/haVpdrBMx0wX1Ut24X77qyBLP7SGxK5OUg==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/react-core": "^1.0.1" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wallet-standard/react-core": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@wallet-standard/react-core/-/react-core-1.0.1.tgz", + "integrity": "sha512-g+vZaLlAGlYMwZEoKsmjjI5qz1D8P3FF1aqiI3WLooWOVk55Nszbpk01QCbIFdIMF0UDhxia2FU667TCv509iw==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/app": "^1.1.0", + "@wallet-standard/base": "^1.1.0", + "@wallet-standard/errors": "^0.1.1", + "@wallet-standard/experimental-features": "^0.2.0", + "@wallet-standard/features": "^1.1.0", + "@wallet-standard/ui": "^1.0.1", + "@wallet-standard/ui-registry": "^1.0.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/@wallet-standard/ui": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@wallet-standard/ui/-/ui-1.0.1.tgz", @@ -16121,12 +19645,62 @@ "node": ">=16" } }, + "node_modules/@wry/caches": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@wry/caches/-/caches-1.0.1.tgz", + "integrity": "sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/context": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.4.tgz", + "integrity": "sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/equality": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.7.tgz", + "integrity": "sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/trie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.5.0.tgz", + "integrity": "sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", "license": "BSD-2-Clause" }, + "node_modules/@yr/monotone-cubic-spline": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz", + "integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==", + "license": "MIT" + }, "node_modules/@zksync/contracts": { "name": "era-contracts", "version": "0.1.0", @@ -16237,24 +19811,6 @@ "node": ">= 8.0.0" } }, - "node_modules/ai": { - "version": "5.0.101", - "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.101.tgz", - "integrity": "sha512-/P4fgs2PGYTBaZi192YkPikOudsl9vccA65F7J7LvoNTOoP5kh1yAsJPsKAy6FXU32bAngai7ft1UDyC3u7z5g==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/gateway": "2.0.15", - "@ai-sdk/provider": "2.0.0", - "@ai-sdk/provider-utils": "3.0.17", - "@opentelemetry/api": "1.9.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, "node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -16298,35 +19854,35 @@ } }, "node_modules/algoliasearch": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.45.0.tgz", - "integrity": "sha512-wrj4FGr14heLOYkBKV3Fbq5ZBGuIFeDJkTilYq/G+hH1CSlQBtYvG2X1j67flwv0fUeQJwnWxxRIunSemAZirA==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.48.0.tgz", + "integrity": "sha512-aD8EQC6KEman6/S79FtPdQmB7D4af/etcRL/KwiKFKgAE62iU8c5PeEQvpvIcBPurC3O/4Lj78nOl7ZcoazqSw==", "license": "MIT", "peer": true, "dependencies": { - "@algolia/abtesting": "1.11.0", - "@algolia/client-abtesting": "5.45.0", - "@algolia/client-analytics": "5.45.0", - "@algolia/client-common": "5.45.0", - "@algolia/client-insights": "5.45.0", - "@algolia/client-personalization": "5.45.0", - "@algolia/client-query-suggestions": "5.45.0", - "@algolia/client-search": "5.45.0", - "@algolia/ingestion": "1.45.0", - "@algolia/monitoring": "1.45.0", - "@algolia/recommend": "5.45.0", - "@algolia/requester-browser-xhr": "5.45.0", - "@algolia/requester-fetch": "5.45.0", - "@algolia/requester-node-http": "5.45.0" + "@algolia/abtesting": "1.14.0", + "@algolia/client-abtesting": "5.48.0", + "@algolia/client-analytics": "5.48.0", + "@algolia/client-common": "5.48.0", + "@algolia/client-insights": "5.48.0", + "@algolia/client-personalization": "5.48.0", + "@algolia/client-query-suggestions": "5.48.0", + "@algolia/client-search": "5.48.0", + "@algolia/ingestion": "1.48.0", + "@algolia/monitoring": "1.48.0", + "@algolia/recommend": "5.48.0", + "@algolia/requester-browser-xhr": "5.48.0", + "@algolia/requester-fetch": "5.48.0", + "@algolia/requester-node-http": "5.48.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/algoliasearch-helper": { - "version": "3.26.1", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.26.1.tgz", - "integrity": "sha512-CAlCxm4fYBXtvc5MamDzP6Svu8rW4z9me4DCBY1rQ2UDJ0u0flWmusQ8M3nOExZsLLRcUwUPoRAPMrhzOG3erw==", + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.27.0.tgz", + "integrity": "sha512-eNYchRerbsvk2doHOMfdS1/B6Tm70oGtu8mzQlrNzbCeQ8p1MjCW8t/BL6iZ5PD+cL5NNMgTMyMnmiXZ1sgmNw==", "license": "MIT", "dependencies": { "@algolia/events": "^4.0.1" @@ -16444,16 +20000,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/antlr4": { - "version": "4.13.2", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.2.tgz", - "integrity": "sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=16" - } - }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -16473,6 +20019,20 @@ "node": ">= 8" } }, + "node_modules/apexcharts": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-4.5.0.tgz", + "integrity": "sha512-E7ZkrVqPNBUWy/Rmg8DEIqHNBmElzICE/oxOX5Ekvs2ICQUOK/VkEkMH09JGJu+O/EA0NL31hxlmF+wrwrSLaQ==", + "license": "MIT", + "dependencies": { + "@svgdotjs/svg.draggable.js": "^3.0.4", + "@svgdotjs/svg.filter.js": "^3.0.8", + "@svgdotjs/svg.js": "^3.2.4", + "@svgdotjs/svg.resize.js": "^2.0.2", + "@svgdotjs/svg.select.js": "^4.0.1", + "@yr/monotone-cubic-spline": "^1.0.3" + } + }, "node_modules/apg-lite": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/apg-lite/-/apg-lite-1.0.5.tgz", @@ -16696,16 +20256,16 @@ } }, "node_modules/astro": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/astro/-/astro-5.16.0.tgz", - "integrity": "sha512-GaDRs2Mngpw3dr2vc085GnORh98NiXxwIjg/EoQQQl/icZt3Z7s0BRsYHDZ8swkZbOA6wZsqWJdrNirl+iKcDg==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.17.1.tgz", + "integrity": "sha512-oD3tlxTaVWGq/Wfbqk6gxzVRz98xa/rYlpe+gU2jXJMSD01k6sEDL01ZlT8mVSYB/rMgnvIOfiQQ3BbLdN237A==", "license": "MIT", "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.5", - "@astrojs/markdown-remark": "6.3.9", + "@astrojs/markdown-remark": "6.3.10", "@astrojs/telemetry": "3.3.0", - "@capsizecss/unpack": "^3.0.1", + "@capsizecss/unpack": "^4.0.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "acorn": "^8.15.0", @@ -16715,19 +20275,19 @@ "ci-info": "^4.3.1", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", - "cookie": "^1.0.2", + "cookie": "^1.1.1", "cssesc": "^3.0.0", "debug": "^4.4.3", "deterministic-object-hash": "^2.0.2", - "devalue": "^5.5.0", - "diff": "^5.2.0", + "devalue": "^5.6.2", + "diff": "^8.0.3", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", - "fontace": "~0.3.1", + "fontace": "~0.4.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", @@ -16739,22 +20299,22 @@ "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.1", - "package-manager-detector": "^1.5.0", + "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", - "shiki": "^3.15.0", - "smol-toml": "^1.5.0", + "shiki": "^3.21.0", + "smol-toml": "^1.6.0", "svgo": "^4.0.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", - "unifont": "~0.6.0", + "unifont": "~0.7.3", "unist-util-visit": "^5.0.0", - "unstorage": "^1.17.2", + "unstorage": "^1.17.4", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", @@ -16762,7 +20322,7 @@ "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", - "zod-to-json-schema": "^3.24.6", + "zod-to-json-schema": "^3.25.1", "zod-to-ts": "^1.2.0" }, "bin": { @@ -16810,15 +20370,15 @@ "license": "MIT" }, "node_modules/astro/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -16846,10 +20406,13 @@ "license": "MIT" }, "node_modules/astro/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } }, "node_modules/astro/node_modules/p-limit": { "version": "6.2.0", @@ -16895,9 +20458,9 @@ } }, "node_modules/astro/node_modules/package-manager-detector": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.5.0.tgz", - "integrity": "sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", "license": "MIT" }, "node_modules/astro/node_modules/picomatch": { @@ -16913,12 +20476,12 @@ } }, "node_modules/astro/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">= 20.19.0" }, "funding": { "type": "individual", @@ -16938,19 +20501,19 @@ } }, "node_modules/astro/node_modules/unstorage": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.3.tgz", - "integrity": "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==", + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.4.tgz", + "integrity": "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==", "license": "MIT", "dependencies": { "anymatch": "^3.1.3", - "chokidar": "^4.0.3", + "chokidar": "^5.0.0", "destr": "^2.0.5", - "h3": "^1.15.4", - "lru-cache": "^10.4.3", + "h3": "^1.15.5", + "lru-cache": "^11.2.0", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", - "ufo": "^1.6.1" + "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", @@ -16959,14 +20522,14 @@ "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", - "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", - "@vercel/kv": "^1.0.1", + "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", @@ -17089,6 +20652,43 @@ "tslib": "^2.3.0" } }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -17495,15 +21095,6 @@ "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", "license": "MIT" }, - "node_modules/brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.1.2" - } - }, "node_modules/browserslist": { "version": "4.28.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", @@ -17609,9 +21200,9 @@ } }, "node_modules/bufferutil": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", - "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", + "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", "hasInstallScript": true, "license": "MIT", "optional": true, @@ -17658,7 +21249,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "peer": true, "dependencies": { "streamsearch": "^1.1.0" }, @@ -18170,8 +21760,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/clipboard": { "version": "2.0.11", @@ -18249,15 +21838,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -18425,12 +22005,16 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cookie-es": { @@ -19011,9 +22595,9 @@ } }, "node_modules/devalue": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.5.0.tgz", - "integrity": "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.2.tgz", + "integrity": "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==", "license": "MIT" }, "node_modules/devlop": { @@ -19029,12 +22613,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/dfa": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", - "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", - "license": "MIT" - }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -19042,9 +22620,9 @@ "license": "Apache-2.0" }, "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -19984,14 +23562,14 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", - "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", "dev": true, "license": "MIT", "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.7" + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -20532,9 +24110,9 @@ } }, "node_modules/ethers": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.15.0.tgz", - "integrity": "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", + "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", "funding": [ { "type": "individual", @@ -20641,15 +24219,6 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -20792,9 +24361,9 @@ } }, "node_modules/fast-copy": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", - "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.1.tgz", + "integrity": "sha512-+uUOQlhsaswsizHFmEFAQhB3lSiQ+lisxl50N6ZP0wywlZeWsIESxSi9ftPEps8UGfiBzyYP7x27zA674WUvXw==", "dev": true, "license": "MIT" }, @@ -21087,22 +24656,22 @@ "peer": true }, "node_modules/focus-trap": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.6.tgz", - "integrity": "sha512-v/Z8bvMCajtx4mEXmOo7QEsIzlIOqRXTIwgUfsFOF9gEsespdbD0AkPIka1bSXZ8Y8oZ+2IVDQZePkTfEHZl7Q==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", "license": "MIT", "dependencies": { - "tabbable": "^6.3.0" + "tabbable": "^6.4.0" } }, "node_modules/focus-trap-react": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/focus-trap-react/-/focus-trap-react-11.0.4.tgz", - "integrity": "sha512-tC7jC/yqeAqhe4irNIzdyDf9XCtGSeECHiBSYJBO/vIN0asizbKZCt8TarB6/XqIceu42ajQ/U4lQJ9pZlWjrg==", + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/focus-trap-react/-/focus-trap-react-11.0.6.tgz", + "integrity": "sha512-8YbWR8kDf2pQ8G9LT11p39VY4T7eWVrj00Fhp1HUSdv5uW9q6+WK8OMAdy9Ui7vGb1zNouFDzwBIqJwt82rIYQ==", "license": "MIT", "dependencies": { - "focus-trap": "^7.6.5", - "tabbable": "^6.2.0" + "focus-trap": "^7.8.0", + "tabbable": "^6.4.0" }, "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", @@ -21132,30 +24701,24 @@ } }, "node_modules/fontace": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.3.1.tgz", - "integrity": "sha512-9f5g4feWT1jWT8+SbL85aLIRLIXUaDygaM2xPXRmzPYxrOMNok79Lr3FGJoKVNKibE0WCunNiEVG2mwuE+2qEg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.0.tgz", + "integrity": "sha512-moThBCItUe2bjZip5PF/iZClpKHGLwMvR79Kp8XpGRBrvoRSnySN4VcILdv3/MJzbhvUA5WeiUXF5o538m5fvg==", "license": "MIT", "dependencies": { - "@types/fontkit": "^2.0.8", - "fontkit": "^2.0.4" + "fontkitten": "^1.0.0" } }, - "node_modules/fontkit": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz", - "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==", + "node_modules/fontkitten": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.0.tgz", + "integrity": "sha512-b0RdzQeztiiUFWEDzq6Ka26qkNVNLCehoRtifOIGNbQ4CfxyYRh73fyWaQX/JshPVcueITOEeoSWPy5XQv8FUg==", "license": "MIT", "dependencies": { - "@swc/helpers": "^0.5.12", - "brotli": "^1.3.2", - "clone": "^2.1.2", - "dfa": "^1.2.0", - "fast-deep-equal": "^3.1.3", - "restructure": "^3.0.0", - "tiny-inflate": "^1.0.3", - "unicode-properties": "^1.4.0", - "unicode-trie": "^2.0.0" + "tiny-inflate": "^1.0.3" + }, + "engines": { + "node": ">=20" } }, "node_modules/for-each": { @@ -21239,6 +24802,19 @@ "node": ">=18.3.0" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -21642,10 +25218,33 @@ "dev": true, "license": "MIT" }, + "node_modules/graphql": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", + "integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-tag": { + "version": "2.12.6", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", + "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, "node_modules/h3": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.4.tgz", - "integrity": "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.5.tgz", + "integrity": "sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==", "license": "MIT", "dependencies": { "cookie-es": "^1.2.2", @@ -21653,9 +25252,9 @@ "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", - "node-mock-http": "^1.0.2", + "node-mock-http": "^1.0.4", "radix3": "^1.1.2", - "ufo": "^1.6.1", + "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, @@ -22326,6 +25925,19 @@ "node": "*" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/htm": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/htm/-/htm-3.1.1.tgz", @@ -22463,6 +26075,15 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", @@ -22629,13 +26250,12 @@ "license": "MIT" }, "node_modules/instantsearch-ui-components": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/instantsearch-ui-components/-/instantsearch-ui-components-0.15.0.tgz", - "integrity": "sha512-eQYwOgHk7+JJwr8C/QQOAsiPV8JdDN7D5edjO1VZVW6UgZWvTlfRR7xM9qPLJjpqbZMw46n1N2Bx8ZAYQjXiCA==", + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/instantsearch-ui-components/-/instantsearch-ui-components-0.17.1.tgz", + "integrity": "sha512-uOn39sNs9ukK0N6pklVdxbE5dapIdSJmkh/WJPPtOe4bpnvLzzvvexQYpUJ9vy1xQJMaQcAoPMoMKfBXwUA29A==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.6", - "ai": "^5.0.18", "markdown-to-jsx": "^7.7.15", "zod": "^3.25.76 || ^4", "zod-to-json-schema": "3.24.6" @@ -22651,9 +26271,9 @@ } }, "node_modules/instantsearch.js": { - "version": "4.84.0", - "resolved": "https://registry.npmjs.org/instantsearch.js/-/instantsearch.js-4.84.0.tgz", - "integrity": "sha512-7ThTNzBgyFJgZT2ng/0lwGmCXZnK3nq5476bu0hL5u6Nc+AuKFGtAMKlNozXI/Nel3i3WJkoWwxO+37OxfqQmw==", + "version": "4.87.1", + "resolved": "https://registry.npmjs.org/instantsearch.js/-/instantsearch.js-4.87.1.tgz", + "integrity": "sha512-KkOSosDPnCXZg5QNZ6AnW+wWJaTsK0kXzUyr4/ugGE/Tm5Fn5D08yC9RFT4JxlvDJw+re0ov1xBbWKBcBn8XuA==", "license": "MIT", "dependencies": { "@algolia/events": "^4.0.1", @@ -22661,13 +26281,12 @@ "@types/google.maps": "^3.55.12", "@types/hogan.js": "^3.0.0", "@types/qs": "^6.5.3", - "ai": "^5.0.18", - "algoliasearch-helper": "3.26.1", + "algoliasearch-helper": "3.27.0", "hogan.js": "^3.0.2", "htm": "^3.0.0", - "instantsearch-ui-components": "0.15.0", + "instantsearch-ui-components": "0.17.1", "preact": "^10.10.0", - "qs": "^6.5.1 < 6.10", + "qs": "^6.5.1", "react": ">= 0.14.0", "search-insights": "^2.17.2", "zod": "^3.25.76 || ^4", @@ -26878,12 +30497,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -26997,9 +30610,9 @@ } }, "node_modules/knip": { - "version": "5.70.2", - "resolved": "https://registry.npmjs.org/knip/-/knip-5.70.2.tgz", - "integrity": "sha512-LI7DbeVnk7h9+FAet5KzzHNdDwJyqDa2+cn4uQfZYTfpuVjEqtGmYD9r5b9JEuOs4eVkf/7sskNhWXxELm3C/Q==", + "version": "5.83.1", + "resolved": "https://registry.npmjs.org/knip/-/knip-5.83.1.tgz", + "integrity": "sha512-av3ZG/Nui6S/BNL8Tmj12yGxYfTnwWnslouW97m40him7o8MwiMjZBY9TPvlEWUci45aVId0/HbgTwSKIDGpMw==", "dev": true, "funding": [ { @@ -27019,7 +30632,7 @@ "jiti": "^2.6.0", "js-yaml": "^4.1.1", "minimist": "^1.2.8", - "oxc-resolver": "^11.13.2", + "oxc-resolver": "^11.15.0", "picocolors": "^1.1.1", "picomatch": "^4.0.1", "smol-toml": "^1.5.2", @@ -27391,9 +31004,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -29614,13 +33227,12 @@ } }, "node_modules/next": { - "version": "14.2.33", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.33.tgz", - "integrity": "sha512-GiKHLsD00t4ACm1p00VgrI0rUFAC9cRDGReKyERlM57aeEZkOQGcZTpIbsGn0b562FTPJWmYfKwplfO9EaT6ng==", + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.35.tgz", + "integrity": "sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==", "license": "MIT", - "peer": true, "dependencies": { - "@next/env": "14.2.33", + "@next/env": "14.2.35", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -29669,7 +33281,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "tslib": "^2.4.0" @@ -29694,7 +33305,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -29840,9 +33450,9 @@ "license": "MIT" }, "node_modules/node-mock-http": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.3.tgz", - "integrity": "sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz", + "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==", "license": "MIT" }, "node_modules/node-releases": { @@ -29875,6 +33485,15 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/normalize-url": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.0.tgz", @@ -29961,7 +33580,6 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -30210,6 +33828,17 @@ "dev": true, "license": "MIT" }, + "node_modules/optimism": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.1.tgz", + "integrity": "sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==", + "dependencies": { + "@wry/caches": "^1.0.0", + "@wry/context": "^0.7.0", + "@wry/trie": "^0.5.0", + "tslib": "^2.3.0" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -30262,34 +33891,35 @@ } }, "node_modules/oxc-resolver": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.14.0.tgz", - "integrity": "sha512-i4wNrqhOd+4YdHJfHglHtFiqqSxXuzFA+RUqmmWN1aMD3r1HqUSrIhw17tSO4jwKfhLs9uw1wzFPmvMsWacStg==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.15.0.tgz", + "integrity": "sha512-Hk2J8QMYwmIO9XTCUiOH00+Xk2/+aBxRUnhrSlANDyCnLYc32R1WSIq1sU2yEdlqd53FfMpPEpnBYIKQMzliJw==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-resolver/binding-android-arm-eabi": "11.14.0", - "@oxc-resolver/binding-android-arm64": "11.14.0", - "@oxc-resolver/binding-darwin-arm64": "11.14.0", - "@oxc-resolver/binding-darwin-x64": "11.14.0", - "@oxc-resolver/binding-freebsd-x64": "11.14.0", - "@oxc-resolver/binding-linux-arm-gnueabihf": "11.14.0", - "@oxc-resolver/binding-linux-arm-musleabihf": "11.14.0", - "@oxc-resolver/binding-linux-arm64-gnu": "11.14.0", - "@oxc-resolver/binding-linux-arm64-musl": "11.14.0", - "@oxc-resolver/binding-linux-ppc64-gnu": "11.14.0", - "@oxc-resolver/binding-linux-riscv64-gnu": "11.14.0", - "@oxc-resolver/binding-linux-riscv64-musl": "11.14.0", - "@oxc-resolver/binding-linux-s390x-gnu": "11.14.0", - "@oxc-resolver/binding-linux-x64-gnu": "11.14.0", - "@oxc-resolver/binding-linux-x64-musl": "11.14.0", - "@oxc-resolver/binding-wasm32-wasi": "11.14.0", - "@oxc-resolver/binding-win32-arm64-msvc": "11.14.0", - "@oxc-resolver/binding-win32-ia32-msvc": "11.14.0", - "@oxc-resolver/binding-win32-x64-msvc": "11.14.0" + "@oxc-resolver/binding-android-arm-eabi": "11.15.0", + "@oxc-resolver/binding-android-arm64": "11.15.0", + "@oxc-resolver/binding-darwin-arm64": "11.15.0", + "@oxc-resolver/binding-darwin-x64": "11.15.0", + "@oxc-resolver/binding-freebsd-x64": "11.15.0", + "@oxc-resolver/binding-linux-arm-gnueabihf": "11.15.0", + "@oxc-resolver/binding-linux-arm-musleabihf": "11.15.0", + "@oxc-resolver/binding-linux-arm64-gnu": "11.15.0", + "@oxc-resolver/binding-linux-arm64-musl": "11.15.0", + "@oxc-resolver/binding-linux-ppc64-gnu": "11.15.0", + "@oxc-resolver/binding-linux-riscv64-gnu": "11.15.0", + "@oxc-resolver/binding-linux-riscv64-musl": "11.15.0", + "@oxc-resolver/binding-linux-s390x-gnu": "11.15.0", + "@oxc-resolver/binding-linux-x64-gnu": "11.15.0", + "@oxc-resolver/binding-linux-x64-musl": "11.15.0", + "@oxc-resolver/binding-openharmony-arm64": "11.15.0", + "@oxc-resolver/binding-wasm32-wasi": "11.15.0", + "@oxc-resolver/binding-win32-arm64-msvc": "11.15.0", + "@oxc-resolver/binding-win32-ia32-msvc": "11.15.0", + "@oxc-resolver/binding-win32-x64-msvc": "11.15.0" } }, "node_modules/p-cancelable": { @@ -30899,21 +34529,21 @@ } }, "node_modules/pino-pretty": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.2.tgz", - "integrity": "sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ==", + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", "dev": true, "license": "MIT", "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", - "fast-copy": "^3.0.2", + "fast-copy": "^4.0.0", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^2.0.0", + "pino-abstract-transport": "^3.0.0", "pump": "^3.0.0", "secure-json-parse": "^4.0.0", "sonic-boom": "^4.0.1", @@ -30923,6 +34553,16 @@ "pino-pretty": "bin.js" } }, + "node_modules/pino-pretty/node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, "node_modules/pino-pretty/node_modules/strip-json-comments": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", @@ -31152,9 +34792,9 @@ "license": "MIT" }, "node_modules/preact": { - "version": "10.27.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.27.2.tgz", - "integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==", + "version": "10.28.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.3.tgz", + "integrity": "sha512-tCmoRkPQLpBeWzpmbhryairGnhW9tKV6c6gr/w+RhoRoKEJwsjzipwp//1oCpGPOchvSLaAPlpcJi9MwMmoPyA==", "license": "MIT", "funding": { "type": "opencollective", @@ -31181,9 +34821,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -31197,9 +34837,9 @@ } }, "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", "dev": true, "license": "MIT", "dependencies": { @@ -31224,6 +34864,34 @@ "node": "^14.15.0 || >=16.0.0" } }, + "node_modules/prettier-plugin-solidity": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.3.tgz", + "integrity": "sha512-Mrr/iiR9f9IaeGRMZY2ApumXcn/C5Gs3S7B7hWB3gigBFML06C0yEyW86oLp0eqiA0qg+46FaChgLPJCj/pIlg==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.20.1", + "semver": "^7.7.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "prettier": ">=2.3.0" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -31507,10 +35175,13 @@ } }, "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, "engines": { "node": ">=0.6" }, @@ -31691,6 +35362,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-apexcharts": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/react-apexcharts/-/react-apexcharts-1.7.0.tgz", + "integrity": "sha512-03oScKJyNLRf0Oe+ihJxFZliBQM9vW3UWwomVn4YVRTN1jsIR58dLWt0v1sb8RwJVHDMbeHiKQueM0KGpn7nOA==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "apexcharts": ">=4.0.0", + "react": ">=0.13" + } + }, "node_modules/react-copy-to-clipboard": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", @@ -31763,6 +35447,22 @@ "react": "^18.3.1" } }, + "node_modules/react-hook-form": { + "version": "7.53.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.1.tgz", + "integrity": "sha512-6aiQeBda4zjcuaugWvim9WsGqisoUk+etmFEsSUMm451/Ic8L/UAb7sRtMj3V+Hdzm6mMjU1VhiSzYUZeBm0Vg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, "node_modules/react-immutable-proptypes": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/react-immutable-proptypes/-/react-immutable-proptypes-2.2.0.tgz", @@ -31796,15 +35496,15 @@ } }, "node_modules/react-instantsearch": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/react-instantsearch/-/react-instantsearch-7.20.0.tgz", - "integrity": "sha512-I7luR9MstQSe0olLqZj+DB5+U0P9Gd8mcNTWhqr0e+mKIWize6le+/BoGgvp8yJhBlXCSLLpbU9SvE0UilYcqQ==", + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/react-instantsearch/-/react-instantsearch-7.23.1.tgz", + "integrity": "sha512-+AKTEm9JwuvGPS9Bkxnayaz7IhZ1TMLxv7DplgT6uCr4kB5jYPU5YbIqlZv0Zo7oiv49DXbLt8w6XriwZAnAaA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.6", - "instantsearch-ui-components": "0.15.0", - "instantsearch.js": "4.84.0", - "react-instantsearch-core": "7.20.0" + "instantsearch-ui-components": "0.17.1", + "instantsearch.js": "4.87.1", + "react-instantsearch-core": "7.23.1" }, "peerDependencies": { "algoliasearch": ">= 3.1 < 6", @@ -31813,15 +35513,14 @@ } }, "node_modules/react-instantsearch-core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/react-instantsearch-core/-/react-instantsearch-core-7.20.0.tgz", - "integrity": "sha512-awTPtAEozGWNVcZ969fMBO1S61QPDT13NdIlDjtoeg6GF4ZN9TXH+B/kjK5OxN0WzdbWxrE1nPGNfH9lHS7ZMg==", + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/react-instantsearch-core/-/react-instantsearch-core-7.23.1.tgz", + "integrity": "sha512-mKmy7llIMF9DlJza8maHEwObONf49gXJP+rS4BMb6GgRi3IVi2OBxdPmia9C7JXANR2x2fYxm7uSxYyMs1qveQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.6", - "ai": "^5.0.18", - "algoliasearch-helper": "3.26.1", - "instantsearch.js": "4.84.0", + "algoliasearch-helper": "3.27.0", + "instantsearch.js": "4.87.1", "use-sync-external-store": "^1.0.0", "zod": "^3.25.76 || ^4", "zod-to-json-schema": "3.24.6" @@ -32309,9 +36008,9 @@ "peer": true }, "node_modules/regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", - "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", "license": "MIT", "dependencies": { "regex-utilities": "^2.3.0" @@ -32395,6 +36094,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/rehackt": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/rehackt/-/rehackt-0.1.0.tgz", + "integrity": "sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==", + "peerDependencies": { + "@types/react": "*", + "react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/rehype": { "version": "13.0.2", "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", @@ -32894,12 +36610,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/restructure": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz", - "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==", - "license": "MIT" - }, "node_modules/ret": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", @@ -33252,7 +36962,8 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/search-insights": { "version": "2.17.3", @@ -33626,17 +37337,17 @@ } }, "node_modules/shiki": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.15.0.tgz", - "integrity": "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.21.0.tgz", + "integrity": "sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w==", "license": "MIT", "dependencies": { - "@shikijs/core": "3.15.0", - "@shikijs/engine-javascript": "3.15.0", - "@shikijs/engine-oniguruma": "3.15.0", - "@shikijs/langs": "3.15.0", - "@shikijs/themes": "3.15.0", - "@shikijs/types": "3.15.0", + "@shikijs/core": "3.21.0", + "@shikijs/engine-javascript": "3.21.0", + "@shikijs/engine-oniguruma": "3.21.0", + "@shikijs/langs": "3.21.0", + "@shikijs/themes": "3.21.0", + "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } @@ -33655,7 +37366,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -33675,7 +37385,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -33692,7 +37401,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -33711,7 +37419,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -33819,9 +37526,9 @@ } }, "node_modules/smol-toml": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.5.2.tgz", - "integrity": "sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.0.tgz", + "integrity": "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==", "license": "BSD-3-Clause", "engines": { "node": ">= 18" @@ -33847,16 +37554,15 @@ "license": "MIT" }, "node_modules/solhint": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-6.0.1.tgz", - "integrity": "sha512-Lew5nhmkXqHPybzBzkMzvvWkpOJSSLTkfTZwRriWvfR2naS4YW2PsjVGaoX9tZFmHh7SuS+e2GEGo5FPYYmJ8g==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-6.0.3.tgz", + "integrity": "sha512-LYiy1bN8X9eUsti13mbS4fY6ILVxhP6VoOgqbHxCsHl5VPnxOWf7U1V9ZvgizxdInKBMW82D1FNJO+daAcWHbA==", "dev": true, "license": "MIT", "dependencies": { "@solidity-parser/parser": "^0.20.2", "ajv": "^6.12.6", "ajv-errors": "^1.0.1", - "antlr4": "^4.13.1-patch-1", "ast-parents": "^0.0.1", "better-ajv-errors": "^2.0.2", "chalk": "^4.1.2", @@ -33886,6 +37592,20 @@ "resolved": "git+ssh://git@github.com/smartcontractkit/chainlink-solhint-rules.git#2f0a3a6c3475607bb0cf8ab1a1df979534453ba9", "dev": true }, + "node_modules/solhint-plugin-prettier": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.1.0.tgz", + "integrity": "sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==", + "dev": true, + "dependencies": { + "@prettier/sync": "^0.3.0", + "prettier-linter-helpers": "^1.0.0" + }, + "peerDependencies": { + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.0.0" + } + }, "node_modules/solhint/node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -34003,6 +37723,16 @@ "atomic-sleep": "^1.0.0" } }, + "node_modules/sonner": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.7.3.tgz", + "integrity": "sha512-KXLWQfyR6AHpYZuQk8eO8fCbZSJY3JOpgsu/tbGc++jgPjj8JsR1ZpO8vFhqR/OxvWMQCSAmnSShY0gr4FPqHg==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/source-map": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", @@ -34188,7 +37918,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "peer": true, "engines": { "node": ">=10.0.0" } @@ -34456,7 +38185,6 @@ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", "license": "MIT", - "peer": true, "dependencies": { "client-only": "0.0.1" }, @@ -34608,18 +38336,18 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.30.2", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.30.2.tgz", - "integrity": "sha512-HWCg1DTNE/Nmapt+0m2EPXFwNKNeKK4PwMjkwveN/zn1cV2Kxi9SURd+m0SpdcSgWEK/O64sf8bzXdtUhigtHA==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.31.0.tgz", + "integrity": "sha512-zSUTIck02fSga6rc0RZP3b7J7wgHXwLea8ZjgLA3Vgnb8QeOl3Wou2/j5QkzSGeoz6HusP/coYuJl33aQxQZpg==", "license": "Apache-2.0", "dependencies": { "@scarf/scarf": "=1.4.0" } }, "node_modules/swagger-ui-react": { - "version": "5.30.2", - "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-5.30.2.tgz", - "integrity": "sha512-0tS9GOcswKuQrIpCyvDoCDs6xS8B6MRC+iE7P99WfVXDhAIU+U7iFHuS4e7zucSh9qXvcL7KsXs623c+4oBe6w==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-5.31.0.tgz", + "integrity": "sha512-E/sTgKADThzpVksaGXbhED0pQCYdajiBNOzvSAan+RhV7pdoi2qvdwWhZsIo8nRvHk9UXJ0nkuxrud854ICr7A==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.27.1", @@ -34633,7 +38361,7 @@ "ieee754": "^1.2.1", "immutable": "^3.x.x", "js-file-download": "^0.4.12", - "js-yaml": "=4.1.0", + "js-yaml": "=4.1.1", "lodash": "^4.17.21", "prop-types": "^15.8.1", "randexp": "^0.5.3", @@ -34671,22 +38399,18 @@ "@types/trusted-types": "^2.0.7" } }, - "node_modules/swagger-ui-react/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "engines": { + "node": ">=0.10" } }, "node_modules/synckit": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", - "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -34700,9 +38424,9 @@ } }, "node_modules/tabbable": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.3.0.tgz", - "integrity": "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", "license": "MIT" }, "node_modules/table": { @@ -34786,33 +38510,33 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", - "integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", + "version": "3.4.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz", + "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.3.0", + "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.21.0", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", @@ -34831,6 +38555,19 @@ "tailwindcss": ">=3.0.0 || insiders" } }, + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "extraneous": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/tailwindcss/node_modules/jiti": { "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", @@ -34840,13 +38577,32 @@ "jiti": "bin/jiti.js" } }, - "node_modules/tailwindcss/node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "node_modules/tailwindcss/node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, "engines": { - "node": ">=10" + "node": "^10 || ^12 || >=14" } }, "node_modules/tar": { @@ -35228,10 +38984,21 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "license": "Apache-2.0" }, + "node_modules/ts-invariant": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", + "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ts-jest": { - "version": "29.4.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz", - "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", "dev": true, "license": "MIT", "dependencies": { @@ -35381,13 +39148,13 @@ "license": "0BSD" }, "node_modules/tsx": { - "version": "4.20.6", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", - "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "devOptional": true, "license": "MIT", "dependencies": { - "esbuild": "~0.25.0", + "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "bin": { @@ -35400,6 +39167,464 @@ "fsevents": "~2.3.3" } }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz", + "integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.0.tgz", + "integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz", + "integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.0.tgz", + "integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz", + "integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz", + "integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz", + "integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz", + "integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz", + "integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz", + "integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz", + "integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz", + "integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz", + "integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz", + "integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz", + "integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz", + "integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz", + "integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz", + "integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz", + "integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz", + "integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz", + "integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz", + "integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz", + "integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz", + "integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz", + "integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz", + "integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz", + "integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==", + "devOptional": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.0", + "@esbuild/android-arm": "0.27.0", + "@esbuild/android-arm64": "0.27.0", + "@esbuild/android-x64": "0.27.0", + "@esbuild/darwin-arm64": "0.27.0", + "@esbuild/darwin-x64": "0.27.0", + "@esbuild/freebsd-arm64": "0.27.0", + "@esbuild/freebsd-x64": "0.27.0", + "@esbuild/linux-arm": "0.27.0", + "@esbuild/linux-arm64": "0.27.0", + "@esbuild/linux-ia32": "0.27.0", + "@esbuild/linux-loong64": "0.27.0", + "@esbuild/linux-mips64el": "0.27.0", + "@esbuild/linux-ppc64": "0.27.0", + "@esbuild/linux-riscv64": "0.27.0", + "@esbuild/linux-s390x": "0.27.0", + "@esbuild/linux-x64": "0.27.0", + "@esbuild/netbsd-arm64": "0.27.0", + "@esbuild/netbsd-x64": "0.27.0", + "@esbuild/openbsd-arm64": "0.27.0", + "@esbuild/openbsd-x64": "0.27.0", + "@esbuild/openharmony-arm64": "0.27.0", + "@esbuild/sunos-x64": "0.27.0", + "@esbuild/win32-arm64": "0.27.0", + "@esbuild/win32-ia32": "0.27.0", + "@esbuild/win32-x64": "0.27.0" + } + }, "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -35540,9 +39765,9 @@ } }, "node_modules/ufo": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", - "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", "license": "MIT" }, "node_modules/uglify-js": { @@ -35591,35 +39816,9 @@ "license": "MIT" }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "license": "MIT" - }, - "node_modules/unicode-properties": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", - "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/unicode-trie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "license": "MIT", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/unicode-trie/node_modules/pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.20.0.tgz", + "integrity": "sha512-PZDAAlMkNw5ZzN/ebfyrwzrMWfIf7Jbn9iM/I6SF456OKrb2wnfqVowaxEY/cMAM8MjFu1zhdpJyA0L+rTYwNw==", "license": "MIT" }, "node_modules/unified": { @@ -35642,14 +39841,14 @@ } }, "node_modules/unifont": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.6.0.tgz", - "integrity": "sha512-5Fx50fFQMQL5aeHyWnZX9122sSLckcDvcfFiBf3QYeHa7a1MKJooUy52b67moi2MJYkrfo/TWY+CoLdr/w0tTA==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.3.tgz", + "integrity": "sha512-b0GtQzKCyuSHGsfj5vyN8st7muZ6VCI4XD4vFlr7Uy1rlWVYxC3npnfk8MyreHxJYrz1ooLDqDzFe9XqQTlAhA==", "license": "MIT", "dependencies": { - "css-tree": "^3.0.0", - "ofetch": "^1.4.1", - "ohash": "^2.0.0" + "css-tree": "^3.1.0", + "ofetch": "^1.5.1", + "ohash": "^2.0.11" } }, "node_modules/unist-util-filter": { @@ -35758,9 +39957,9 @@ } }, "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -36595,9 +40794,9 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -36772,6 +40971,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + }, + "node_modules/zen-observable-ts": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz", + "integrity": "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==", + "dependencies": { + "zen-observable": "0.8.15" + } + }, "node_modules/zenscroll": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/zenscroll/-/zenscroll-4.0.2.tgz", @@ -36788,9 +41000,9 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.25.0", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz", - "integrity": "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==", + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", "license": "ISC", "peerDependencies": { "zod": "^3.25 || ^4" diff --git a/package.json b/package.json index 0bf30cc7c44..5ac7832c61b 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "astro": "astro", "dev": "astro dev", "start": "astro dev", - "build": "astro build && npm run pin-sol-version", + "build": "astro build && npm run pin-sol-version && node scripts/cleanup-vercel-function.mjs", "preview": "astro preview", "pin-sol-version": "tsx --require tsconfig-paths/register src/scripts/helper/pin-solver-dist.ts", "linkcheckWrapper": "tsx --require tsconfig-paths/register src/scripts/link-check/linkcheckWrapper.ts", @@ -55,13 +55,17 @@ }, "dependencies": { "@11ty/eleventy-fetch": "^4.0.1", - "@astro-community/astro-embed-youtube": "^0.5.9", - "@astrojs/mdx": "^4.3.12", + "@algolia/client-search": "^5.41.0", + "@apollo/client": "^3.14.0", + "@astro-community/astro-embed-youtube": "^0.5.10", + "@astrojs/mdx": "^4.3.13", "@astrojs/partytown": "^2.1.4", "@astrojs/preact": "^4.1.3", "@astrojs/prism": "^3.3.0", "@astrojs/react": "^4.4.2", - "@astrojs/sitemap": "^3.6.0", + "@astrojs/sitemap": "^3.7.0", + "@astrojs/tailwind": "^6.0.2", + "@chainlink/blocks": "^1.3.1", "@astrojs/vercel": "^8.2.11", "@chainlink/cl-search-frontend": "^0.12.1", "@chainlink/components": "^0.4.18", @@ -72,43 +76,44 @@ "@chainlink/local": "0.2.7-beta", "@chainlink/solana-sdk": "^0.2.2", "@metamask/providers": "^22.1.1", - "@nanostores/persistent": "^1.1.0", + "@nanostores/persistent": "^1.3.3", "@nanostores/preact": "^0.5.2", "@nanostores/react": "^0.8.4", "@openzeppelin/contracts": "5.4.0", - "@solana-program/compute-budget": "^0.11.0", + "@solana-program/compute-budget": "^0.12.0", "@solana-program/system": "^0.10.0", "@solana-program/token": "^0.9.0", - "@solana-program/token-2022": "^0.6.1", - "@solana/kit": "^5.0.0", - "@solana/react": "^5.0.0", + "@solana-program/token-2022": "^0.8.0", + "@solana/kit": "^5.5.1", + "@solana/react": "^5.5.1", "@solana/wallet-adapter-base": "^0.9.27", "@solana/wallet-adapter-coinbase": "^0.1.23", "@solana/wallet-adapter-react": "^0.15.39", "@solana/wallet-adapter-react-ui": "^0.9.39", "@solana/wallet-adapter-solflare": "^0.6.32", "@solana/wallet-adapter-trust": "^0.1.17", - "@supabase/supabase-js": "^2.84.0", - "astro": "^5.16.0", + "@supabase/supabase-js": "^2.95.3", + "astro": "^5.17.1", "bignumber.js": "^9.3.1", "bs58": "^6.0.0", "clipboard": "^2.0.11", "dotenv": "^16.6.1", - "ethers": "^6.15.0", - "focus-trap-react": "^11.0.4", + "ethers": "^6.16.0", + "focus-trap-react": "^11.0.6", "github-slugger": "^2.0.0", - "lodash": "^4.17.21", + "lodash": "^4.17.23", "marked": "^15.0.12", "nanostores": "^0.11.4", + "next": "14.2.35", "pino": "^9.14.0", - "preact": "^10.27.2", - "react-instantsearch": "^7.20.0", + "preact": "^10.28.3", + "react-instantsearch": "^7.23.1", "rehype-autolink-headings": "^7.1.0", "rehype-slug": "^6.0.0", "rehype-wrap-all": "^1.1.0", "remark-directive": "^3.0.1", - "swagger-ui-dist": "^5.30.1", - "swagger-ui-react": "^5.30.1", + "swagger-ui-dist": "^5.31.0", + "swagger-ui-react": "^5.31.0", "tweetnacl": "^1.0.3", "uuid": "^11.1.0" }, @@ -118,11 +123,11 @@ "@project-serum/anchor": "^0.26.0", "@rollup/plugin-yaml": "^4.1.2", "@types/jest": "^29.5.14", - "@types/lodash": "^4.17.21", - "@types/node": "^20.19.25", + "@types/lodash": "^4.17.23", + "@types/node": "^20.19.33", "@types/node-fetch": "^2.6.13", "@types/prismjs": "^1.26.5", - "@types/react": "^19.2.7", + "@types/react": "^19.2.13", "@types/react-dom": "^19.2.3", "@types/swagger-ui-dist": "^3.30.6", "@types/swagger-ui-react": "^5.18.0", @@ -133,28 +138,31 @@ "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.32.0", "eslint-plugin-n": "^15.7.0", - "eslint-plugin-prettier": "^5.5.0", + "eslint-plugin-prettier": "^5.5.5", "eslint-plugin-promise": "^6.1.1", "husky": "^9.1.7", "jest-yaml-transform": "^0.2.0", - "knip": "^5.70.1", + "knip": "^5.83.1", "lint-staged": "^15.5.2", "openapi-types": "^12.1.3", - "pino-pretty": "^13.1.2", - "prettier": "^3.5.3", + "pino-pretty": "^13.1.3", + "prettier": "^3.8.1", "prettier-plugin-astro": "^0.14.1", "remark-gfm": "^4.0.0", "remark-mdx": "^3.1.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", - "solhint": "^6.0.1", + "solhint": "^6.0.3", "solhint-plugin-chainlink-solidity": "github:smartcontractkit/chainlink-solhint-rules#v1.3.0", - "ts-jest": "^29.4.5", + "prettier-plugin-solidity": "^1.4.3", + "solhint-plugin-prettier": "^0.1.0", + "tailwindcss": "^3.4.18", + "ts-jest": "^29.4.6", "tsconfig-paths": "^4.2.0", - "tsx": "^4.20.6", + "tsx": "^4.21.0", "typescript": "^5.9.3", "unified": "^11.0.4", - "unist-util-visit": "^5.0.0", + "unist-util-visit": "^5.1.0", "vite": "^6.4.1" }, "lint-staged": { diff --git a/public/api/ccip/v1/openapi.json b/public/api/ccip/v1/openapi.json index 8cf38841257..0be05a9bff9 100644 --- a/public/api/ccip/v1/openapi.json +++ b/public/api/ccip/v1/openapi.json @@ -2,8 +2,8 @@ "openapi": "3.0.0", "info": { "title": "CCIP Docs config API", - "description": "API for retrieving CCIP chain, token, and lane information.\n\nTo get started quickly, you can download our [Postman Collection](/api/ccip/v1/postman-collection.json) which includes all endpoints and example requests.", - "version": "1.5.0", + "description": "API for retrieving CCIP chain, token, lane, and rate limits information.\n\nTo get started quickly, you can download our [Postman Collection](/api/ccip/v1/postman-collection.json) which includes all endpoints and example requests.", + "version": "1.11.0", "contact": { "name": "File issues", "url": "https://github.com/smartcontractkit/documentation/issues/new/choose" @@ -34,7 +34,7 @@ }, { "name": "lanes", - "description": "Cross-chain lane information endpoints" + "description": "Cross-chain lane information endpoints with rate limits" } ], "paths": { @@ -83,17 +83,17 @@ "example": "ethereum-mainnet,bsc-mainnet" }, { - "name": "outputKey", + "name": "output_key", "in": "query", "schema": { "type": "string", - "enum": ["chainId", "selector", "internalId"], - "default": "chainId" + "enum": ["chain_id", "selector", "internal_id"], + "default": "chain_id" }, "description": "Key to use for organizing the response data" }, { - "name": "enrichFeeTokens", + "name": "enrich_fee_tokens", "in": "query", "schema": { "type": "string", @@ -270,12 +270,12 @@ "example": "1,56" }, { - "name": "outputKey", + "name": "output_key", "in": "query", "schema": { "type": "string", - "enum": ["chainId", "selector", "internalId"], - "default": "chainId" + "enum": ["chain_id", "selector", "internal_id"], + "default": "chain_id" }, "description": "Key to use for organizing the response data" } @@ -361,6 +361,275 @@ } } }, + "/tokens/{tokenCanonicalSymbol}": { + "get": { + "tags": ["tokens"], + "summary": "Retrieve detailed token information with custom finality data", + "description": "Returns detailed information about a specific CCIP token, including chain-specific configurations and custom finality settings (minBlockConfirmation and hasCustomFinality).", + "operationId": "getTokenDetail", + "parameters": [ + { + "name": "tokenCanonicalSymbol", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The canonical symbol for the token (e.g., LINK, USDC, BETS)", + "example": "BETS" + }, + { + "name": "environment", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["mainnet", "testnet"] + }, + "description": "The network environment to query" + }, + { + "name": "output_key", + "in": "query", + "schema": { + "type": "string", + "enum": ["chain_id", "selector", "internal_id"], + "default": "chain_id" + }, + "description": "Key to use for organizing the response data by chain" + } + ], + "responses": { + "200": { + "description": "Successful response with token detail data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TokenDetailApiResponse" + }, + "examples": { + "withCustomFinality": { + "summary": "Token with custom finality enabled", + "value": { + "metadata": { + "environment": "mainnet", + "timestamp": "2025-12-10T12:00:00Z", + "requestId": "123e4567-e89b-12d3-a456-426614174000", + "tokenSymbol": "BETS", + "chainCount": 2 + }, + "data": { + "43114": { + "chainId": 43114, + "chainName": "Avalanche", + "decimals": 18, + "destinations": ["1", "137"], + "name": "BetSwirl v2", + "poolAddress": "0xe9d2...9C06", + "poolType": "burnMint", + "symbol": "BETS", + "tokenAddress": "0x9402...E6e5", + "hasCustomFinality": true, + "minBlockConfirmation": 5 + }, + "1": { + "chainId": 1, + "chainName": "Ethereum", + "decimals": 18, + "destinations": ["43114"], + "name": "BetSwirl v2", + "poolAddress": "0x1234...5678", + "poolType": "lockRelease", + "symbol": "BETS", + "tokenAddress": "0xabcd...ef01", + "hasCustomFinality": false, + "minBlockConfirmation": 0 + } + } + } + }, + "unavailable": { + "summary": "Token with unavailable finality data", + "value": { + "metadata": { + "environment": "mainnet", + "timestamp": "2025-12-10T12:00:00Z", + "requestId": "456e7890-e89b-12d3-a456-426614174000", + "tokenSymbol": "USDC", + "chainCount": 1 + }, + "data": { + "1": { + "chainId": 1, + "chainName": "Ethereum", + "decimals": 6, + "destinations": ["43114"], + "name": "USD Coin", + "poolAddress": "0x1234...5678", + "poolType": "burnMint", + "symbol": "USDC", + "tokenAddress": "0xA0b8...c4d2", + "hasCustomFinality": null, + "minBlockConfirmation": null + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid request parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Token not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "error": "NOT_FOUND", + "message": "Token 'INVALID' not found" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/tokens/{tokenCanonicalSymbol}/finality": { + "get": { + "tags": ["tokens"], + "summary": "Retrieve token finality data only", + "description": "Returns only custom finality information (hasCustomFinality and minBlockConfirmation) for a specific token across all chains. This is a lightweight endpoint that returns minimal data for UI components that only need finality status.", + "operationId": "getTokenFinality", + "parameters": [ + { + "name": "tokenCanonicalSymbol", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The canonical symbol for the token (e.g., LINK, USDC, BETS)", + "example": "BETS" + }, + { + "name": "environment", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["mainnet", "testnet"] + }, + "description": "The network environment to query" + }, + { + "name": "output_key", + "in": "query", + "schema": { + "type": "string", + "enum": ["chain_id", "selector", "internal_id"], + "default": "chain_id" + }, + "description": "Key to use for organizing the response data by chain" + } + ], + "responses": { + "200": { + "description": "Successful response with token finality data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TokenFinalityApiResponse" + }, + "examples": { + "mixedFinality": { + "summary": "Token with mixed finality states", + "value": { + "metadata": { + "environment": "mainnet", + "timestamp": "2025-12-10T12:00:00Z", + "requestId": "123e4567-e89b-12d3-a456-426614174000", + "tokenSymbol": "BETS", + "chainCount": 3 + }, + "data": { + "avalanche-mainnet": { + "hasCustomFinality": true, + "minBlockConfirmation": 5 + }, + "ethereum-mainnet": { + "hasCustomFinality": false, + "minBlockConfirmation": 0 + }, + "polygon-mainnet": { + "hasCustomFinality": null, + "minBlockConfirmation": null + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid request parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Token not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "error": "NOT_FOUND", + "message": "Token 'INVALID' not found" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, "/lanes": { "get": { "tags": ["lanes"], @@ -379,7 +648,7 @@ "description": "The network environment to query" }, { - "name": "sourceChainId", + "name": "source_chain_id", "in": "query", "schema": { "type": "string" @@ -388,7 +657,7 @@ "example": "1,56" }, { - "name": "destinationChainId", + "name": "destination_chain_id", "in": "query", "schema": { "type": "string" @@ -397,7 +666,7 @@ "example": "137,42161" }, { - "name": "sourceSelector", + "name": "source_selector", "in": "query", "schema": { "type": "string" @@ -406,7 +675,7 @@ "example": "5009297550715157269" }, { - "name": "destinationSelector", + "name": "destination_selector", "in": "query", "schema": { "type": "string" @@ -415,7 +684,7 @@ "example": "4949039107694359620" }, { - "name": "sourceInternalId", + "name": "source_internal_id", "in": "query", "schema": { "type": "string" @@ -424,7 +693,7 @@ "example": "ethereum-mainnet" }, { - "name": "destinationInternalId", + "name": "destination_internal_id", "in": "query", "schema": { "type": "string" @@ -442,12 +711,12 @@ "example": "1.6.0" }, { - "name": "outputKey", + "name": "output_key", "in": "query", "schema": { "type": "string", - "enum": ["chainId", "selector", "internalId"], - "default": "chainId" + "enum": ["chain_id", "selector", "internal_id"], + "default": "chain_id" }, "description": "Key format to use for organizing the lane keys in the response" } @@ -522,8 +791,500 @@ } } }, - "400": { - "description": "Bad request - invalid parameters", + "400": { + "description": "Bad request - invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/lanes/by-chain-id/{source}/{destination}": { + "get": { + "tags": ["lanes"], + "summary": "Retrieve lane details by chain ID", + "description": "Returns detailed information about a specific CCIP lane identified by source and destination chain IDs", + "operationId": "getLaneByChainId", + "parameters": [ + { + "name": "source", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Source chain ID (e.g., 1 for Ethereum, 56 for BSC)", + "example": "1" + }, + { + "name": "destination", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Destination chain ID", + "example": "43114" + }, + { + "name": "environment", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["mainnet", "testnet"] + }, + "description": "The network environment to query" + } + ], + "responses": { + "200": { + "description": "Successful response with lane details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LaneDetailApiResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Lane not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/lanes/by-chain-id/{source}/{destination}/supported-tokens": { + "get": { + "tags": ["lanes"], + "summary": "Retrieve supported tokens with rate limits by chain ID", + "description": "Returns only the supported tokens and their rate limit configurations for a lane identified by chain IDs", + "operationId": "getSupportedTokensByChainId", + "parameters": [ + { + "name": "source", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Source chain ID", + "example": "1" + }, + { + "name": "destination", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Destination chain ID", + "example": "43114" + }, + { + "name": "environment", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["mainnet", "testnet"] + }, + "description": "The network environment to query" + } + ], + "responses": { + "200": { + "description": "Successful response with supported tokens data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SupportedTokensApiResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Lane not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/lanes/by-selector/{source}/{destination}": { + "get": { + "tags": ["lanes"], + "summary": "Retrieve lane details by CCIP selector", + "description": "Returns detailed information about a specific CCIP lane identified by source and destination CCIP selectors", + "operationId": "getLaneBySelector", + "parameters": [ + { + "name": "source", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Source chain CCIP selector", + "example": "5009297550715157269" + }, + { + "name": "destination", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Destination chain CCIP selector", + "example": "6433500567565415381" + }, + { + "name": "environment", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["mainnet", "testnet"] + }, + "description": "The network environment to query" + } + ], + "responses": { + "200": { + "description": "Successful response with lane details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LaneDetailApiResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Lane not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/lanes/by-selector/{source}/{destination}/supported-tokens": { + "get": { + "tags": ["lanes"], + "summary": "Retrieve supported tokens with rate limits by CCIP selector", + "description": "Returns only the supported tokens and their rate limit configurations for a lane identified by CCIP selectors", + "operationId": "getSupportedTokensBySelector", + "parameters": [ + { + "name": "source", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Source chain CCIP selector", + "example": "5009297550715157269" + }, + { + "name": "destination", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Destination chain CCIP selector", + "example": "6433500567565415381" + }, + { + "name": "environment", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["mainnet", "testnet"] + }, + "description": "The network environment to query" + } + ], + "responses": { + "200": { + "description": "Successful response with supported tokens data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SupportedTokensApiResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Lane not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/lanes/by-internal-id/{source}/{destination}": { + "get": { + "tags": ["lanes"], + "summary": "Retrieve lane details by internal ID", + "description": "Returns detailed information about a specific CCIP lane identified by source and destination internal IDs", + "operationId": "getLaneByInternalId", + "parameters": [ + { + "name": "source", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Source chain internal identifier", + "example": "ethereum-mainnet" + }, + { + "name": "destination", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Destination chain internal identifier", + "example": "avalanche-mainnet" + }, + { + "name": "environment", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["mainnet", "testnet"] + }, + "description": "The network environment to query" + } + ], + "responses": { + "200": { + "description": "Successful response with lane details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LaneDetailApiResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Lane not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/lanes/by-internal-id/{source}/{destination}/supported-tokens": { + "get": { + "tags": ["lanes"], + "summary": "Retrieve supported tokens with rate limits by internal ID", + "description": "Returns only the supported tokens and their rate limit configurations for a lane identified by internal IDs", + "operationId": "getSupportedTokensByInternalId", + "parameters": [ + { + "name": "source", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Source chain internal identifier", + "example": "ethereum-mainnet" + }, + { + "name": "destination", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Destination chain internal identifier", + "example": "avalanche-mainnet" + }, + { + "name": "environment", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["mainnet", "testnet"] + }, + "description": "The network environment to query" + } + ], + "responses": { + "200": { + "description": "Successful response with supported tokens data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SupportedTokensApiResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Lane not found", "content": { "application/json": { "schema": { @@ -920,6 +1681,198 @@ } } }, + "LaneDetailApiResponse": { + "type": "object", + "required": ["metadata", "data"], + "properties": { + "metadata": { + "$ref": "#/components/schemas/LaneDetailMetadata" + }, + "data": { + "$ref": "#/components/schemas/LaneDetailWithRateLimits" + } + }, + "description": "Response for a single lane detail query with rate limits included" + }, + "LaneDetailWithRateLimits": { + "type": "object", + "required": ["sourceChain", "destinationChain", "onRamp", "offRamp", "supportedTokens"], + "properties": { + "sourceChain": { + "$ref": "#/components/schemas/ChainInfo" + }, + "destinationChain": { + "$ref": "#/components/schemas/ChainInfo" + }, + "onRamp": { + "type": "object", + "required": ["address", "version"], + "properties": { + "address": { + "type": "string", + "description": "OnRamp contract address" + }, + "version": { + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$", + "description": "Normalized semantic version of the OnRamp contract" + }, + "enforceOutOfOrder": { + "type": "boolean", + "description": "Whether the OnRamp enforces out-of-order execution" + } + } + }, + "offRamp": { + "type": "object", + "required": ["address", "version"], + "properties": { + "address": { + "type": "string", + "description": "OffRamp contract address" + }, + "version": { + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$", + "description": "Normalized semantic version of the OffRamp contract" + } + } + }, + "supportedTokens": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/TokenRateLimits" + }, + "description": "Supported tokens with their rate limit configurations" + } + }, + "description": "Lane details with rate limits included in supportedTokens" + }, + "TokenRateLimits": { + "type": "object", + "properties": { + "standard": { + "oneOf": [{ "$ref": "#/components/schemas/RateLimiterDirections" }, { "type": "null" }], + "description": "Standard rate limit configuration (null if unavailable)" + }, + "custom": { + "oneOf": [{ "$ref": "#/components/schemas/RateLimiterDirections" }, { "type": "null" }], + "description": "Custom (FTF) rate limit configuration (null if unavailable)" + } + }, + "description": "Rate limit configurations for a token" + }, + "RateLimiterDirections": { + "type": "object", + "properties": { + "in": { + "$ref": "#/components/schemas/RateLimiterConfig" + }, + "out": { + "$ref": "#/components/schemas/RateLimiterConfig" + } + }, + "description": "Inbound and outbound rate limiter configurations" + }, + "RateLimiterConfig": { + "type": "object", + "required": ["capacity", "isEnabled", "rate"], + "properties": { + "capacity": { + "type": "string", + "description": "Maximum capacity in token units (wei for ERC20)" + }, + "isEnabled": { + "type": "boolean", + "description": "Whether the rate limiter is enabled" + }, + "rate": { + "type": "string", + "description": "Refill rate per second in token units" + } + }, + "description": "Single direction rate limiter configuration" + }, + "LaneDetailMetadata": { + "type": "object", + "required": ["environment", "timestamp", "requestId", "sourceChain", "destinationChain"], + "properties": { + "environment": { + "type": "string", + "enum": ["mainnet", "testnet"], + "description": "The network environment" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of the response" + }, + "requestId": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the request" + }, + "sourceChain": { + "type": "string", + "description": "Source chain identifier used in the request" + }, + "destinationChain": { + "type": "string", + "description": "Destination chain identifier used in the request" + } + } + }, + "SupportedTokensApiResponse": { + "type": "object", + "required": ["metadata", "data"], + "properties": { + "metadata": { + "$ref": "#/components/schemas/SupportedTokensMetadata" + }, + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/TokenRateLimits" + }, + "description": "Supported tokens with their rate limit configurations" + } + }, + "description": "Response containing only supported tokens and their rate limits" + }, + "SupportedTokensMetadata": { + "type": "object", + "required": ["environment", "timestamp", "requestId", "sourceChain", "destinationChain", "tokenCount"], + "properties": { + "environment": { + "type": "string", + "enum": ["mainnet", "testnet"], + "description": "The network environment" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of the response" + }, + "requestId": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the request" + }, + "sourceChain": { + "type": "string", + "description": "Source chain identifier used in the request" + }, + "destinationChain": { + "type": "string", + "description": "Destination chain identifier used in the request" + }, + "tokenCount": { + "type": "integer", + "minimum": 0, + "description": "Number of supported tokens returned" + } + } + }, "ErrorResponse": { "type": "object", "required": ["error", "message"], @@ -1046,6 +1999,107 @@ } } }, + "TokenDetailChainData": { + "type": "object", + "description": "Extended token chain data with custom finality information", + "allOf": [ + { + "$ref": "#/components/schemas/TokenChainData" + }, + { + "type": "object", + "properties": { + "hasCustomFinality": { + "type": "boolean", + "nullable": true, + "description": "Whether custom finality is enabled (derived from minBlockConfirmation > 0). Null if data is unavailable." + }, + "minBlockConfirmation": { + "type": "integer", + "nullable": true, + "description": "Minimum block confirmations required. Null if data is unavailable." + } + } + } + ] + }, + "TokenDetailMetadata": { + "type": "object", + "required": ["environment", "timestamp", "requestId", "tokenSymbol", "chainCount"], + "properties": { + "environment": { + "type": "string", + "enum": ["mainnet", "testnet"], + "description": "Network environment" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the response" + }, + "requestId": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for this request" + }, + "tokenSymbol": { + "type": "string", + "description": "Canonical symbol of the requested token" + }, + "chainCount": { + "type": "integer", + "description": "Number of chains this token is available on" + } + } + }, + "TokenDetailApiResponse": { + "type": "object", + "required": ["metadata", "data"], + "properties": { + "metadata": { + "$ref": "#/components/schemas/TokenDetailMetadata" + }, + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/TokenDetailChainData" + }, + "description": "Token data indexed by chain ID/selector, including custom finality information" + } + } + }, + "TokenFinalityData": { + "type": "object", + "description": "Finality data for a token on a specific chain", + "properties": { + "hasCustomFinality": { + "type": "boolean", + "nullable": true, + "description": "Whether custom finality is enabled (derived from minBlockConfirmation > 0). Null if data is unavailable." + }, + "minBlockConfirmation": { + "type": "integer", + "nullable": true, + "description": "Minimum block confirmations required. Null if data is unavailable." + } + } + }, + "TokenFinalityApiResponse": { + "type": "object", + "required": ["metadata", "data"], + "properties": { + "metadata": { + "$ref": "#/components/schemas/TokenDetailMetadata" + }, + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/TokenFinalityData" + }, + "description": "Finality data indexed by chain ID/selector" + } + } + }, "TokenDetails": { "type": "object", "required": ["symbol", "lanes", "chains"], @@ -1120,6 +2174,88 @@ "description": "List of tokens that were ignored due to configuration issues" } } + }, + "RateLimitsMetadata": { + "type": "object", + "required": ["environment", "timestamp", "requestId", "sourceChain", "destinationChain", "tokenCount"], + "properties": { + "environment": { + "type": "string", + "enum": ["mainnet", "testnet"], + "description": "The network environment" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of the response" + }, + "requestId": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the request" + }, + "sourceChain": { + "type": "string", + "description": "Source chain internal identifier" + }, + "destinationChain": { + "type": "string", + "description": "Destination chain internal identifier" + }, + "tokenCount": { + "type": "integer", + "minimum": 0, + "description": "Number of tokens in the response" + } + } + }, + "RateLimiterConfig": { + "type": "object", + "required": ["capacity", "isEnabled", "rate"], + "properties": { + "capacity": { + "type": "string", + "description": "Maximum token capacity for rate limiting (in token smallest unit as string)" + }, + "isEnabled": { + "type": "boolean", + "description": "Whether rate limiting is enabled for this direction" + }, + "rate": { + "type": "string", + "description": "Rate of token replenishment per second (in token smallest unit as string)" + } + } + }, + "TokenRateLimits": { + "type": "object", + "properties": { + "in": { + "$ref": "#/components/schemas/RateLimiterConfig", + "description": "Inbound rate limiter configuration (tokens coming into destination chain)" + }, + "out": { + "$ref": "#/components/schemas/RateLimiterConfig", + "description": "Outbound rate limiter configuration (tokens leaving source chain)" + } + }, + "description": "Rate limiter configurations for both inbound and outbound directions" + }, + "RateLimitsApiResponse": { + "type": "object", + "required": ["metadata", "data"], + "properties": { + "metadata": { + "$ref": "#/components/schemas/RateLimitsMetadata" + }, + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/TokenRateLimits" + }, + "description": "Rate limits data indexed by token symbol" + } + } } } } diff --git a/public/assets/chains/arc.svg b/public/assets/chains/arc.svg new file mode 100644 index 00000000000..f5e0184260d --- /dev/null +++ b/public/assets/chains/arc.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/assets/chains/dogeos.svg b/public/assets/chains/dogeos.svg new file mode 100644 index 00000000000..6ab4d7411d9 --- /dev/null +++ b/public/assets/chains/dogeos.svg @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/chains/morph.svg b/public/assets/chains/morph.svg new file mode 100644 index 00000000000..fed6187a96d --- /dev/null +++ b/public/assets/chains/morph.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/chains/stable.svg b/public/assets/chains/stable.svg new file mode 100644 index 00000000000..f4b2e783bb9 --- /dev/null +++ b/public/assets/chains/stable.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/assets/chains/tempo.svg b/public/assets/chains/tempo.svg new file mode 100644 index 00000000000..cee91482315 --- /dev/null +++ b/public/assets/chains/tempo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/icons/Arrow Right.svg b/public/assets/icons/Arrow Right.svg new file mode 100644 index 00000000000..c73460f5326 --- /dev/null +++ b/public/assets/icons/Arrow Right.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/assets/icons/add.svg b/public/assets/icons/add.svg new file mode 100644 index 00000000000..690aad5bb2f --- /dev/null +++ b/public/assets/icons/add.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/assets/icons/generic-verifier.svg b/public/assets/icons/generic-verifier.svg new file mode 100644 index 00000000000..275f1c8400c --- /dev/null +++ b/public/assets/icons/generic-verifier.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/assets/icons/upper-right-arrow.svg b/public/assets/icons/upper-right-arrow.svg new file mode 100644 index 00000000000..7f588a0dcbd --- /dev/null +++ b/public/assets/icons/upper-right-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/changelog.json b/public/changelog.json index de6336e6eb0..5f5cb2f37fd 100644 --- a/public/changelog.json +++ b/public/changelog.json @@ -24,6 +24,10 @@ "displayName": "Arbitrum", "iconUrl": "https://docs.chain.link/assets/chains/arbitrum.svg" }, + "arc": { + "displayName": "Arc", + "iconUrl": "https://docs.chain.link/assets/chains/arc.svg" + }, "astar": { "displayName": "Astar", "iconUrl": "https://docs.chain.link/assets/chains/astar.svg" @@ -88,6 +92,10 @@ "displayName": "Cronos zkEVM", "iconUrl": "https://docs.chain.link/assets/chains/cronoszkevm.svg" }, + "dogeos": { + "displayName": "DogeOS", + "iconUrl": "https://docs.chain.link/assets/chains/dogeos.svg" + }, "ethereum": { "displayName": "Ethereum", "iconUrl": "https://docs.chain.link/assets/chains/ethereum.svg" @@ -148,6 +156,10 @@ "displayName": "Janction", "iconUrl": "https://docs.chain.link/assets/chains/janction.svg" }, + "jovay": { + "displayName": "Jovay", + "iconUrl": "https://docs.chain.link/assets/chains/jovay.svg" + }, "kaia": { "displayName": "Kaia", "iconUrl": "https://docs.chain.link/assets/chains/kaia.svg" @@ -220,6 +232,10 @@ "displayName": "Moonriver", "iconUrl": "https://docs.chain.link/assets/chains/moonriver.svg" }, + "morph": { + "displayName": "Morph", + "iconUrl": "https://docs.chain.link/assets/chains/morph.svg" + }, "neox": { "displayName": "Neo X", "iconUrl": "https://docs.chain.link/assets/chains/neox.svg" @@ -232,6 +248,10 @@ "displayName": "OP", "iconUrl": "https://docs.chain.link/assets/chains/optimism.svg" }, + "pharos": { + "displayName": "Pharos", + "iconUrl": "https://docs.chain.link/assets/chains/pharos.svg" + }, "plasma": { "displayName": "Plasma", "iconUrl": "https://docs.chain.link/assets/chains/plasma.svg" @@ -284,6 +304,10 @@ "displayName": "Sonic", "iconUrl": "https://docs.chain.link/assets/chains/sonic.svg" }, + "stable": { + "displayName": "Stable", + "iconUrl": "https://docs.chain.link/assets/chains/stable.svg" + }, "starknet": { "displayName": "Starknet", "iconUrl": "https://docs.chain.link/assets/chains/starknet.svg" @@ -304,6 +328,10 @@ "displayName": "Treasure", "iconUrl": "https://docs.chain.link/assets/chains/treasure.svg" }, + "tempo": { + "displayName": "Tempo", + "iconUrl": "https://docs.chain.link/assets/chains/tempo.svg" + }, "tron": { "displayName": "TRON", "iconUrl": "https://docs.chain.link/assets/chains/tron.svg" @@ -342,87 +370,74 @@ } }, "data": [ + { + "category": "release", + "date": "2026-02-11", + "description": "Chainlink introduces Tokenized Equity Feeds, providing continuous 24/5 pricing for tokenized representations of US equities and ETFs across all major trading sessions. Ondo Finance is our first partner, with feeds now available on Ethereum Mainnet. View available feeds and learn more about [Tokenized Equity Feeds](https://docs.chain.link/data-feeds/tokenized-equity-feeds).", + "title": "Tokenized Equity Feeds Launch with Ondo Finance", + "topic": "Data Feeds" + }, { "category": "integration", - "date": "2025-11-25", - "description": "Chainlink CCIP expands support to new blockchains:", + "date": "2026-02-10", + "description": "Chainlink CCIP expands support to new testnets:", "newNetworks": [ { - "displayName": "Pharos Atlantic Testnet", - "network": "pharos", - "url": "https://docs.chain.link/ccip/directory/testnet/chain/pharos-atlantic-testnet" + "displayName": "Arc Network Testnet", + "network": "arc", + "url": "https://docs.chain.link/ccip/directory/testnet/chain/arc-testnet" + }, + { + "displayName": "DogeOS Chikyu Testnet", + "network": "dogeos", + "url": "https://docs.chain.link/ccip/directory/testnet/chain/dogeos-testnet-chikyu" } ], - "relatedNetworks": ["pharos"], - "title": "CCIP Expands to Pharos Atlantic Testnet", + "relatedNetworks": ["arc", "dogeos"], + "title": "CCIP on Arc Network Testnet and DogeOS Chikyu Testnet", "topic": "CCIP" }, { - "category": "integration", - "date": "2025-11-24", - "description": "Chainlink Data Streams is available for Monad Mainnet. The verifier proxy addresses and stream IDs are available on the [Stream Addresses](https://docs.chain.link/data-streams/crypto-streams) page.", - "relatedNetworks": ["monad"], - "title": "Data Streams Expands to Monad Mainnet", - "topic": "Data Streams" + "category": "release", + "date": "2026-02-09", + "description": "CRE CLI version 1.0.10 is now available. This release fixes secret injection for the Confidential HTTP capability in the simulator — template placeholders now resolve correctly during simulation.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.9...v1.0.10)", + "title": "CRE CLI v1.0.10", + "topic": "CRE" }, { "category": "integration", - "date": "2025-11-24", - "description": "Chainlink Data Feeds is available on Monad Mainnet. View the available price feed information on the [Price Feed Addresses](https://docs.chain.link/data-feeds/price-feeds/addresses?network=monad&page=1) page.", - "relatedNetworks": ["monad"], - "title": "Data Feeds Expands to Monad Mainnet", + "date": "2026-02-09", + "description": "Chainlink Data Feeds is available on MegaETH Mainnet. View the available price feed information on the [Price Feed Addresses](https://docs.chain.link/data-feeds/price-feeds/addresses?network=megaeth&page=1) page.", + "relatedNetworks": ["megaeth"], + "title": "Data Feeds Expands to MegaETH Mainnet", "topic": "Data Feeds" }, { "category": "integration", - "date": "2025-11-24", - "description": "Chainlink CCIP expands support to new blockchains:", - "newNetworks": [ - { - "displayName": "Henesys Mainnet", - "network": "nexon", - "url": "https://docs.chain.link/ccip/directory/mainnet/chain/nexon-mainnet-henesys" - }, - { - "displayName": "Monad Mainnet", - "network": "monad", - "url": "https://docs.chain.link/ccip/directory/mainnet/chain/monad-mainnet" - } - ], - "relatedNetworks": ["henesys", "monad"], - "title": "CCIP on Nexon Mainnet and Monad Mainnet", - "topic": "CCIP" + "date": "2026-02-09", + "description": "Chainlink Data Streams is available for MegaETH Mainnet. The verifier proxy addresses and stream IDs are available on the [Stream Addresses](https://docs.chain.link/data-streams/crypto-streams) page.", + "relatedNetworks": ["megaeth"], + "title": "Data Streams Expands to MegaETH Mainnet", + "topic": "Data Streams" }, { "category": "integration", - "date": "2025-11-23", - "description": "Newly supported tokens: BOB, WHLP, wstETH", - "relatedTokens": [ - { - "assetName": "BOB", - "baseAsset": "BOB", - "url": "https://docs.chain.link/ccip/directory/mainnet/token/BOB", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bob.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" - }, - { - "assetName": "Wrapped HLP", - "baseAsset": "WHLP", - "url": "https://docs.chain.link/ccip/directory/mainnet/token/WHLP", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/whlp.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" - }, + "date": "2026-02-09", + "description": "Chainlink CCIP expands support to MegaETH Mainnet:", + "newNetworks": [ { - "assetName": "Wrapped stETH", - "baseAsset": "wstETH", - "url": "https://docs.chain.link/ccip/directory/mainnet/token/wstETH", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wsteth.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + "displayName": "MegaETH Mainnet", + "network": "megaeth", + "url": "https://docs.chain.link/ccip/directory/mainnet/chain/megaeth-mainnet" } ], - "title": "Cross-chain token (CCT) standard: Added support for new tokens", + "relatedNetworks": ["megaeth"], + "title": "CCIP on MegaETH Mainnet", "topic": "CCIP" }, { "category": "integration", - "date": "2025-11-23", + "date": "2026-02-08", "description": "New Data Streams available on all [supported networks](https://docs.chain.link/data-streams/crypto-streams):", "relatedNetworks": [ "0g", @@ -452,9 +467,11 @@ "linea", "mantle", "metis", + "monad", "opbnb", "optimism", "polygon", + "pharos", "plasma", "ronin", "scroll", @@ -470,32 +487,88 @@ ], "relatedTokens": [ { - "assetName": "sUSDu / USDU Exchange Rate", - "baseAsset": "sUSDu ", - "quoteAsset": "USDU", - "url": "https://data.chain.link/streams/susdu%20-usdu-exchangerate-streams", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susdu.webp" + "assetName": "AUSD", + "baseAsset": "AUSD", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/ausd-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ausd.webp" }, { - "assetName": "Unit Bitcoin", - "baseAsset": "UBTC", + "assetName": "Avalanche Bridged BTC", + "baseAsset": "BTC.B", "quoteAsset": "USD", - "url": "https://data.chain.link/streams/ubtc-usd", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ubtc.webp" + "url": "https://data.chain.link/streams/btc.b-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btc.b.webp" }, { - "assetName": "Unit Ethereum", - "baseAsset": "UETH", + "assetName": "Euro Coin", + "baseAsset": "EURC", "quoteAsset": "USD", - "url": "https://data.chain.link/streams/ueth-usd", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ueth.webp" + "url": "https://data.chain.link/streams/eurc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eurc.webp" }, { - "assetName": "Unit Solana", - "baseAsset": "USOL", + "assetName": "FBTC / BTC Exchange Rate", + "baseAsset": "FBTC", + "quoteAsset": "BTC", + "url": "https://docs.chain.link/data-streams/exchange-rate-streams?search=FBTC&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/fbtc.webp" + }, + { + "assetName": "Lighter", + "baseAsset": "LIT", "quoteAsset": "USD", - "url": "https://data.chain.link/streams/usol-usd", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usol.webp" + "url": "https://data.chain.link/streams/lit-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/lit.webp" + }, + { + "assetName": "Meteora", + "baseAsset": "MET", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/met-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/met.webp" + }, + { + "assetName": "OpenEden", + "baseAsset": "EDEN", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/eden-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eden.webp" + }, + { + "assetName": "Resolv", + "baseAsset": "RESOLV", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/resolv-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/resolv.webp" + }, + { + "assetName": "The White Whale", + "baseAsset": "WHITEWHALE", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/whitewhale-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/whitewhale.webp" + }, + { + "assetName": "TRY", + "baseAsset": "TRY", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/try-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/try.webp" + }, + { + "assetName": "Turtle", + "baseAsset": "TURTLE", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/turtle-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/turtle.webp" + }, + { + "assetName": "USDM", + "baseAsset": "USDM", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/usdm-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdm.webp" } ], "title": "Added support to Data Streams", @@ -503,85 +576,2301 @@ }, { "category": "integration", - "date": "2025-11-23", + "date": "2026-02-08", "description": "New Data Feeds available:", - "relatedNetworks": ["optimism", "ethereum", "base", "bnb-chain"], + "relatedNetworks": ["megaeth", "avalanche"], "relatedTokens": [ { - "assetName": "sUSDai", - "baseAsset": "sUSDai", - "quoteAsset": "USDai", - "network": "base", - "url": "https://data.chain.link/feeds/base/base/susdai-usdai-exchange-rate", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susdai.webp" + "assetName": "Copper", + "baseAsset": "XCU", + "quoteAsset": "USD", + "network": "avalanche", + "url": "https://data.chain.link/feeds/avalanche/mainnet/xcu-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/xcu.webp" }, { - "assetName": "sUSDD / USDD Exchange Rate", - "baseAsset": "sUSDD", - "quoteAsset": "USDD", - "network": "ethereum", - "url": "https://data.chain.link/feeds/ethereum/mainnet/susdd-usdd-exchange-rate", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susdd.webp" + "assetName": "GLV [AVAX-USDC]", + "baseAsset": "GLV", + "quoteAsset": "USD", + "network": "avalanche", + "url": "https://data.chain.link/feeds/avalanche/mainnet/glv-%5Bavax-usdc%5D-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/glv.webp" }, { - "assetName": "sUSDD / USDD Exchange Rate", - "baseAsset": "sUSDD", - "quoteAsset": "USDD", + "assetName": "Mountain Protocol USD", + "baseAsset": "USDM", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH&page=1&search=USDM", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdm.webp" + }, + { + "assetName": "Splashing Staked SEI", + "baseAsset": "SPSEI", + "quoteAsset": "SEI", + "network": "avalanche", + "url": "https://data.chain.link/feeds/avalanche/mainnet/spsei-sei-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/spsei.webp" + }, + { + "assetName": "WSRUSD / RUSD Exchange Rate", + "baseAsset": "WSRUSD", + "quoteAsset": "RUSD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH&search=WSR&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wsrusd.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "release", + "date": "2026-02-06", + "description": "CRE CLI version 1.0.9 is now available. This release adds experimental [Confidential HTTP](https://docs.chain.link/cre/capabilities/confidential-http) capability support in the simulator, allowing you to simulate workflows with privacy-preserving API calls.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.8...v1.0.9)", + "title": "CRE CLI v1.0.9", + "topic": "CRE" + }, + { + "category": "release", + "date": "2026-02-06", + "description": "CRE CLI version 1.0.8 is now available. This release changes `chain-id` to `chain-selector` in simulator settings, adds support for longer workflow names, and fixes a logic bug in the template contract MessageEmitter.sol.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.7...v1.0.8)", + "title": "CRE CLI v1.0.8", + "topic": "CRE" + }, + { + "category": "release", + "date": "2026-02-02", + "description": "We have updated the Selecting Quality Data Feeds guide to include risk level indicators for Custom Feeds, stablecoin-specific considerations, and clarified developer responsibilities across all feed categories. [Learn more](https://docs.chain.link/data-feeds/selecting-data-feeds).", + "title": "Updated Selecting Quality Data Feeds Guide", + "topic": "Data Feeds" + }, + { + "category": "deprecation", + "date": "2026-02-02", + "description": "Support for select Data Stream feeds have been deprecated due to a lack of active users. Check [the list of Deprecating Data Streams to learn more](https://docs.chain.link/data-streams/deprecating-streams).\n\n**Note:** Teams interested in re-enabling a deprecated Data Stream feed (or requesting a new one) can [reach out to discuss requirements, expected usage, and deployment timelines](https://chain.link/contact).", + "title": "Deprecated Data Stream Feeds", + "topic": "Data Streams" + }, + { + "category": "integration", + "date": "2026-02-01", + "description": "New Data Feeds available:", + "relatedNetworks": ["bnb-chain", "hyperevm", "celo"], + "relatedTokens": [ + { + "assetName": "Aave", + "baseAsset": "AAVE", + "quoteAsset": "USD", "network": "bnb-chain", - "url": "https://data.chain.link/feeds/bsc/mainnet/susdd-usdd-exchange-rate", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susdd.webp" + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&search=aave&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/aave.webp" }, { - "assetName": "USDai", - "baseAsset": "USDAI", + "assetName": "BEHYPE", + "baseAsset": "BEHYPE", + "quoteAsset": "HYPE", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=behype&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/behype.webp" + }, + { + "assetName": "Bitcoin", + "baseAsset": "BTC", "quoteAsset": "USD", - "network": "base", - "url": "https://data.chain.link/feeds/base/base/usdai-usd", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdai.webp" + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btc.webp" }, { - "assetName": "USDD / USDC Exchange Rate", - "baseAsset": "USDD", - "quoteAsset": "USDC", - "network": "ethereum", - "url": "https://data.chain.link/feeds/ethereum/mainnet/usdd-usdc-exchange-rate", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp" + "assetName": "Bitcoin", + "baseAsset": "BTC", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btc.webp" }, { - "assetName": "USDD / USDC Exchange Rate", - "baseAsset": "USDD", - "quoteAsset": "USDC", + "assetName": "Bitcoin", + "baseAsset": "BTC", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=BTC&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btc.webp" + }, + { + "assetName": "Bitcoin Cash", + "baseAsset": "BCH", + "quoteAsset": "USD", "network": "bnb-chain", - "url": "https://data.chain.link/feeds/bsc/mainnet/usdd-usdc-exchange-rate", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp" + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bch.webp" }, { - "assetName": "USDD / USDT Exchange Rate", - "baseAsset": "USDD", - "quoteAsset": "USDT", - "network": "ethereum", - "url": "https://data.chain.link/feeds/ethereum/mainnet/usdd-usdt-exchange-rate", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp" + "assetName": "BNB", + "baseAsset": "BNB", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bnb.webp" }, { - "assetName": "USDD / USDT Exchange Rate", - "baseAsset": "USDD", - "quoteAsset": "USDT", + "assetName": "BNB", + "baseAsset": "BNB", + "quoteAsset": "USD", "network": "bnb-chain", - "url": "https://data.chain.link/feeds/bsc/mainnet/usdd-usdt-exchange-rate", - "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp" - } - ], - "title": "Added support to Data Feeds", - "topic": "Data Feeds" - }, - { + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bnb.webp" + }, + { + "assetName": "Cardano", + "baseAsset": "ADA", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ada.webp" + }, + { + "assetName": "Chainlink", + "baseAsset": "LINK", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/link.webp" + }, + { + "assetName": "Circle USD", + "baseAsset": "USDC", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdc.webp" + }, + { + "assetName": "Circle USD", + "baseAsset": "USDC", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdc.webp" + }, + { + "assetName": "Circle USD", + "baseAsset": "USDC", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=USDC&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdc.webp" + }, + { + "assetName": "DAI", + "baseAsset": "DAI", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/dai.webp" + }, + { + "assetName": "Dogecoin", + "baseAsset": "DOGE", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/doge.webp" + }, + { + "assetName": "Ethena Staked USDe", + "baseAsset": "SUSDE", + "quoteAsset": "USDE", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susde.webp" + }, + { + "assetName": "Ethena USDe", + "baseAsset": "USDE", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usde.webp" + }, + { + "assetName": "Ethena USDe", + "baseAsset": "USDE", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=Ethena+USDe&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usde.webp" + }, + { + "assetName": "Ethereum", + "baseAsset": "ETH", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eth.webp" + }, + { + "assetName": "Ethereum", + "baseAsset": "ETH", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eth.webp" + }, + { + "assetName": "Ethereum", + "baseAsset": "ETH", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=ETH&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eth.webp" + }, + { + "assetName": "Filecoin", + "baseAsset": "FIL", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/fil.webp" + }, + { + "assetName": "First Digital USD", + "baseAsset": "FDUSD", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/fdusd.webp" + }, + { + "assetName": "Hyperliquid", + "baseAsset": "HYPE", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://data.chain.link/feeds/hyperliquid/hyperliquid/hype-usd-shared-svr", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/hype.webp" + }, + { + "assetName": "KHYPE", + "baseAsset": "KHYPE", + "quoteAsset": "HYPE", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=HYPE&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/khype.webp" + }, + { + "assetName": "Kinetiq Staked HYPE", + "baseAsset": "KHYPE", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=KHYPE&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/khype.webp" + }, + { + "assetName": "Litecoin", + "baseAsset": "LTC", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ltc.webp" + }, + { + "assetName": "PancakeSwap", + "baseAsset": "CAKE", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/cake.webp" + }, + { + "assetName": "Solana", + "baseAsset": "SOL", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sol.webp" + }, + { + "assetName": "Solana", + "baseAsset": "SOL", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=SOL&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sol.webp" + }, + { + "assetName": "Solv Protocol Staked BTC", + "baseAsset": "xSolvBTC", + "quoteAsset": "SolvBTC", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/xsolvbtc.webp" + }, + { + "assetName": "stCELO / CELO Exchange Rate", + "baseAsset": "stCELO", + "quoteAsset": "CELO", + "network": "celo", + "url": "https://data.chain.link/feeds/celo/mainnet/stcelo-celo-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/stcelo.webp" + }, + { + "assetName": "Tether Gold", + "baseAsset": "XAUT", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=XAUT&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/xaut.webp" + }, + { + "assetName": "Tether USD", + "baseAsset": "USDT", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdt.webp" + }, + { + "assetName": "Tether USD", + "baseAsset": "USDT", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdt.webp" + }, + { + "assetName": "Tether USD", + "baseAsset": "USDT", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=USDT&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdt.webp" + }, + { + "assetName": "Theo Short Duration US Treasury Fund", + "baseAsset": "THBILL", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=THBILL&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/thbill.webp" + }, + { + "assetName": "Tron", + "baseAsset": "TRX", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/trx.webp" + }, + { + "assetName": "True USD", + "baseAsset": "TUSD", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/tusd.webp" + }, + { + "assetName": "Trust Wallet Token", + "baseAsset": "TWT", + "quoteAsset": "BNB", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/twt.webp" + }, + { + "assetName": "Uniswap", + "baseAsset": "UNI", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/uni.webp" + }, + { + "assetName": "Unit Bitcoin", + "baseAsset": "UBTC", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=UBTC&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ubtc.webp" + }, + { + "assetName": "Unit Solana", + "baseAsset": "USOL", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=USOL&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usol.webp" + }, + { + "assetName": "United Stables", + "baseAsset": "U", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/u.webp" + }, + { + "assetName": "USDH", + "baseAsset": "USDH", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=USDH&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdh.webp" + }, + { + "assetName": "Venus", + "baseAsset": "XVS", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/xvs.webp" + }, + { + "assetName": "World Liberty Financial USD", + "baseAsset": "USD1", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usd1.webp" + }, + { + "assetName": "wstETH / stETH Exchange Rate", + "baseAsset": "wstETH", + "quoteAsset": "stETH", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wsteth.webp" + }, + { + "assetName": "WSTHYPE / STHYPE Exchange Rate", + "baseAsset": "WSTHYPE", + "quoteAsset": "STHYPE", + "network": "hyperevm", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=hyperevm&search=WSTHYPE&showSvr=true&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wsthype.webp" + }, + { + "assetName": "XRP", + "baseAsset": "XRP", + "quoteAsset": "USD", + "network": "bnb-chain", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=bnb-chain&showSvr=true", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/xrp.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "integration", + "date": "2026-01-29", + "description": "CRE now supports additional testnets for workflow simulation: Apechain Curtis, Arc Testnet, Hyperliquid Testnet, Ink Sepolia, Jovay Testnet, Linea Sepolia, Plasma Testnet, and World Chain Sepolia.\n\n**Required versions:** CLI v1.0.7+, Go SDK v1.1.4+, TS SDK v1.0.7+\n\nSee the [Supported Networks](https://docs.chain.link/cre/supported-networks) page for chain names and version requirements.", + "relatedNetworks": ["apechain", "arc", "hyperliquid", "ink", "jovay", "linea", "plasma", "worldchain"], + "title": "CRE Expands Testnet Support", + "topic": "CRE" + }, + { + "category": "release", + "date": "2026-01-29", + "description": "CRE CLI version 1.0.7 is now available with internal improvements and updates to the bundled TypeScript SDK (now v1.0.7).\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.6...v1.0.7)", + "title": "CRE CLI v1.0.7", + "topic": "CRE" + }, + { + "category": "release", + "date": "2026-01-29", + "description": "TypeScript SDK version 1.0.7 is now available with internal improvements.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.5...v1.0.7)", + "title": "CRE TS SDK v1.0.7", + "topic": "CRE" + }, + { + "category": "release", + "date": "2026-01-28", + "description": "TypeScript SDK version 1.0.5 fixes an issue with `runtime.now()` returning incorrect timestamps. See [Time in CRE](https://docs.chain.link/cre/concepts/time-in-cre) for usage details.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.4...v1.0.5)", + "title": "CRE TS SDK v1.0.5", + "topic": "CRE" + }, + { + "category": "integration", + "date": "2026-01-27", + "description": "Chainlink Data Streams is available for Pharos Mainnet and Testnet. The verifier proxy addresses and stream IDs are available on the [Stream Addresses](https://docs.chain.link/data-streams/crypto-streams) page.", + "relatedNetworks": ["pharos"], + "title": "Data Streams Expands to Pharos Mainnet and Testnet", + "topic": "Data Streams" + }, + { + "category": "integration", + "date": "2026-01-26", + "description": "CRE now supports ZKSync Era mainnet and testnet for workflow simulation and production deployment.\n\n**Required versions:** CLI v1.0.6+, Go SDK v1.1.3+ (mainnet) / v1.1.2+ (testnet), TS SDK v1.0.7+\n\nSee the [Supported Networks](https://docs.chain.link/cre/supported-networks) page for chain names and version requirements.", + "relatedNetworks": ["zksync"], + "title": "CRE Expands to ZKSync Era", + "topic": "CRE" + }, + { + "category": "release", + "date": "2026-01-26", + "description": "TypeScript SDK version 1.0.4 is now available with internal improvements.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.3...v1.0.4)", + "title": "CRE TS SDK v1.0.4", + "topic": "CRE" + }, + { + "category": "integration", + "date": "2026-01-25", + "description": "New Data Streams available on all [supported networks](https://docs.chain.link/data-streams/crypto-streams):", + "relatedNetworks": [ + "0g", + "apechain", + "aptos", + "arbitrum", + "avalanche", + "base", + "berachain", + "bitlayer", + "blast", + "bnb-chain", + "bob", + "botanix", + "celo", + "ethereum", + "gnosis-chain", + "gravity", + "hashkey", + "hedera", + "hyperliquid", + "injective", + "ink", + "jovay", + "katana", + "lens", + "linea", + "mantle", + "metis", + "monad", + "opbnb", + "optimism", + "polygon", + "plasma", + "ronin", + "scroll", + "shibarium", + "sei", + "soneium", + "sonic", + "solana", + "taiko", + "unichain", + "worldchain", + "zksync" + ], + "relatedTokens": [ + { + "assetName": "AbbVie Inc", + "baseAsset": "ABBV", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/abbv-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/abbv.webp" + }, + { + "assetName": "Alphabet Inc - A", + "baseAsset": "GOOGL", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/googl-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/googl.webp" + }, + { + "assetName": "Amazon.com Inc", + "baseAsset": "AMZN", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/amzn-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/amzn.webp" + }, + { + "assetName": "Apple Inc", + "baseAsset": "AAPL", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/aapl-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/aapl.webp" + }, + { + "assetName": "Bitmine Immersion Technologies", + "baseAsset": "BMNR", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/bmnr-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bmnr.webp" + }, + { + "assetName": "BOB (Build on Bitcoin)", + "baseAsset": "BOB", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/bob-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bob.webp" + }, + { + "assetName": "CBTC Proof of Reserves", + "baseAsset": "CBTC", + "quoteAsset": "POR", + "url": "https://data.chain.link/streams/cbtc-por", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/cbtc.webp" + }, + { + "assetName": "Circle Internet Group Inc", + "baseAsset": "CRCL", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/crcl-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/crcl.webp" + }, + { + "assetName": "Coinbase Global Inc", + "baseAsset": "COIN", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/coin-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/coin.webp" + }, + { + "assetName": "Degen (Base)", + "baseAsset": "DEGEN", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/degen-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/degen.webp" + }, + { + "assetName": "Invesco QQQ Trust Series 1 ETF", + "baseAsset": "QQQ", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/qqq-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/qqq.webp" + }, + { + "assetName": "Merck & Co Inc", + "baseAsset": "MRK", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/mrk-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/mrk.webp" + }, + { + "assetName": "Meta Platforms Inc", + "baseAsset": "META", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/meta-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/meta.webp" + }, + { + "assetName": "Metamask USD", + "baseAsset": "MUSD", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/musd-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/musd.webp" + }, + { + "assetName": "Microsoft Corp", + "baseAsset": "MSFT", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/msft-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/msft.webp" + }, + { + "assetName": "Microstrategy Inc Class A", + "baseAsset": "MSTR", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/mstr-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/mstr.webp" + }, + { + "assetName": "NVIDIA Corp", + "baseAsset": "NVDA", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/nvda-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/nvda.webp" + }, + { + "assetName": "Oracle Corp", + "baseAsset": "ORCL", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/orcl-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/orcl.webp" + }, + { + "assetName": "Palantir Technologies Inc", + "baseAsset": "PLTR", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/pltr-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/pltr.webp" + }, + { + "assetName": "Robinhood Markets Inc", + "baseAsset": "HOOD", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/hood-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/hood.webp" + }, + { + "assetName": "SPDR S&P 500 ETF", + "baseAsset": "SPY", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/spy-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/spy.webp" + }, + { + "assetName": "Superstate Crypto Carry Fund", + "baseAsset": "USCC", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/uscc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/uscc.webp" + }, + { + "assetName": "Superstate Short Duration U.S. Government Securities Fund", + "baseAsset": "USTB", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/ustb-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ustb.webp" + }, + { + "assetName": "Tesla Inc", + "baseAsset": "TSLA", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/tsla-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/tsla.webp" + }, + { + "assetName": "UnitedHealth Group Inc", + "baseAsset": "UNH", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/unh-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/unh.webp" + }, + { + "assetName": "USDT0", + "baseAsset": "USDT0", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/usdt0-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdt0.webp" + }, + { + "assetName": "USDtb", + "baseAsset": "USDTB", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/usdtb-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdtb.webp" + } + ], + "title": "Added support to Data Streams", + "topic": "Data Streams" + }, + { + "category": "release", + "date": "2026-01-21", + "description": "CRE CLI version 1.0.6 is now available. This release adds ZKSync Era testnet and mainnet support in the simulator, along with various small improvements and bug fixes.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.", + "title": "CRE CLI v1.0.6", + "topic": "CRE" + }, + { + "category": "release", + "date": "2026-01-20", + "description": "Chainlink 24/5 U.S. Equities Streams provide real-time equity pricing data across all major U.S. single-name equities and ETFs spanning regular, pre-market, post-market, and overnight trading sessions.\n\nEach instrument is exposed through three distinct streams for different trading phases: Regular Hours, Extended Hours, and Overnight Hours. Users can dynamically switch between these streams to construct a continuous price feed.\n\n- Complete user guide: [24/5 US Equities User Guide](https://docs.chain.link/data-streams/rwa-streams/24-5-us-equities-user-guide)\n- View available streams: [Stream Table Viewer](https://docs.chain.link/data-streams/stream-ids?network=arbitrum&show24x5=true)\n- Report schema: [RWA Advanced (v11)](https://docs.chain.link/data-streams/reference/report-schema-v11)", + "title": "24/5 US Equities Streams Now Available", + "topic": "Data Streams" + }, + { + "category": "release", + "date": "2026-01-19", + "description": "TypeScript SDK version 1.0.3 is now available. This release fixes an issue where workflows could execute twice during simulation. All workflow examples in the SDK repository now use direct imports.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.2...v1.0.3)", + "title": "CRE TS SDK v1.0.3", + "topic": "CRE" + }, + { + "category": "integration", + "date": "2026-01-18", + "description": "New Data Streams available on all [supported networks](https://docs.chain.link/data-streams/crypto-streams):", + "relatedNetworks": [ + "0g", + "apechain", + "aptos", + "arbitrum", + "avalanche", + "base", + "berachain", + "bitlayer", + "blast", + "bnb-chain", + "bob", + "botanix", + "celo", + "ethereum", + "gnosis-chain", + "gravity", + "hashkey", + "hedera", + "hyperliquid", + "injective", + "ink", + "jovay", + "katana", + "lens", + "linea", + "mantle", + "metis", + "monad", + "opbnb", + "optimism", + "polygon", + "plasma", + "ronin", + "scroll", + "shibarium", + "sei", + "soneium", + "sonic", + "solana", + "taiko", + "unichain", + "worldchain", + "zksync" + ], + "relatedTokens": [ + { + "assetName": "Canton", + "baseAsset": "CC", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/cc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/cc.webp" + }, + { + "assetName": "cUSDO / USDO Exchange Rate", + "baseAsset": "cUSDO", + "quoteAsset": "USDO", + "url": "https://docs.chain.link/data-streams/crypto-streams?search=cUSDO%2FUSDO&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/cusdo.webp" + }, + { + "assetName": "kmHYPE / HYPE Exchange Rate", + "baseAsset": "kmHYPE", + "quoteAsset": "HYPE", + "url": "https://docs.chain.link/data-streams/crypto-streams?search=kmHYPE&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/kmhype.webp" + }, + { + "assetName": "Tea-REX", + "baseAsset": "TREX", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/trex-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/trex.webp" + }, + { + "assetName": "wstETH / stETH Exchange Rate", + "baseAsset": "wstETH", + "quoteAsset": "stETH", + "url": "https://docs.chain.link/data-streams/crypto-streams?search=wstETH%2FstETH&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wsteth.webp" + } + ], + "title": "Added support to Data Streams", + "topic": "Data Streams" + }, + { + "category": "integration", + "date": "2026-01-18", + "description": "New SmartData Feeds available:", + "relatedNetworks": ["ethereum"], + "relatedTokens": [ + { + "assetName": "Bitcoin (BTC)", + "baseAsset": "LBTC", + "network": "ethereum", + "productTypeCode": "PoR", + "url": "https://data.chain.link/feeds/ethereum/mainnet/lombard-por", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/lbtc.webp" + } + ], + "title": "Added support to SmartData", + "topic": "SmartData" + }, + { + "category": "integration", + "date": "2026-01-18", + "description": "New Data Feeds available:", + "relatedNetworks": ["base", "megaeth", "arbitrum"], + "relatedTokens": [ + { + "assetName": "Anzen USDz", + "baseAsset": "USDz", + "quoteAsset": "USD", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/usdz-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdz.webp" + }, + { + "assetName": "Avalanche Bridged BTC", + "baseAsset": "BTCB", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btcb.webp" + }, + { + "assetName": "Bitcoin", + "baseAsset": "BTC", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btc.webp" + }, + { + "assetName": "Circle USD", + "baseAsset": "USDC", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdc.webp" + }, + { + "assetName": "Ethena Staked USDe", + "baseAsset": "SUSDE", + "quoteAsset": "USDE", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susde.webp" + }, + { + "assetName": "Ethena USDe", + "baseAsset": "USDE", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usde.webp" + }, + { + "assetName": "Ethereum", + "baseAsset": "ETH", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eth.webp" + }, + { + "assetName": "Hyperliquid", + "baseAsset": "HYPE", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/hype.webp" + }, + { + "assetName": "Kelp DAO Restaked ETH", + "baseAsset": "RSETH", + "quoteAsset": "ETH", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rseth.webp" + }, + { + "assetName": "lBTC-BTC Exchange Rate", + "baseAsset": "lBTC", + "quoteAsset": "BTC", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/lbtc.webp" + }, + { + "assetName": "Lombard Staked BTC", + "baseAsset": "LBTC", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/lbtc.webp" + }, + { + "assetName": "MetaMask USD", + "baseAsset": "MUSD", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/musd.webp" + }, + { + "assetName": "PayPal USD", + "baseAsset": "PYUSD", + "quoteAsset": "USD", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/pyusd-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/pyusd.webp" + }, + { + "assetName": "Renzo Restaked ETH", + "baseAsset": "EZETH", + "quoteAsset": "ETH", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ezeth.webp" + }, + { + "assetName": "Solana", + "baseAsset": "SOL", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sol.webp" + }, + { + "assetName": "STCAPUSD / CAPUSD Exchange Rate", + "baseAsset": "STCAPUSD", + "quoteAsset": "CAPUSD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/stcapusd.webp" + }, + { + "assetName": "Tether USD", + "baseAsset": "USDT", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdt.webp" + }, + { + "assetName": "USD+", + "baseAsset": "USD+", + "quoteAsset": "USD", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/usd+-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usd+.webp" + }, + { + "assetName": "USDT0", + "baseAsset": "USDT0", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdt0.webp" + }, + { + "assetName": "USDtb", + "baseAsset": "USDtb", + "quoteAsset": "USD", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdtb.webp" + }, + { + "assetName": "wstETH / stETH Exchange Rate", + "baseAsset": "wstETH", + "quoteAsset": "stETH", + "network": "megaeth", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=MegaETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wsteth.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "integration", + "date": "2026-01-18", + "description": "Newly supported tokens: BGB, PTjrUSDe, PTsrUSDe", + "relatedTokens": [ + { + "assetName": "BitgetToken", + "baseAsset": "BGB", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/BGB", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bgb.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "PT Strata Junior USDe 2APR2026", + "baseAsset": "PTjrUSDe", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/PTjrUSDe", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ptjrusde.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "PT Strata Senior USDe 2APR2026", + "baseAsset": "PTsrUSDe", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/PTsrUSDe", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ptsrusde.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + } + ], + "title": "Cross-chain token (CCT) standard: Added support for new tokens", + "topic": "CCIP" + }, + { + "category": "release", + "date": "2026-01-16", + "description": "TypeScript SDK version 1.0.2 is now available with improved developer experience: optional `main()` call, automatic error handling, and direct imports for SDK components. Both import styles remain supported for backward compatibility.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.1...v1.0.2)", + "title": "CRE TS SDK v1.0.2", + "topic": "CRE" + }, + { + "category": "deprecation", + "date": "2026-01-15", + "description": "Support for Data Feeds on Ronin will be deprecated on **February 16th, 2026**. A complete list of Data Feeds designated for deprecation along with their corresponding shutdown dates can be found [here](https://docs.chain.link/data-feeds/deprecating-feeds).", + "title": "Deprecated Ronin Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "release", + "date": "2026-01-13", + "description": "CRE CLI version 1.0.5 is now available with various small improvements and bug fixes.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.", + "title": "CRE CLI v1.0.5", + "topic": "CRE" + }, + { + "category": "integration", + "date": "2026-01-11", + "description": "New Data Feeds available:", + "relatedNetworks": ["bob", "ethereum", "mantle"], + "relatedTokens": [ + { + "assetName": "BOB (Build on Bitcoin)", + "baseAsset": "BOB", + "quoteAsset": "USD", + "network": "bob", + "url": "https://data.chain.link/feeds/bob/mainnet/bob-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bob.webp" + }, + { + "assetName": "Ethena USDtb", + "baseAsset": "USDtb", + "quoteAsset": "USD", + "network": "ethereum", + "url": "https://data.chain.link/feeds/ethereum/mainnet/usdtb-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdtb.webp" + }, + { + "assetName": "Kelp DAO Restaked ETH", + "baseAsset": "RSETH", + "quoteAsset": "ETH", + "network": "mantle", + "url": "https://data.chain.link/feeds/mantle/mantle/rseth-eth-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rseth.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "release", + "date": "2026-01-09", + "description": "CRE CLI version 1.0.4 is now available with various small improvements and bug fixes.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.", + "title": "CRE CLI v1.0.4", + "topic": "CRE" + }, + { + "category": "release", + "date": "2026-01-07", + "description": "We've introduced a new [Very High Market Risk](https://docs.chain.link/data-feeds/selecting-data-feeds#-very-high-market-risk-feeds) category across Chainlink documentation pages and data.chain.link to better distinguish data feeds that are subject to extreme market risk beyond the existing High Market Risk classification. These feeds may reflect assets undergoing significant market events, severe liquidity constraints, or deprecation.\n\nTo improve transparency and consistency, feeds are no longer hidden based on risk level. All feeds are now visible and clearly labeled, allowing developers to make [informed decisions](https://docs.chain.link/data-feeds/selecting-data-feeds#overview) using more granular risk classifications.", + "title": "New risk category and improved feed visibility", + "topic": "Data Feeds" + }, + { + "category": "integration", + "date": "2026-01-04", + "description": "New Data Feeds available:", + "relatedNetworks": ["polygon"], + "relatedTokens": [ + { + "assetName": "Indonesian Rupiah", + "baseAsset": "IDR", + "quoteAsset": "USD", + "network": "polygon", + "url": "https://data.chain.link/feeds/polygon/mainnet/idr-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/idr.webp" + }, + { + "assetName": "South African Rand", + "baseAsset": "ZAR", + "quoteAsset": "USD", + "network": "polygon", + "url": "https://data.chain.link/feeds/polygon/mainnet/zar-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/zar.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "release", + "date": "2025-12-29", + "description": "The Data Streams Candlestick API now offers a new [`/groups` endpoint](https://docs.chain.link/data-streams/reference/candlestick-api#get-list-of-supported-groups) that returns a list of all supported symbol types (crypto, equities, forex, equity) which can be used as a filter in the `/symbol_info` endpoint. Additionally, the `/history` and `/history/rows` endpoints now support [user-specified resolutions](https://docs.chain.link/data-streams/reference/candlestick-api#supported-resolutions) with flexible time units (minutes, hours, days, weeks, months, years).", + "title": "Candlestick API: Groups endpoint and user resolution support", + "topic": "Data Streams" + }, + { + "category": "integration", + "date": "2025-12-21", + "description": "Newly supported tokens: QUICK, RAIN, aprMON", + "relatedTokens": [ + { + "assetName": "QuickSwap", + "baseAsset": "QUICK", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/QUICK", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/quick.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "Rain Coin", + "baseAsset": "RAIN", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/RAIN", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rain.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "aPriori LST", + "baseAsset": "aprMON", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/aprMON", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/aprmon.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + } + ], + "title": "Cross-chain token (CCT) standard: Added support for new tokens", + "topic": "CCIP" + }, + { + "category": "integration", + "date": "2025-12-21", + "description": "New SmartData Feeds available:", + "relatedNetworks": ["polygon"], + "relatedTokens": [ + { + "assetName": "R25 rcUSD+", + "baseAsset": "rcUSD+", + "network": "polygon", + "productTypeCode": "NAV", + "url": "https://data.chain.link/feeds/polygon/mainnet/rcusd+-nav", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rcusd+.webp" + } + ], + "title": "Added support to SmartData", + "topic": "SmartData" + }, + { + "category": "integration", + "date": "2025-12-21", + "description": "New Data Feeds available:", + "relatedNetworks": ["polygon", "base", "arbitrum", "hyperevm"], + "relatedTokens": [ + { + "assetName": "Bitcoin", + "baseAsset": "BTC", + "quoteAsset": "USD", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/btc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btc.webp" + }, + { + "assetName": "Circle EUR", + "baseAsset": "EURC", + "quoteAsset": "USD", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/eurc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eurc.webp" + }, + { + "assetName": "Circle USD", + "baseAsset": "USDC", + "quoteAsset": "USD", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/usdc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdc.webp" + }, + { + "assetName": "Circle USD", + "baseAsset": "USDC", + "quoteAsset": "USD", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/usdc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdc.webp" + }, + { + "assetName": "Ethereum", + "baseAsset": "ETH", + "quoteAsset": "USD", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/eth-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eth.webp" + }, + { + "assetName": "Tether USD", + "baseAsset": "USDT", + "quoteAsset": "USD", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/usdt-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdt.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "integration", + "date": "2025-12-19", + "description": "Chainlink CCIP expands support to new blockchains:", + "newNetworks": [ + { + "displayName": "Ethereum Hoodi", + "network": "ethereum", + "url": "https://docs.chain.link/ccip/directory/testnet/chain/ethereum-testnet-hoodi" + } + ], + "relatedNetworks": ["ethereum"], + "title": "CCIP Expands to Ethereum Hoodi", + "topic": "CCIP" + }, + { + "category": "deprecation", + "date": "2025-12-16", + "description": "Support for Data Feeds on Fantom will be deprecated on **January 12th, 2026**. A complete list of Data Feeds designated for deprecation along with their corresponding shutdown dates can be found [here](https://docs.chain.link/data-feeds/deprecating-feeds).", + "title": "Deprecated Fantom Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "integration", + "date": "2025-12-14", + "description": "Newly supported tokens: BTC.b, JCT, KNET, POWER, PTsUSDE, SWCH, avBTC, avBTCx, avUSD, avUSDx, pippin", + "relatedTokens": [ + { + "assetName": "Bitcoin", + "baseAsset": "BTC.b", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/BTC.b", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btcb.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "JANCTION", + "baseAsset": "JCT", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/JCT", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/jct.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "Kingnet AI", + "baseAsset": "KNET", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/KNET", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/knet.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "Power", + "baseAsset": "POWER", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/POWER", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/power.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "PT Ethena sUSDE 5FEB2026", + "baseAsset": "PTsUSDE", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/PTsUSDE", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ptsusde.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "SwissCheese Token", + "baseAsset": "SWCH", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/SWCH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/swch.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "avBTC", + "baseAsset": "avBTC", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/avBTC", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/avbtc.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "avBTC MAX", + "baseAsset": "avBTCx", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/avBTCx", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/avbtcx.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "avUSD", + "baseAsset": "avUSD", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/avUSD", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/avusd.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "avUSD MAX", + "baseAsset": "avUSDx", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/avUSDx", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/avusdx.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "Pippin", + "baseAsset": "pippin", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/pippin", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/pippin.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + } + ], + "title": "Cross-chain token (CCT) standard: Added support for new tokens", + "topic": "CCIP" + }, + { + "category": "integration", + "date": "2025-12-14", + "description": "New SmartData Feeds available:", + "relatedNetworks": ["optimism", "bnb-chain"], + "relatedTokens": [ + { + "assetName": "Virtune Polkadot ETP / PoR", + "baseAsset": "DOT", + "network": "optimism", + "productTypeCode": "PoR", + "url": "https://data.chain.link/feeds/optimism/mainnet/virtune-dot-etp-por", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/dot.webp" + }, + { + "assetName": "Virtune Stellar ETP / PoR", + "baseAsset": "XLM", + "network": "optimism", + "productTypeCode": "PoR", + "url": "https://data.chain.link/feeds/optimism/mainnet/virtune-xlm-etp-por", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/xlm.webp" + }, + { + "assetName": "WisdomTree Bloomberg U.S. Dollar Bullish Fund", + "baseAsset": "USDU", + "network": "bnb-chain", + "productTypeCode": "PoR", + "url": "https://data.chain.link/feeds/bsc/mainnet/usdu-por", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdu.webp" + } + ], + "title": "Added support to SmartData", + "topic": "SmartData" + }, + { + "category": "integration", + "date": "2025-12-14", + "description": "New Data Feeds available:", + "relatedNetworks": [ + "polygon", + "optimism", + "arbitrum", + "ethereum", + "hyperevm", + "solana", + "metis", + "base", + "sonic", + "bnb-chain" + ], + "relatedTokens": [ + { + "assetName": "Arbitrum", + "baseAsset": "ARB", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/arb-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/arb.webp" + }, + { + "assetName": "Avant Staked BTC", + "baseAsset": "savBTC", + "quoteAsset": "avBTC", + "network": "ethereum", + "url": "https://data.chain.link/feeds/ethereum/mainnet/savbtc-avbtc-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/savbtc.webp" + }, + { + "assetName": "Avant Staked USD", + "baseAsset": "savUSD", + "quoteAsset": "avUSD", + "network": "ethereum", + "url": "https://data.chain.link/feeds/ethereum/mainnet/savusd-avusd-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/savusd.webp" + }, + { + "assetName": "Bitcoin", + "baseAsset": "BTC", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/btc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btc.webp" + }, + { + "assetName": "Chainlink", + "baseAsset": "LINK", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/link-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/link.webp" + }, + { + "assetName": "Circle EUR", + "baseAsset": "EURC", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/eurc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eurc.webp" + }, + { + "assetName": "DAI", + "baseAsset": "DAI", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/dai-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/dai.webp" + }, + { + "assetName": "Ethereum", + "baseAsset": "ETH", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/eth-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eth.webp" + }, + { + "assetName": "Felix feUSD", + "baseAsset": "FEUSD", + "quoteAsset": "USD", + "network": "hyperevm", + "url": "https://data.chain.link/feeds/hyperliquid/hyperliquid/feusd-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/feusd.webp" + }, + { + "assetName": "FRAX", + "baseAsset": "FRAX", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/frax-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/frax.webp" + }, + { + "assetName": "Jupiter", + "baseAsset": "JUP", + "quoteAsset": "USD", + "network": "solana", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=solana&search=Jupiter&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/jup.webp" + }, + { + "assetName": "Jupiter Perpetuals Liquidity Provider Token", + "baseAsset": "JLP", + "quoteAsset": "USD", + "network": "solana", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=solana&search=Jupiter+Perpetuals&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/jlp.webp" + }, + { + "assetName": "Liquity USD", + "baseAsset": "LUSD", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/lusd-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/lusd.webp" + }, + { + "assetName": "Solv Protocol SolvBTC / BTC Exchange Rate", + "baseAsset": "solvBTC", + "quoteAsset": "BTC", + "network": "solana", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=solana&search=Solv+Protocol+SolvBTC&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/solvbtc.webp" + }, + { + "assetName": "South African Rand", + "baseAsset": "ZAR", + "quoteAsset": "USD", + "network": "sonic", + "url": "https://data.chain.link/feeds/sonic/sonic/zar-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/zar.webp" + }, + { + "assetName": "syrupUSDT-USDT Exchange Rate", + "baseAsset": "syrupUSDT", + "quoteAsset": "USDT", + "network": "bnb-chain", + "url": "https://data.chain.link/feeds/bsc/mainnet/syrupusdt-usdt-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/syrupusdt.webp" + }, + { + "assetName": "Tether USD", + "baseAsset": "USDT", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/usdt-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdt.webp" + }, + { + "assetName": "Wrapped Bitcoin", + "baseAsset": "WBTC", + "quoteAsset": "USD", + "network": "solana", + "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?network=solana&search=WBTC&page=1", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wbtc.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "integration", + "date": "2025-12-12", + "description": "Chainlink CCIP expands support to new blockchains:", + "newNetworks": [ + { + "displayName": "Tempo Testnet", + "network": "tempo", + "url": "https://docs.chain.link/ccip/directory/testnet/chain/tempo-testnet" + } + ], + "relatedNetworks": ["tempo"], + "title": "CCIP Expands to Tempo Testnet", + "topic": "CCIP" + }, + { + "category": "release", + "date": "2025-12-12", + "description": "CRE CLI version 1.0.3 is now available with various small improvements and bug fixes.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.", + "title": "CRE CLI v1.0.3", + "topic": "CRE" + }, + { + "category": "release", + "date": "2025-12-11", + "description": "Chainlink Node v2.31.0 is now available. See the [Release Notes](https://github.com/smartcontractkit/chainlink/releases/tag/v2.31.0) for details.", + "title": "Chainlink Node v2.31.0", + "topic": "Nodes" + }, + { + "category": "release", + "date": "2025-12-11", + "description": "Upgraded Time-based Upkeeps. Read more [here](https://docs.chain.link/chainlink-automation/guides/job-scheduler)", + "title": "Upgraded Time-based Upkeeps ", + "topic": "Automation" + }, + { + "category": "integration", + "date": "2025-12-09", + "description": "Chainlink CCIP expands support to new blockchains:", + "newNetworks": [ + { + "displayName": "Morph Hoodi Testnet", + "network": "morph", + "url": "https://docs.chain.link/ccip/directory/testnet/chain/ethereum-testnet-hoodi-morph" + } + ], + "relatedNetworks": ["morph"], + "title": "CCIP Expands to Morph Hoodi Testnet", + "topic": "CCIP" + }, + { + "category": "integration", + "date": "2025-12-08", + "description": "Chainlink CCIP expands support to new blockchains:", + "newNetworks": [ + { + "displayName": "Jovay Mainnet", + "network": "jovay", + "url": "https://docs.chain.link/ccip/directory/mainnet/chain/jovay-mainnet" + }, + { + "displayName": "Jovay Testnet", + "network": "jovay", + "url": "https://docs.chain.link/ccip/directory/testnet/chain/jovay-testnet" + }, + { + "displayName": "Morph Mainnet", + "network": "morph", + "url": "https://docs.chain.link/ccip/directory/mainnet/chain/morph-mainnet" + }, + { + "displayName": "Stable Mainnet", + "network": "stable", + "url": "https://docs.chain.link/ccip/directory/mainnet/chain/stable-mainnet" + } + ], + "relatedNetworks": ["jovay", "morph", "stable"], + "title": "CCIP Expands to Jovay Mainnet & Testnet, Morph Mainnet, Stable Mainnet", + "topic": "CCIP" + }, + { + "category": "integration", + "date": "2025-12-07", + "description": "New Data Streams available on all [supported networks](https://docs.chain.link/data-streams/crypto-streams):", + "relatedNetworks": [ + "0g", + "apechain", + "aptos", + "arbitrum", + "avalanche", + "base", + "berachain", + "bitlayer", + "blast", + "bnb-chain", + "bob", + "botanix", + "celo", + "ethereum", + "gnosis-chain", + "gravity", + "hashkey", + "hedera", + "hyperliquid", + "injective", + "ink", + "jovay", + "katana", + "lens", + "linea", + "mantle", + "metis", + "monad", + "opbnb", + "optimism", + "polygon", + "plasma", + "ronin", + "scroll", + "shibarium", + "sei", + "soneium", + "sonic", + "solana", + "taiko", + "unichain", + "worldchain", + "zksync" + ], + "relatedTokens": [ + { + "assetName": "PLTR", + "baseAsset": "PLTR", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/pltr-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/pltr.webp" + }, + { + "assetName": "SOLVBTC / BTC Exchange Rate", + "baseAsset": "SOLVBTC", + "quoteAsset": "BTC", + "url": "https://data.chain.link/streams/solvbtc-btc", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/solvbtc.webp" + } + ], + "title": "Added support to Data Streams", + "topic": "Data Streams" + }, + { + "category": "integration", + "date": "2025-12-07", + "description": "New SmartData Feeds available:", + "relatedNetworks": ["base"], + "relatedTokens": [ + { + "assetName": "ARSx", + "baseAsset": "ARSx", + "network": "base", + "productTypeCode": "PoR", + "url": "https://data.chain.link/feeds/base/base/arsx-base-por", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/arsx.webp" + } + ], + "title": "Added support to SmartData", + "topic": "SmartData" + }, + { + "category": "integration", + "date": "2025-12-07", + "description": "New Data Feeds available:", + "relatedNetworks": ["arbitrum", "optimism", "ethereum", "mantle", "base"], + "relatedTokens": [ + { + "assetName": "Aave", + "baseAsset": "AAVE", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/aave-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/aave.webp" + }, + { + "assetName": "Arbitrum", + "baseAsset": "ARB", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/arb-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/arb.webp" + }, + { + "assetName": "Bitcoin", + "baseAsset": "BTC", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/btc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btc.webp" + }, + { + "assetName": "Calculated ETH+", + "baseAsset": "ETH+", + "quoteAsset": "USD", + "network": "ethereum", + "url": "https://data.chain.link/feeds/ethereum/mainnet/calculated-ethplus-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eth+.webp" + }, + { + "assetName": "Chainlink", + "baseAsset": "LINK", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/link-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/link.webp" + }, + { + "assetName": "Circle EUR", + "baseAsset": "EURC", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/eurc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eurc.webp" + }, + { + "assetName": "Circle USD", + "baseAsset": "USDC", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/usdc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdc.webp" + }, + { + "assetName": "Compounding OpenDollar", + "baseAsset": "CUSDO", + "quoteAsset": "USD", + "network": "ethereum", + "url": "https://data.chain.link/feeds/ethereum/mainnet/cusdo-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/cusdo.webp" + }, + { + "assetName": "DAI", + "baseAsset": "DAI", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/dai-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/dai.webp" + }, + { + "assetName": "Ethena Staked USDe", + "baseAsset": "SUSDE", + "quoteAsset": "USDE", + "network": "mantle", + "url": "https://data.chain.link/feeds/mantle/mantle/susde-usde-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susde.webp" + }, + { + "assetName": "FRAX", + "baseAsset": "FRAX", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/frax-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/frax.webp" + }, + { + "assetName": "GHO", + "baseAsset": "GHO", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/gho-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/gho.webp" + }, + { + "assetName": "Kelp DAO Restaked ETH", + "baseAsset": "RSETH", + "quoteAsset": "ETH (SVR)", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/rseth-eth-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rseth.webp" + }, + { + "assetName": "Liquity USD", + "baseAsset": "LUSD", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/lusd-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/lusd.webp" + }, + { + "assetName": "syrupUSDC-USDC Exchange Rate", + "baseAsset": "syrupUSDC", + "quoteAsset": "USDC", + "network": "mantle", + "url": "https://data.chain.link/feeds/mantle/mantle/syrupusdc-usdc-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/syrupusdc.webp" + }, + { + "assetName": "syrupUSDT-USDT Exchange Rate", + "baseAsset": "syrupUSDT", + "quoteAsset": "USDT", + "network": "mantle", + "url": "https://data.chain.link/feeds/mantle/mantle/syrupusdt-usdt-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/syrupusdt.webp" + }, + { + "assetName": "Tether USD", + "baseAsset": "USDT", + "quoteAsset": "USD (SVR)", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/usdt-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdt.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "integration", + "date": "2025-11-30", + "description": "Newly supported tokens: VOOI", + "relatedTokens": [ + { + "assetName": "VOOI", + "baseAsset": "VOOI", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/VOOI", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/vooi.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + } + ], + "title": "Cross-chain token (CCT) standard: Added support for new tokens", + "topic": "CCIP" + }, + { + "category": "integration", + "date": "2025-11-30", + "description": "New Data Streams available on all [supported networks](https://docs.chain.link/data-streams/crypto-streams):", + "relatedNetworks": [ + "0g", + "apechain", + "aptos", + "arbitrum", + "avalanche", + "base", + "berachain", + "bitlayer", + "blast", + "bnb-chain", + "bob", + "botanix", + "celo", + "ethereum", + "gnosis-chain", + "gravity", + "hashkey", + "hedera", + "hyperliquid", + "injective", + "ink", + "jovay", + "katana", + "lens", + "linea", + "mantle", + "metis", + "monad", + "opbnb", + "optimism", + "polygon", + "plasma", + "ronin", + "scroll", + "shibarium", + "sei", + "soneium", + "sonic", + "solana", + "taiko", + "unichain", + "worldchain", + "zksync" + ], + "relatedTokens": [ + { + "assetName": "Monad", + "baseAsset": "MON", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/mon-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/mon.webp" + } + ], + "title": "Added support to Data Streams", + "topic": "Data Streams" + }, + { + "category": "integration", + "date": "2025-11-30", + "description": "New SmartData Feeds available:", + "relatedNetworks": ["linea"], + "relatedTokens": [ + { + "assetName": "M", + "baseAsset": "MN", + "network": "linea", + "productTypeCode": "NAV", + "url": "https://data.chain.link/feeds/linea/mainnet/m-nav-linea", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/mn.webp" + } + ], + "title": "Added support to SmartData", + "topic": "SmartData" + }, + { + "category": "integration", + "date": "2025-11-30", + "description": "New Data Feeds available:", + "relatedNetworks": ["linea", "ethereum"], + "relatedTokens": [ + { + "assetName": "Avant Staked ETH", + "baseAsset": "savETH", + "quoteAsset": "avETH", + "network": "linea", + "url": "https://data.chain.link/feeds/linea/mainnet/saveth-aveth-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/saveth.webp" + }, + { + "assetName": "Monad", + "baseAsset": "MON", + "quoteAsset": "USD", + "network": "arbitrum", + "url": "https://data.chain.link/feeds/arbitrum/mainnet/mon-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/mon.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { + "category": "integration", + "date": "2025-11-25", + "description": "Chainlink CCIP expands support to new blockchains:", + "newNetworks": [ + { + "displayName": "Pharos Atlantic Testnet", + "network": "pharos", + "url": "https://docs.chain.link/ccip/directory/testnet/chain/pharos-atlantic-testnet" + } + ], + "relatedNetworks": ["pharos"], + "title": "CCIP Expands to Pharos Atlantic Testnet", + "topic": "CCIP" + }, + { + "category": "integration", + "date": "2025-11-24", + "description": "Chainlink Data Streams is available for Monad Mainnet. The verifier proxy addresses and stream IDs are available on the [Stream Addresses](https://docs.chain.link/data-streams/crypto-streams) page.", + "relatedNetworks": ["monad"], + "title": "Data Streams Expands to Monad Mainnet", + "topic": "Data Streams" + }, + { + "category": "integration", + "date": "2025-11-24", + "description": "Chainlink Data Feeds is available on Monad Mainnet. View the available price feed information on the [Price Feed Addresses](https://docs.chain.link/data-feeds/price-feeds/addresses?network=monad&page=1) page.", + "relatedNetworks": ["monad"], + "title": "Data Feeds Expands to Monad Mainnet", + "topic": "Data Feeds" + }, + { + "category": "integration", + "date": "2025-11-24", + "description": "Chainlink CCIP expands support to new blockchains:", + "newNetworks": [ + { + "displayName": "Henesys Mainnet", + "network": "nexon", + "url": "https://docs.chain.link/ccip/directory/mainnet/chain/nexon-mainnet-henesys" + }, + { + "displayName": "Monad Mainnet", + "network": "monad", + "url": "https://docs.chain.link/ccip/directory/mainnet/chain/monad-mainnet" + } + ], + "relatedNetworks": ["henesys", "monad"], + "title": "CCIP on Nexon Mainnet and Monad Mainnet", + "topic": "CCIP" + }, + { + "category": "integration", + "date": "2025-11-23", + "description": "Newly supported tokens: BOB, WHLP, wstETH", + "relatedTokens": [ + { + "assetName": "BOB", + "baseAsset": "BOB", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/BOB", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bob.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "Wrapped HLP", + "baseAsset": "WHLP", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/WHLP", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/whlp.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + }, + { + "assetName": "Wrapped stETH", + "baseAsset": "wstETH", + "url": "https://docs.chain.link/ccip/directory/mainnet/token/wstETH", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wsteth.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover" + } + ], + "title": "Cross-chain token (CCT) standard: Added support for new tokens", + "topic": "CCIP" + }, + { + "category": "integration", + "date": "2025-11-23", + "description": "New Data Streams available on all [supported networks](https://docs.chain.link/data-streams/crypto-streams):", + "relatedNetworks": [ + "0g", + "apechain", + "aptos", + "arbitrum", + "avalanche", + "base", + "berachain", + "bitlayer", + "blast", + "bnb-chain", + "bob", + "botanix", + "celo", + "ethereum", + "gnosis-chain", + "gravity", + "hashkey", + "hedera", + "hyperliquid", + "injective", + "ink", + "jovay", + "katana", + "lens", + "linea", + "mantle", + "metis", + "opbnb", + "optimism", + "polygon", + "plasma", + "ronin", + "scroll", + "shibarium", + "sei", + "soneium", + "sonic", + "solana", + "taiko", + "unichain", + "worldchain", + "zksync" + ], + "relatedTokens": [ + { + "assetName": "sUSDu / USDU Exchange Rate", + "baseAsset": "sUSDu ", + "quoteAsset": "USDU", + "url": "https://data.chain.link/streams/susdu%20-usdu-exchangerate-streams", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susdu.webp" + }, + { + "assetName": "Unit Bitcoin", + "baseAsset": "UBTC", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/ubtc-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ubtc.webp" + }, + { + "assetName": "Unit Ethereum", + "baseAsset": "UETH", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/ueth-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ueth.webp" + }, + { + "assetName": "Unit Solana", + "baseAsset": "USOL", + "quoteAsset": "USD", + "url": "https://data.chain.link/streams/usol-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usol.webp" + } + ], + "title": "Added support to Data Streams", + "topic": "Data Streams" + }, + { + "category": "integration", + "date": "2025-11-23", + "description": "New Data Feeds available:", + "relatedNetworks": ["optimism", "ethereum", "base", "bnb-chain"], + "relatedTokens": [ + { + "assetName": "sUSDai", + "baseAsset": "sUSDai", + "quoteAsset": "USDai", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/susdai-usdai-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susdai.webp" + }, + { + "assetName": "sUSDD / USDD Exchange Rate", + "baseAsset": "sUSDD", + "quoteAsset": "USDD", + "network": "ethereum", + "url": "https://data.chain.link/feeds/ethereum/mainnet/susdd-usdd-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susdd.webp" + }, + { + "assetName": "sUSDD / USDD Exchange Rate", + "baseAsset": "sUSDD", + "quoteAsset": "USDD", + "network": "bnb-chain", + "url": "https://data.chain.link/feeds/bsc/mainnet/susdd-usdd-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susdd.webp" + }, + { + "assetName": "USDai", + "baseAsset": "USDAI", + "quoteAsset": "USD", + "network": "base", + "url": "https://data.chain.link/feeds/base/base/usdai-usd", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdai.webp" + }, + { + "assetName": "USDD / USDC Exchange Rate", + "baseAsset": "USDD", + "quoteAsset": "USDC", + "network": "ethereum", + "url": "https://data.chain.link/feeds/ethereum/mainnet/usdd-usdc-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp" + }, + { + "assetName": "USDD / USDC Exchange Rate", + "baseAsset": "USDD", + "quoteAsset": "USDC", + "network": "bnb-chain", + "url": "https://data.chain.link/feeds/bsc/mainnet/usdd-usdc-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp" + }, + { + "assetName": "USDD / USDT Exchange Rate", + "baseAsset": "USDD", + "quoteAsset": "USDT", + "network": "ethereum", + "url": "https://data.chain.link/feeds/ethereum/mainnet/usdd-usdt-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp" + }, + { + "assetName": "USDD / USDT Exchange Rate", + "baseAsset": "USDD", + "quoteAsset": "USDT", + "network": "bnb-chain", + "url": "https://data.chain.link/feeds/bsc/mainnet/usdd-usdt-exchange-rate", + "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp" + } + ], + "title": "Added support to Data Feeds", + "topic": "Data Feeds" + }, + { "category": "release", "date": "2025-11-20", "description": "CRE CLI version 1.0.2 is now available with various improvements based on user feedback.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.", "title": "CRE CLI v1.0.2", "topic": "CRE" }, + { + "category": "release", + "date": "2025-11-17", + "description": "Chainlink Node v2.30.0 is now available. See the [Release Notes](https://github.com/smartcontractkit/chainlink/releases/tag/v2.30.0) for details.", + "title": "Chainlink Node v2.30.0", + "topic": "Nodes" + }, { "category": "integration", "date": "2025-11-16", @@ -5100,7 +7389,7 @@ { "category": "release", "date": "2025-08-18", - "description": "Backed xStock streams are now available on mainnet and testnet.\n\n- Backed xStock streams use the [V10 report schema](https://docs.chain.link/data-streams/reference/report-schema-v10).\n- Verifier proxy addresses and Backed xStock stream IDs are available on the [Stream Addresses](https://docs.chain.link/data-streams/backed-streams) page.", + "description": "Backed xStock streams are now available on mainnet and testnet.\n\n- Backed xStock streams use the [V10 report schema](https://docs.chain.link/data-streams/reference/report-schema-v10).\n- Verifier proxy addresses and Backed xStock stream IDs are available on the [Stream Addresses](https://docs.chain.link/data-streams/tokenized-asset-streams) page.", "title": "Backed xStock streams", "topic": "Data Streams" }, diff --git a/public/images/architecture.png b/public/images/architecture.png new file mode 100644 index 00000000000..076b0418e4f Binary files /dev/null and b/public/images/architecture.png differ diff --git a/public/images/ccip-logo.svg b/public/images/ccip-logo.svg new file mode 100644 index 00000000000..79f05e8a605 --- /dev/null +++ b/public/images/ccip-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/ccip/ccip-hero-bg.png b/public/images/ccip/ccip-hero-bg.png new file mode 100644 index 00000000000..5f3bc5df559 Binary files /dev/null and b/public/images/ccip/ccip-hero-bg.png differ diff --git a/public/images/ccip/ccip-hero.png b/public/images/ccip/ccip-hero.png new file mode 100644 index 00000000000..306b8cb3ed3 Binary files /dev/null and b/public/images/ccip/ccip-hero.png differ diff --git a/public/images/ccip/ccip-hl-v1.7.jpg b/public/images/ccip/ccip-hl-v1.7.jpg new file mode 100644 index 00000000000..b7c06d09c68 Binary files /dev/null and b/public/images/ccip/ccip-hl-v1.7.jpg differ diff --git a/public/images/ccip/tutorials/ccip-getting-started-evm-1.png b/public/images/ccip/tutorials/ccip-getting-started-evm-1.png new file mode 100644 index 00000000000..f3c0edf6016 Binary files /dev/null and b/public/images/ccip/tutorials/ccip-getting-started-evm-1.png differ diff --git a/public/images/ccip/tutorials/ccip-getting-started-evm-2.png b/public/images/ccip/tutorials/ccip-getting-started-evm-2.png new file mode 100644 index 00000000000..6f561bbcd16 Binary files /dev/null and b/public/images/ccip/tutorials/ccip-getting-started-evm-2.png differ diff --git a/public/images/certification/Imagedevhubresources.png b/public/images/certification/Imagedevhubresources.png new file mode 100644 index 00000000000..fb41186977b Binary files /dev/null and b/public/images/certification/Imagedevhubresources.png differ diff --git a/public/images/certification/Imagedevhubvideo.png b/public/images/certification/Imagedevhubvideo.png new file mode 100644 index 00000000000..259ea7d8d4f Binary files /dev/null and b/public/images/certification/Imagedevhubvideo.png differ diff --git a/public/images/certification/Tailless--Arrow-Down.svg b/public/images/certification/Tailless--Arrow-Down.svg new file mode 100644 index 00000000000..2a3ca0873aa --- /dev/null +++ b/public/images/certification/Tailless--Arrow-Down.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/certification/image-1.png b/public/images/certification/image-1.png new file mode 100644 index 00000000000..850eff21ee0 Binary files /dev/null and b/public/images/certification/image-1.png differ diff --git a/public/images/certification/image-200.png b/public/images/certification/image-200.png new file mode 100644 index 00000000000..dcf069cc5e1 Binary files /dev/null and b/public/images/certification/image-200.png differ diff --git a/public/images/certification/image-201.png b/public/images/certification/image-201.png new file mode 100644 index 00000000000..5975fc2082d Binary files /dev/null and b/public/images/certification/image-201.png differ diff --git a/public/images/certification/image-certificate.svg b/public/images/certification/image-certificate.svg new file mode 100644 index 00000000000..6ba2805de44 --- /dev/null +++ b/public/images/certification/image-certificate.svg @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/certification/image-learnings.svg b/public/images/certification/image-learnings.svg new file mode 100644 index 00000000000..4d6df7915c3 --- /dev/null +++ b/public/images/certification/image-learnings.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/code-sample.png b/public/images/code-sample.png new file mode 100644 index 00000000000..89aa34475df Binary files /dev/null and b/public/images/code-sample.png differ diff --git a/public/images/data-feed/tokenized-equity/ondo-tokenized-equity-pause-behavior.png b/public/images/data-feed/tokenized-equity/ondo-tokenized-equity-pause-behavior.png new file mode 100644 index 00000000000..f30bab19be5 Binary files /dev/null and b/public/images/data-feed/tokenized-equity/ondo-tokenized-equity-pause-behavior.png differ diff --git a/public/images/data-feed/tokenized-equity/tokenized-equity-diagram.png b/public/images/data-feed/tokenized-equity/tokenized-equity-diagram.png new file mode 100644 index 00000000000..38342db23ef Binary files /dev/null and b/public/images/data-feed/tokenized-equity/tokenized-equity-diagram.png differ diff --git a/public/images/data-streams/24-5-availability.png b/public/images/data-streams/24-5-availability.png new file mode 100644 index 00000000000..01298dcbe27 Binary files /dev/null and b/public/images/data-streams/24-5-availability.png differ diff --git a/public/images/data-streams/24-5-price-jumps-example.png b/public/images/data-streams/24-5-price-jumps-example.png new file mode 100644 index 00000000000..d38453ea31e Binary files /dev/null and b/public/images/data-streams/24-5-price-jumps-example.png differ diff --git a/public/images/data-streams/calculated-streams-diagram.png b/public/images/data-streams/calculated-streams-diagram.png new file mode 100644 index 00000000000..64b02149cde Binary files /dev/null and b/public/images/data-streams/calculated-streams-diagram.png differ diff --git a/public/images/demos/Demos thumbnails 1.png b/public/images/demos/Demos thumbnails 1.png new file mode 100644 index 00000000000..ac2841680bd Binary files /dev/null and b/public/images/demos/Demos thumbnails 1.png differ diff --git a/public/images/demos/Demos thumbnails 2.png b/public/images/demos/Demos thumbnails 2.png new file mode 100644 index 00000000000..a5b86705672 Binary files /dev/null and b/public/images/demos/Demos thumbnails 2.png differ diff --git a/public/images/demos/Demos thumbnails 3.png b/public/images/demos/Demos thumbnails 3.png new file mode 100644 index 00000000000..ab5a48f2b63 Binary files /dev/null and b/public/images/demos/Demos thumbnails 3.png differ diff --git a/public/images/demos/Demos thumbnails 4.png b/public/images/demos/Demos thumbnails 4.png new file mode 100644 index 00000000000..da2a2a0a583 Binary files /dev/null and b/public/images/demos/Demos thumbnails 4.png differ diff --git a/public/images/direct-stacking-logo.svg b/public/images/direct-stacking-logo.svg new file mode 100644 index 00000000000..1814e384a6a --- /dev/null +++ b/public/images/direct-stacking-logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/images/foundry-logo.svg b/public/images/foundry-logo.svg new file mode 100644 index 00000000000..2315253caf3 --- /dev/null +++ b/public/images/foundry-logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/images/hardhat-logo.svg b/public/images/hardhat-logo.svg new file mode 100644 index 00000000000..6077c84afae --- /dev/null +++ b/public/images/hardhat-logo.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/hero-1.png b/public/images/hero-1.png new file mode 100644 index 00000000000..f921b02c1ec Binary files /dev/null and b/public/images/hero-1.png differ diff --git a/public/images/hero-dotted.png b/public/images/hero-dotted.png new file mode 100644 index 00000000000..fbcd97a909d Binary files /dev/null and b/public/images/hero-dotted.png differ diff --git a/public/images/info-sidebar-img.png b/public/images/info-sidebar-img.png new file mode 100644 index 00000000000..44eadb5cfb2 Binary files /dev/null and b/public/images/info-sidebar-img.png differ diff --git a/public/images/js-logo.svg b/public/images/js-logo.svg new file mode 100644 index 00000000000..a4baee9a679 --- /dev/null +++ b/public/images/js-logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/language-icons/go.svg b/public/images/language-icons/go.svg new file mode 100644 index 00000000000..9bb5f643118 --- /dev/null +++ b/public/images/language-icons/go.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/public/images/language-icons/json.svg b/public/images/language-icons/json.svg new file mode 100644 index 00000000000..b5c5ada53de --- /dev/null +++ b/public/images/language-icons/json.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/public/images/language-icons/python.svg b/public/images/language-icons/python.svg new file mode 100644 index 00000000000..5bd72165186 --- /dev/null +++ b/public/images/language-icons/python.svg @@ -0,0 +1,7 @@ + + + + + + python [#ffffff] Created with Sketch. + \ No newline at end of file diff --git a/public/images/language-icons/rust.svg b/public/images/language-icons/rust.svg new file mode 100644 index 00000000000..630595afb26 --- /dev/null +++ b/public/images/language-icons/rust.svg @@ -0,0 +1,7 @@ + + + + + + rust + \ No newline at end of file diff --git a/public/images/language-icons/solidity.svg b/public/images/language-icons/solidity.svg new file mode 100644 index 00000000000..86b9f4995b2 --- /dev/null +++ b/public/images/language-icons/solidity.svg @@ -0,0 +1,27 @@ + + + + +Vector 1 +Created with Sketch. + + + + + + + + + + + + + diff --git a/public/images/language-icons/terminal.svg b/public/images/language-icons/terminal.svg new file mode 100644 index 00000000000..4920153ef58 --- /dev/null +++ b/public/images/language-icons/terminal.svg @@ -0,0 +1,13 @@ + + + diff --git a/public/images/language-icons/toml.svg b/public/images/language-icons/toml.svg new file mode 100644 index 00000000000..de69f153f63 --- /dev/null +++ b/public/images/language-icons/toml.svg @@ -0,0 +1,12 @@ + + + + + + + file_type_toml + + + + + \ No newline at end of file diff --git a/public/images/language-icons/typescript.svg b/public/images/language-icons/typescript.svg new file mode 100644 index 00000000000..025b352d841 --- /dev/null +++ b/public/images/language-icons/typescript.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/public/images/not-found.svg b/public/images/not-found.svg new file mode 100644 index 00000000000..cb212359571 --- /dev/null +++ b/public/images/not-found.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/npm-logo.png b/public/images/npm-logo.png new file mode 100644 index 00000000000..481f9493e8d Binary files /dev/null and b/public/images/npm-logo.png differ diff --git a/public/images/tryitout.png b/public/images/tryitout.png new file mode 100644 index 00000000000..330416da8c9 Binary files /dev/null and b/public/images/tryitout.png differ diff --git a/public/images/ts-logo.svg b/public/images/ts-logo.svg new file mode 100644 index 00000000000..047caf543cc --- /dev/null +++ b/public/images/ts-logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/samples/CCIP/Sender.sol b/public/samples/CCIP/Sender.sol index 0623795b109..595de1de296 100644 --- a/public/samples/CCIP/Sender.sol +++ b/public/samples/CCIP/Sender.sol @@ -4,8 +4,8 @@ pragma solidity 0.8.24; import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; -import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; -import {LinkTokenInterface} from "@chainlink/contracts@1.4.0/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; +import {OwnerIsCreator} from "@chainlink/contracts/src/v0.8/shared/access/OwnerIsCreator.sol"; +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. diff --git a/public/samples/CRE/BasicConsumer.sol b/public/samples/CRE/BasicConsumer.sol new file mode 100644 index 00000000000..f91431b8646 --- /dev/null +++ b/public/samples/CRE/BasicConsumer.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; +import {ReceiverTemplate} from "./ReceiverTemplate.sol"; + +contract MyConsumer is ReceiverTemplate { + uint256 public s_storedValue; + event ValueUpdated(uint256 newValue); + + // Constructor requires forwarder address + constructor( + address _forwarderAddress + ) ReceiverTemplate(_forwarderAddress) {} + + // Implement your business logic here + function _processReport( + bytes calldata report + ) internal override { + uint256 newValue = abi.decode(report, (uint256)); + s_storedValue = newValue; + emit ValueUpdated(newValue); + } +} diff --git a/public/samples/CRE/CalculatorConsumer.sol b/public/samples/CRE/CalculatorConsumer.sol new file mode 100644 index 00000000000..547296b37e0 --- /dev/null +++ b/public/samples/CRE/CalculatorConsumer.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ReceiverTemplate} from "./ReceiverTemplate.sol"; + +/** + * @title CalculatorConsumer (Testing Version) + * @notice This contract receives reports from a CRE workflow and stores the results of a calculation onchain. + * @dev Inherits from ReceiverTemplate which provides security checks. The forwarder address must be + * configured at deployment. Additional security checks (workflowId, workflowName, author) can be enabled via setter + * functions. + */ +contract CalculatorConsumer is ReceiverTemplate { + // Struct to hold the data sent in a report from the workflow + struct CalculatorResult { + uint256 offchainValue; + int256 onchainValue; + uint256 finalResult; + } + + // --- State Variables --- + CalculatorResult public latestResult; + uint256 public resultCount; + mapping(uint256 => CalculatorResult) public results; + + // --- Events --- + event ResultUpdated(uint256 indexed resultId, uint256 finalResult); + + /** + * @notice Constructor requires the forwarder address for security + * @param _forwarderAddress The address of the Chainlink Forwarder contract (for testing: MockForwarder) + * @dev The forwarder address enables the first layer of security - only the forwarder can call onReport. + * Additional security checks can be configured after deployment using setter functions. + */ + constructor( + address _forwarderAddress + ) ReceiverTemplate(_forwarderAddress) {} + + /** + * @notice Implements the core business logic for processing reports. + * @dev This is called automatically by ReceiverTemplate's onReport function after security checks. + */ + function _processReport( + bytes calldata report + ) internal override { + // Decode the report bytes into our CalculatorResult struct + CalculatorResult memory calculatorResult = abi.decode(report, (CalculatorResult)); + + // --- Core Logic --- + // Update contract state with the new result + resultCount++; + results[resultCount] = calculatorResult; + latestResult = calculatorResult; + + emit ResultUpdated(resultCount, calculatorResult.finalResult); + } + + // This function is a "dry-run" utility. It allows an offchain system to check + // if a prospective result is an outlier before submitting it for a real onchain update. + // It is also used to guide the binding generator to create a method that accepts the CalculatorResult struct. + function isResultAnomalous( + CalculatorResult memory _prospectiveResult + ) public view returns (bool) { + // A result is not considered anomalous if it's the first one. + if (resultCount == 0) { + return false; + } + + // Business logic: Define an anomaly as a new result that is more than double the previous result. + // This is just one example of a validation rule you could implement. + return _prospectiveResult.finalResult > (latestResult.finalResult * 2); + } +} diff --git a/public/samples/CRE/IERC165.sol b/public/samples/CRE/IERC165.sol new file mode 100644 index 00000000000..5d28886a8b7 --- /dev/null +++ b/public/samples/CRE/IERC165.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol) + +pragma solidity >=0.4.16; + +/** + * @dev Interface of the ERC-165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[ERC]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface( + bytes4 interfaceId + ) external view returns (bool); +} diff --git a/public/samples/CRE/IReceiver.sol b/public/samples/CRE/IReceiver.sol new file mode 100644 index 00000000000..e7f047b172b --- /dev/null +++ b/public/samples/CRE/IReceiver.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC165} from "./IERC165.sol"; + +/// @title IReceiver - receives keystone reports +/// @notice Implementations must support the IReceiver interface through ERC165. +interface IReceiver is IERC165 { + /// @notice Handles incoming keystone reports. + /// @dev If this function call reverts, it can be retried with a higher gas + /// limit. The receiver is responsible for discarding stale reports. + /// @param metadata Report's metadata. + /// @param report Workflow report. + function onReport( + bytes calldata metadata, + bytes calldata report + ) external; +} diff --git a/public/samples/CRE/ReceiverTemplate.sol b/public/samples/CRE/ReceiverTemplate.sol new file mode 100644 index 00000000000..488324dd652 --- /dev/null +++ b/public/samples/CRE/ReceiverTemplate.sol @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC165} from "./IERC165.sol"; +import {IReceiver} from "./IReceiver.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +/// @title ReceiverTemplate - Abstract receiver with optional permission controls +/// @notice Provides flexible, updatable security checks for receiving workflow reports +/// @dev The forwarder address is required at construction time for security. +/// Additional permission fields can be configured using setter functions. +abstract contract ReceiverTemplate is IReceiver, Ownable { + // Required permission field at deployment, configurable after + address private s_forwarderAddress; // If set, only this address can call onReport + + // Optional permission fields (all default to zero = disabled) + address private s_expectedAuthor; // If set, only reports from this workflow owner are accepted + bytes10 private s_expectedWorkflowName; // Only validated when s_expectedAuthor is also set + bytes32 private s_expectedWorkflowId; // If set, only reports from this specific workflow ID are accepted + + // Hex character lookup table for bytes-to-hex conversion + bytes private constant HEX_CHARS = "0123456789abcdef"; + + // Custom errors + error InvalidForwarderAddress(); + error InvalidSender(address sender, address expected); + error InvalidAuthor(address received, address expected); + error InvalidWorkflowName(bytes10 received, bytes10 expected); + error InvalidWorkflowId(bytes32 received, bytes32 expected); + error WorkflowNameRequiresAuthorValidation(); + + // Events + event ForwarderAddressUpdated(address indexed previousForwarder, address indexed newForwarder); + event ExpectedAuthorUpdated(address indexed previousAuthor, address indexed newAuthor); + event ExpectedWorkflowNameUpdated(bytes10 indexed previousName, bytes10 indexed newName); + event ExpectedWorkflowIdUpdated(bytes32 indexed previousId, bytes32 indexed newId); + event SecurityWarning(string message); + + /// @notice Constructor sets msg.sender as the owner and configures the forwarder address + /// @param _forwarderAddress The address of the Chainlink Forwarder contract (cannot be address(0)) + /// @dev The forwarder address is required for security - it ensures only verified reports are processed + constructor( + address _forwarderAddress + ) Ownable(msg.sender) { + if (_forwarderAddress == address(0)) { + revert InvalidForwarderAddress(); + } + s_forwarderAddress = _forwarderAddress; + emit ForwarderAddressUpdated(address(0), _forwarderAddress); + } + + /// @notice Returns the configured forwarder address + /// @return The forwarder address (address(0) if disabled) + function getForwarderAddress() external view returns (address) { + return s_forwarderAddress; + } + + /// @notice Returns the expected workflow author address + /// @return The expected author address (address(0) if not set) + function getExpectedAuthor() external view returns (address) { + return s_expectedAuthor; + } + + /// @notice Returns the expected workflow name + /// @return The expected workflow name (bytes10(0) if not set) + function getExpectedWorkflowName() external view returns (bytes10) { + return s_expectedWorkflowName; + } + + /// @notice Returns the expected workflow ID + /// @return The expected workflow ID (bytes32(0) if not set) + function getExpectedWorkflowId() external view returns (bytes32) { + return s_expectedWorkflowId; + } + + /// @inheritdoc IReceiver + /// @dev Performs optional validation checks based on which permission fields are set + function onReport( + bytes calldata metadata, + bytes calldata report + ) external override { + // Security Check 1: Verify caller is the trusted Chainlink Forwarder (if configured) + if (s_forwarderAddress != address(0) && msg.sender != s_forwarderAddress) { + revert InvalidSender(msg.sender, s_forwarderAddress); + } + + // Security Checks 2-4: Verify workflow identity - ID, owner, and/or name (if any are configured) + if (s_expectedWorkflowId != bytes32(0) || s_expectedAuthor != address(0) || s_expectedWorkflowName != bytes10(0)) { + (bytes32 workflowId, bytes10 workflowName, address workflowOwner) = _decodeMetadata(metadata); + + if (s_expectedWorkflowId != bytes32(0) && workflowId != s_expectedWorkflowId) { + revert InvalidWorkflowId(workflowId, s_expectedWorkflowId); + } + if (s_expectedAuthor != address(0) && workflowOwner != s_expectedAuthor) { + revert InvalidAuthor(workflowOwner, s_expectedAuthor); + } + + // ================================================================ + // WORKFLOW NAME VALIDATION - REQUIRES AUTHOR VALIDATION + // ================================================================ + // Do not rely on workflow name validation alone. Workflow names are unique + // per owner, but not across owners. + // Furthermore, workflow names use 40-bit truncation (bytes10), making collisions possible. + // Therefore, workflow name validation REQUIRES author (workflow owner) validation. + // The code enforces this dependency at runtime. + // ================================================================ + if (s_expectedWorkflowName != bytes10(0)) { + // Author must be configured if workflow name is used + if (s_expectedAuthor == address(0)) { + revert WorkflowNameRequiresAuthorValidation(); + } + // Validate workflow name matches (author already validated above) + if (workflowName != s_expectedWorkflowName) { + revert InvalidWorkflowName(workflowName, s_expectedWorkflowName); + } + } + } + + _processReport(report); + } + + /// @notice Updates the forwarder address that is allowed to call onReport + /// @param _forwarder The new forwarder address + /// @dev WARNING: Setting to address(0) disables forwarder validation. + /// This makes your contract INSECURE - anyone can call onReport() with arbitrary data. + /// Only use address(0) if you fully understand the security implications. + function setForwarderAddress( + address _forwarder + ) external onlyOwner { + address previousForwarder = s_forwarderAddress; + + // Emit warning if disabling forwarder check + if (_forwarder == address(0)) { + emit SecurityWarning("Forwarder address set to zero - contract is now INSECURE"); + } + + s_forwarderAddress = _forwarder; + emit ForwarderAddressUpdated(previousForwarder, _forwarder); + } + + /// @notice Updates the expected workflow owner address + /// @param _author The new expected author address (use address(0) to disable this check) + function setExpectedAuthor( + address _author + ) external onlyOwner { + address previousAuthor = s_expectedAuthor; + s_expectedAuthor = _author; + emit ExpectedAuthorUpdated(previousAuthor, _author); + } + + /// @notice Updates the expected workflow name from a plaintext string + /// @param _name The workflow name as a string (use empty string "" to disable this check) + /// @dev IMPORTANT: Workflow name validation REQUIRES author validation to be enabled. + /// The workflow name uses only 40-bit truncation, making collision attacks feasible + /// when used alone. However, since workflow names are unique per owner, validating + /// both the name AND the author address provides adequate security. + /// You must call setExpectedAuthor() before or after calling this function. + /// The name is hashed using SHA256 and truncated to bytes10. + function setExpectedWorkflowName( + string calldata _name + ) external onlyOwner { + bytes10 previousName = s_expectedWorkflowName; + + if (bytes(_name).length == 0) { + s_expectedWorkflowName = bytes10(0); + emit ExpectedWorkflowNameUpdated(previousName, bytes10(0)); + return; + } + + // Convert workflow name to bytes10: + // SHA256 hash → hex encode → take first 10 chars → hex encode those chars + bytes32 hash = sha256(bytes(_name)); + bytes memory hexString = _bytesToHexString(abi.encodePacked(hash)); + bytes memory first10 = new bytes(10); + for (uint256 i = 0; i < 10; i++) { + first10[i] = hexString[i]; + } + s_expectedWorkflowName = bytes10(first10); + emit ExpectedWorkflowNameUpdated(previousName, s_expectedWorkflowName); + } + + /// @notice Updates the expected workflow ID + /// @param _id The new expected workflow ID (use bytes32(0) to disable this check) + function setExpectedWorkflowId( + bytes32 _id + ) external onlyOwner { + bytes32 previousId = s_expectedWorkflowId; + s_expectedWorkflowId = _id; + emit ExpectedWorkflowIdUpdated(previousId, _id); + } + + /// @notice Helper function to convert bytes to hex string + /// @param data The bytes to convert + /// @return The hex string representation + function _bytesToHexString( + bytes memory data + ) private pure returns (bytes memory) { + bytes memory hexString = new bytes(data.length * 2); + + for (uint256 i = 0; i < data.length; i++) { + hexString[i * 2] = HEX_CHARS[uint8(data[i] >> 4)]; + hexString[i * 2 + 1] = HEX_CHARS[uint8(data[i] & 0x0f)]; + } + + return hexString; + } + + /// @notice Extracts all metadata fields from the onReport metadata parameter + /// @param metadata The metadata bytes encoded using abi.encodePacked(workflowId, workflowName, workflowOwner) + /// @return workflowId The unique identifier of the workflow (bytes32) + /// @return workflowName The name of the workflow (bytes10) + /// @return workflowOwner The owner address of the workflow + function _decodeMetadata( + bytes memory metadata + ) internal pure returns (bytes32 workflowId, bytes10 workflowName, address workflowOwner) { + // Metadata structure (encoded using abi.encodePacked by the Forwarder): + // - First 32 bytes: length of the byte array (standard for dynamic bytes) + // - Offset 32, size 32: workflow_id (bytes32) + // - Offset 64, size 10: workflow_name (bytes10) + // - Offset 74, size 20: workflow_owner (address) + assembly { + workflowId := mload(add(metadata, 32)) + workflowName := mload(add(metadata, 64)) + workflowOwner := shr(mul(12, 8), mload(add(metadata, 74))) + } + return (workflowId, workflowName, workflowOwner); + } + + /// @notice Abstract function to process the report data + /// @param report The report calldata containing your workflow's encoded data + /// @dev Implement this function with your contract's business logic + function _processReport( + bytes calldata report + ) internal virtual; + + /// @inheritdoc IERC165 + function supportsInterface( + bytes4 interfaceId + ) public view virtual override returns (bool) { + return interfaceId == type(IReceiver).interfaceId || interfaceId == type(IERC165).interfaceId; + } +} diff --git a/public/samples/CRE/basic-functionality.ts b/public/samples/CRE/basic-functionality.ts new file mode 100644 index 00000000000..5a25e8e51a6 --- /dev/null +++ b/public/samples/CRE/basic-functionality.ts @@ -0,0 +1,18 @@ +import { cre } from "@chainlink/cre-sdk" + +cre.handler( + cron.trigger({ schedule: "0 */5 * * *" }), // Every 5 minutes + (runtime) => { + // Fetch data from API + const price = httpClient.get(url).result() + + // Read from EVM blockchain + const threshold = evmClient.read(contract).result() + + // Make any computation + const shouldUpdate = price > threshold + + // Write result onchain + return evmClient.write(contract, price).result() + } +) diff --git a/public/samples/DataFeeds/SVR/import-aggregatorV3.sol b/public/samples/DataFeeds/SVR/import-aggregatorV3.sol new file mode 100644 index 00000000000..229601df65f --- /dev/null +++ b/public/samples/DataFeeds/SVR/import-aggregatorV3.sol @@ -0,0 +1,20 @@ +import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; + +contract SVRConsumer { + AggregatorV3Interface internal svrFeed; + + constructor( + address _svrFeedAddress + ) { + svrFeed = AggregatorV3Interface(_svrFeedAddress); + } + + function getLatestPrice() public view returns (int256) { + (, /* uint80 roundID */ + int256 price, /* uint256 startedAt */ + /* uint256 timeStamp */ + /* uint80 answeredInRound */,, + ) = svrFeed.latestRoundData(); + return price; + } +} diff --git a/public/samples/DataStreams/FetchSingleStream.ts b/public/samples/DataStreams/FetchSingleStream.ts new file mode 100644 index 00000000000..36830885458 --- /dev/null +++ b/public/samples/DataStreams/FetchSingleStream.ts @@ -0,0 +1,55 @@ +import { createClient, decodeReport, LogLevel, getReportVersion, formatReport } from "@chainlink/data-streams-sdk" +import "dotenv/config" + +async function main() { + if (process.argv.length < 3) { + console.error("Please provide a feed ID as an argument") + console.error("Example: npx tsx singleStream.ts 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782") + process.exit(1) + } + + const feedId = process.argv[2] + const version = getReportVersion(feedId) + + try { + const config = { + apiKey: process.env.API_KEY || "YOUR_API_KEY", + userSecret: process.env.USER_SECRET || "YOUR_USER_SECRET", + endpoint: "https://api.testnet-dataengine.chain.link", + wsEndpoint: "wss://ws.testnet-dataengine.chain.link", + // Comment to disable SDK logging: + logging: { + logger: console, + logLevel: LogLevel.INFO, + }, + } + + const client = createClient(config) + console.log(`\nFetching latest report for feed ${feedId} (${version})...\n`) + + // Get raw report data + const report = await client.getLatestReport(feedId) + console.log(`Raw Report Blob: ${report.fullReport}`) + + // Decode the report + const decodedData = decodeReport(report.fullReport, report.feedID) + + // Combine decoded data with report metadata + const decodedReport = { + ...decodedData, + feedID: report.feedID, + validFromTimestamp: report.validFromTimestamp, + observationsTimestamp: report.observationsTimestamp, + } + console.log(formatReport(decodedReport, version)) + } catch (error) { + if (error instanceof Error) { + console.error("Error:", error.message) + } else { + console.error("Unknown error:", error) + } + process.exit(1) + } +} + +main() diff --git a/reports/llms-report.json b/reports/llms-report.json deleted file mode 100644 index 23c8ab3522c..00000000000 --- a/reports/llms-report.json +++ /dev/null @@ -1,127 +0,0 @@ -{ - "startedAt": "2025-11-25T23:16:10.318Z", - "siteBase": "https://docs.chain.link", - "sections": [ - { - "section": "cre-go", - "pagesProcessed": 83, - "outputPath": "src/content/cre/llms-full-go.txt", - "bytes": 651940, - "prevBytes": 651940, - "deltaBytes": 0 - }, - { - "section": "cre-ts", - "pagesProcessed": 78, - "outputPath": "src/content/cre/llms-full-ts.txt", - "bytes": 607447, - "prevBytes": 607447, - "deltaBytes": 0 - }, - { - "section": "vrf", - "pagesProcessed": 35, - "outputPath": "src/content/vrf/llms-full.txt", - "bytes": 301012, - "prevBytes": 301012, - "deltaBytes": 0 - }, - { - "section": "ccip", - "pagesProcessed": 260, - "outputPath": "src/content/ccip/llms-full.txt", - "bytes": 2849278, - "prevBytes": 2849278, - "deltaBytes": 0 - }, - { - "section": "data-feeds", - "pagesProcessed": 37, - "outputPath": "src/content/data-feeds/llms-full.txt", - "bytes": 302350, - "prevBytes": 302350, - "deltaBytes": 0 - }, - { - "section": "data-streams", - "pagesProcessed": 54, - "outputPath": "src/content/data-streams/llms-full.txt", - "bytes": 477065, - "prevBytes": 477061, - "deltaBytes": 4 - }, - { - "section": "dta-technical-standard", - "pagesProcessed": 7, - "outputPath": "src/content/dta-technical-standard/llms-full.txt", - "bytes": 32397, - "prevBytes": 32397, - "deltaBytes": 0 - }, - { - "section": "datalink", - "pagesProcessed": 20, - "outputPath": "src/content/datalink/llms-full.txt", - "bytes": 136010, - "prevBytes": 136010, - "deltaBytes": 0 - }, - { - "section": "chainlink-functions", - "pagesProcessed": 27, - "outputPath": "src/content/chainlink-functions/llms-full.txt", - "bytes": 299619, - "prevBytes": 299619, - "deltaBytes": 0 - }, - { - "section": "chainlink-automation", - "pagesProcessed": 25, - "outputPath": "src/content/chainlink-automation/llms-full.txt", - "bytes": 196013, - "prevBytes": 196013, - "deltaBytes": 0 - }, - { - "section": "resources", - "pagesProcessed": 12, - "outputPath": "src/content/resources/llms-full.txt", - "bytes": 331970, - "prevBytes": 331970, - "deltaBytes": 0 - }, - { - "section": "architecture-overview", - "pagesProcessed": 4, - "outputPath": "src/content/architecture-overview/llms-full.txt", - "bytes": 13086, - "prevBytes": 13086, - "deltaBytes": 0 - }, - { - "section": "getting-started", - "pagesProcessed": 1, - "outputPath": "src/content/getting-started/llms-full.txt", - "bytes": 10326, - "prevBytes": 10326, - "deltaBytes": 0 - }, - { - "section": "chainlink-nodes", - "pagesProcessed": 37, - "outputPath": "src/content/chainlink-nodes/llms-full.txt", - "bytes": 660645, - "prevBytes": 660645, - "deltaBytes": 0 - }, - { - "section": "chainlink-local", - "pagesProcessed": 55, - "outputPath": "src/content/chainlink-local/llms-full.txt", - "bytes": 297263, - "prevBytes": 297263, - "deltaBytes": 0 - } - ], - "finishedAt": "2025-11-25T23:16:13.816Z" -} diff --git a/scripts/cleanup-vercel-function.mjs b/scripts/cleanup-vercel-function.mjs new file mode 100755 index 00000000000..04eaea1a707 --- /dev/null +++ b/scripts/cleanup-vercel-function.mjs @@ -0,0 +1,50 @@ +#!/usr/bin/env node +/** + * Post-build script to remove unnecessary files from Vercel serverless function + * Reduces function size from 364MB to under 250MB limit + */ + +import { rm } from "fs/promises" +import { existsSync } from "fs" +import { execSync } from "child_process" + +const FUNCTION_DIR = ".vercel/output/functions/_render.func" + +async function cleanup() { + if (!existsSync(FUNCTION_DIR)) { + console.error(`❌ Function directory not found: ${FUNCTION_DIR}`) + process.exit(1) + } + + console.log("🧹 Cleaning up serverless function bundle...") + + const sizeBefore = execSync(`du -sh ${FUNCTION_DIR}`, { encoding: "utf-8" }).trim() + console.log(`📦 Size before: ${sizeBefore}`) + + // Remove large files/directories that are served statically by CDN + // Note: public/samples is kept because the /api/page-markdown endpoint needs to read these files + const itemsToRemove = [ + `${FUNCTION_DIR}/public/images`, + `${FUNCTION_DIR}/public/search-index.json`, + `${FUNCTION_DIR}/public/files`, + `${FUNCTION_DIR}/public/default-og-image.png`, + // `${FUNCTION_DIR}/public/samples`, // Kept for API route access + `${FUNCTION_DIR}/public/changelog.json`, + ] + + for (const item of itemsToRemove) { + if (existsSync(item)) { + await rm(item, { recursive: true, force: true }) + console.log(` ✓ Removed: ${item.replace(FUNCTION_DIR + "/", "")}`) + } + } + + const sizeAfter = execSync(`du -sh ${FUNCTION_DIR}`, { encoding: "utf-8" }).trim() + console.log(`📦 Size after: ${sizeAfter}`) + console.log("✨ Cleanup complete!") +} + +cleanup().catch((error) => { + console.error("❌ Cleanup failed:", error) + process.exit(1) +}) diff --git a/src/__mocks__/rate-limits-mainnet.json b/src/__mocks__/rate-limits-mainnet.json new file mode 100644 index 00000000000..3f90fff496c --- /dev/null +++ b/src/__mocks__/rate-limits-mainnet.json @@ -0,0 +1,55946 @@ +{ + "$PAAL": { + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "1XMM": { + "bsc-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "AISTR": { + "bsc-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 5, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "ANIMA": { + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + } + }, + "APRS": { + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "11910000000000000000000000", + "isEnabled": true, + "rate": "137847213400000000000" + }, + "out": { + "capacity": "18090000000000000000000000", + "isEnabled": true, + "rate": "209375000000000000000" + } + }, + "standard": { + "in": { + "capacity": "30000000000000000000000000", + "isEnabled": true, + "rate": "347222200000000000000" + }, + "out": { + "capacity": "27000000000000000000000000", + "isEnabled": true, + "rate": "312500000000000000000" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "20370000000000000000000000", + "isEnabled": true, + "rate": "235763873800000000000" + }, + "out": { + "capacity": "14931000000000000000000000", + "isEnabled": true, + "rate": "172812500000000000000" + } + }, + "standard": { + "in": { + "capacity": "30000000000000000000000000", + "isEnabled": true, + "rate": "347222200000000000000" + }, + "out": { + "capacity": "27000000000000000000000000", + "isEnabled": true, + "rate": "312500000000000000000" + } + } + } + } + } + }, + "APU": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "30600000000000000000000000", + "isEnabled": true, + "rate": "8499999976200000000000" + }, + "out": { + "capacity": "32900000000000000000000000", + "isEnabled": true, + "rate": "9138888863300000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + }, + "out": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "45700000000000000000000000", + "isEnabled": true, + "rate": "12694444408900000000000" + }, + "out": { + "capacity": "49600000000000000000000000", + "isEnabled": true, + "rate": "13777777739200000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + }, + "out": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "44700000000000000000000000", + "isEnabled": true, + "rate": "12416666631900000000000" + }, + "out": { + "capacity": "34300000000000000000000000", + "isEnabled": true, + "rate": "9527777751100000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + }, + "out": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "56600000000000000000000000", + "isEnabled": true, + "rate": "15722222178200000000000" + }, + "out": { + "capacity": "46200000000000000000000000", + "isEnabled": true, + "rate": "12833333297400000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + }, + "out": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "36000000000000000000000000", + "isEnabled": true, + "rate": "9999999972000000000000" + }, + "out": { + "capacity": "56400000000000000000000000", + "isEnabled": true, + "rate": "15666666622800000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + }, + "out": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27777777700000000000000" + } + } + } + } + } + }, + "avBTC": { + "avalanche-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "avETH": { + "avalanche-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "avETHx": { + "avalanche-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "avUSD": { + "avalanche-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "avUSDx": { + "avalanche-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "AXS": { + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BANANA": { + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1017000000000000000000000", + "isEnabled": true, + "rate": "11770832580000000000" + }, + "out": { + "capacity": "460350000000000000000000", + "isEnabled": true, + "rate": "5328125000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "17361110000000000000" + }, + "out": { + "capacity": "1350000000000000000000000", + "isEnabled": true, + "rate": "15625000000000000000" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "538500000000000000000000", + "isEnabled": true, + "rate": "6232638490000000000" + }, + "out": { + "capacity": "507600000000000000000000", + "isEnabled": true, + "rate": "5875000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "17361110000000000000" + }, + "out": { + "capacity": "1350000000000000000000000", + "isEnabled": true, + "rate": "15625000000000000000" + } + } + } + } + } + }, + "BANK": { + "bsc-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BARD": { + "bsc-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "beraBTC": { + "berachain-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BETS": { + "avalanche-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "11970000000000000000000000", + "isEnabled": true, + "rate": "19950000000000000000000" + }, + "out": { + "capacity": "11730000000000000000000000", + "isEnabled": true, + "rate": "19550000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "30000000000000000000000000", + "isEnabled": true, + "rate": "50000000000000000000000" + }, + "out": { + "capacity": "30000000000000000000000000", + "isEnabled": true, + "rate": "50000000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "18810000000000000000000000", + "isEnabled": true, + "rate": "31350000000000000000000" + }, + "out": { + "capacity": "13020000000000000000000000", + "isEnabled": true, + "rate": "21700000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "30000000000000000000000000", + "isEnabled": true, + "rate": "50000000000000000000000" + }, + "out": { + "capacity": "30000000000000000000000000", + "isEnabled": true, + "rate": "50000000000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "19350000000000000000000000", + "isEnabled": true, + "rate": "32250000000000000000000" + }, + "out": { + "capacity": "13260000000000000000000000", + "isEnabled": true, + "rate": "22100000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "30000000000000000000000000", + "isEnabled": true, + "rate": "50000000000000000000000" + }, + "out": { + "capacity": "30000000000000000000000000", + "isEnabled": true, + "rate": "50000000000000000000000" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 8, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-unichain-1": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": null, + "standard": null + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BKN": { + "bsc-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BMX": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "65300000000000000000000", + "isEnabled": true, + "rate": "18133810000000000000" + }, + "out": { + "capacity": "50800000000000000000000", + "isEnabled": true, + "rate": "14107160000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27770000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27770000000000000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "65100000000000000000000", + "isEnabled": true, + "rate": "18078270000000000000" + }, + "out": { + "capacity": "36500000000000000000000", + "isEnabled": true, + "rate": "10136050000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27770000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27770000000000000000" + } + } + } + } + }, + "ethereum-mainnet-mode-1": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "35500000000000000000000", + "isEnabled": true, + "rate": "9858350000000000000" + }, + "out": { + "capacity": "55300000000000000000000", + "isEnabled": true, + "rate": "15356810000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27770000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27770000000000000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BOB": { + "bitcoin-mainnet-bob-1": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BOLD": { + "avalanche-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "berachain-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-scroll-1": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "hyperliquid-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-scroll-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "plasma-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BONE": { + "avalanche-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "celo-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-andromeda-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-blast-1": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-mantle-1": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-mode-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-scroll-1": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-zircuit-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-zksync-1": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": null, + "standard": null + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "celo-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-andromeda-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-blast-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-mantle-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-scroll-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-zircuit-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polkadot-mainnet-astar": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "polkadot-mainnet-astar": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "wemix-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "xdai-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BR": { + "berachain-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "2980000000000000000000000", + "isEnabled": true, + "rate": "34568000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "682000000000000000", + "isEnabled": true, + "rate": "68200000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "1000000000000000000", + "isEnabled": true, + "rate": "100000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "326000000000000000", + "isEnabled": true, + "rate": "32600000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "1000000000000000000", + "isEnabled": true, + "rate": "100000000000000000" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "2780000000000000000000000", + "isEnabled": true, + "rate": "32248000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "2865000000000000000000000", + "isEnabled": true, + "rate": "33234000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "2370000000000000000000000", + "isEnabled": true, + "rate": "27492000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "283500000000000", + "isEnabled": true, + "rate": "3288600000" + }, + "out": { + "capacity": "2075000000000000000000000", + "isEnabled": true, + "rate": "24070000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "5800000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 6, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "471000000000000000", + "isEnabled": true, + "rate": "47100000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "1000000000000000000", + "isEnabled": true, + "rate": "100000000000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "2070000000000000000000000", + "isEnabled": true, + "rate": "24012000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "511000000000000000", + "isEnabled": true, + "rate": "51100000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "1000000000000000000", + "isEnabled": true, + "rate": "100000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "676000000000000000", + "isEnabled": true, + "rate": "67600000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "1000000000000000000", + "isEnabled": true, + "rate": "100000000000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "2620000000000000000000000", + "isEnabled": true, + "rate": "30392000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "595000000000000000", + "isEnabled": true, + "rate": "59500000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "1000000000000000000", + "isEnabled": true, + "rate": "100000000000000000" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "347500000000000", + "isEnabled": true, + "rate": "4031000000" + }, + "out": { + "capacity": "273000000000000", + "isEnabled": true, + "rate": "3166800000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "5800000000" + }, + "out": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "5800000000" + } + } + } + } + } + }, + "brBTC": { + "aptos-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "91400000", + "isEnabled": true, + "rate": "1057" + }, + "out": { + "capacity": "113000000", + "isEnabled": true, + "rate": "1307" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "107200000", + "isEnabled": true, + "rate": "1240" + }, + "out": { + "capacity": "113800000", + "isEnabled": true, + "rate": "1317" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "berachain-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "127800000", + "isEnabled": true, + "rate": "1479" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "aptos-mainnet": { + "custom": { + "in": { + "capacity": "94200000", + "isEnabled": true, + "rate": "1090" + }, + "out": { + "capacity": "72600000", + "isEnabled": true, + "rate": "840" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "91600000", + "isEnabled": true, + "rate": "1060" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "120800000", + "isEnabled": true, + "rate": "1398" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "ethereum-mainnet-ink-1": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "73600000", + "isEnabled": true, + "rate": "851" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "ethereum-mainnet-xlayer-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "133600000", + "isEnabled": true, + "rate": "1546" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "hyperliquid-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "80400000", + "isEnabled": true, + "rate": "930" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "aptos-mainnet": { + "custom": { + "in": { + "capacity": "108400000", + "isEnabled": true, + "rate": "1254" + }, + "out": { + "capacity": "118800000", + "isEnabled": true, + "rate": "1375" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "berachain-mainnet": { + "custom": null, + "standard": null + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "135400000", + "isEnabled": true, + "rate": "1567" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "132200000", + "isEnabled": true, + "rate": "1530" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "111800000", + "isEnabled": true, + "rate": "1294" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "ethereum-mainnet-xlayer-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "73000000", + "isEnabled": true, + "rate": "844" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "73200000", + "isEnabled": true, + "rate": "847" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "120600000", + "isEnabled": true, + "rate": "1395" + }, + "out": { + "capacity": "139600000", + "isEnabled": true, + "rate": "1615" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "139400000", + "isEnabled": true, + "rate": "1613" + }, + "out": { + "capacity": "85800000", + "isEnabled": true, + "rate": "993" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + } + }, + "BTR": { + "bitcoin-mainnet-bitlayer-1": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "BYTES": { + "avalanche-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "CANNED": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 6, + "remote": { + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "CGX": { + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "CHEX": { + "bsc-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "CHIKA": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "CKP": { + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "44400000000000000000000", + "isEnabled": true, + "rate": "12432000000000000000" + }, + "out": { + "capacity": "30500000000000000000000", + "isEnabled": true, + "rate": "8540000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "28000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "28000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "56500000000000000000000", + "isEnabled": true, + "rate": "15820000000000000000" + }, + "out": { + "capacity": "62300000000000000000000", + "isEnabled": true, + "rate": "17444000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "28000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "28000000000000000000" + } + } + } + } + } + }, + "clBTC": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "CRTV": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "DAMN": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "DEGEN": { + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "soneium-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "DFX": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "3145000000000000000000000", + "isEnabled": true, + "rate": "35853000000000000000" + }, + "out": { + "capacity": "2865000000000000000000000", + "isEnabled": true, + "rate": "32661000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "2840000000000000000000000", + "isEnabled": true, + "rate": "32376000000000000000" + }, + "out": { + "capacity": "2025000000000000000000000", + "isEnabled": true, + "rate": "23085000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "2065000000000000000000000", + "isEnabled": true, + "rate": "23541000000000000000" + }, + "out": { + "capacity": "2795000000000000000000000", + "isEnabled": true, + "rate": "31863000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "3105000000000000000000000", + "isEnabled": true, + "rate": "35397000000000000000" + }, + "out": { + "capacity": "1705000000000000000000000", + "isEnabled": true, + "rate": "19437000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "3080000000000000000000000", + "isEnabled": true, + "rate": "35112000000000000000" + }, + "out": { + "capacity": "2095000000000000000000000", + "isEnabled": true, + "rate": "23883000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1600000000000000000000000", + "isEnabled": true, + "rate": "18240000000000000000" + }, + "out": { + "capacity": "1980000000000000000000000", + "isEnabled": true, + "rate": "22572000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57000000000000000000" + } + } + } + } + } + }, + "DIP": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "6730000000000000000000000", + "isEnabled": true, + "rate": "1869594000000000000000" + }, + "out": { + "capacity": "3300000000000000000000000", + "isEnabled": true, + "rate": "916740000000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "2778000000000000000000" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "2778000000000000000000" + } + } + } + } + } + }, + "DOBO": { + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "DOLO": { + "berachain-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "DPI": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "386802000000000000000", + "isEnabled": true, + "rate": "26100000000000000" + }, + "out": { + "capacity": "431262000000000000000", + "isEnabled": true, + "rate": "29100000000000000" + } + }, + "standard": { + "in": { + "capacity": "741000000000000000000", + "isEnabled": true, + "rate": "50000000000000000" + }, + "out": { + "capacity": "741000000000000000000", + "isEnabled": true, + "rate": "50000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1698415000000000000000", + "isEnabled": true, + "rate": "117900000000000000" + }, + "out": { + "capacity": "873841000000000000000", + "isEnabled": true, + "rate": "60660000000000000" + } + }, + "standard": { + "in": { + "capacity": "2593000000000000000000", + "isEnabled": true, + "rate": "180000000000000000" + }, + "out": { + "capacity": "2593000000000000000000", + "isEnabled": true, + "rate": "180000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "245271000000000000000", + "isEnabled": true, + "rate": "16550000000000000" + }, + "out": { + "capacity": "472017000000000000000", + "isEnabled": true, + "rate": "31850000000000000" + } + }, + "standard": { + "in": { + "capacity": "741000000000000000000", + "isEnabled": true, + "rate": "50000000000000000" + }, + "out": { + "capacity": "741000000000000000000", + "isEnabled": true, + "rate": "50000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "469053000000000000000", + "isEnabled": true, + "rate": "31650000000000000" + }, + "out": { + "capacity": "246012000000000000000", + "isEnabled": true, + "rate": "16600000000000000" + } + }, + "standard": { + "in": { + "capacity": "741000000000000000000", + "isEnabled": true, + "rate": "50000000000000000" + }, + "out": { + "capacity": "741000000000000000000", + "isEnabled": true, + "rate": "50000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1571358000000000000000", + "isEnabled": true, + "rate": "109080000000000000" + }, + "out": { + "capacity": "902364000000000000000", + "isEnabled": true, + "rate": "62640000000000000" + } + }, + "standard": { + "in": { + "capacity": "2593000000000000000000", + "isEnabled": true, + "rate": "180000000000000000" + }, + "out": { + "capacity": "2593000000000000000000", + "isEnabled": true, + "rate": "180000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "223041000000000000000", + "isEnabled": true, + "rate": "15050000000000000" + }, + "out": { + "capacity": "312702000000000000000", + "isEnabled": true, + "rate": "21100000000000000" + } + }, + "standard": { + "in": { + "capacity": "741000000000000000000", + "isEnabled": true, + "rate": "50000000000000000" + }, + "out": { + "capacity": "741000000000000000000", + "isEnabled": true, + "rate": "50000000000000000" + } + } + } + } + } + }, + "dsETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "6383000000000000000", + "isEnabled": true, + "rate": "441900000000000" + }, + "out": { + "capacity": "5967000000000000000", + "isEnabled": true, + "rate": "413100000000000" + } + }, + "standard": { + "in": { + "capacity": "13000000000000000000", + "isEnabled": true, + "rate": "900000000000000" + }, + "out": { + "capacity": "13000000000000000000", + "isEnabled": true, + "rate": "900000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "11200000000000000000", + "isEnabled": true, + "rate": "761600000000000" + }, + "out": { + "capacity": "11800000000000000000", + "isEnabled": true, + "rate": "802400000000000" + } + }, + "standard": { + "in": { + "capacity": "25000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + }, + "out": { + "capacity": "25000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "5642000000000000000", + "isEnabled": true, + "rate": "390600000000000" + }, + "out": { + "capacity": "6786000000000000000", + "isEnabled": true, + "rate": "469800000000000" + } + }, + "standard": { + "in": { + "capacity": "13000000000000000000", + "isEnabled": true, + "rate": "900000000000000" + }, + "out": { + "capacity": "13000000000000000000", + "isEnabled": true, + "rate": "900000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "5213000000000000000", + "isEnabled": true, + "rate": "360900000000000" + }, + "out": { + "capacity": "6084000000000000000", + "isEnabled": true, + "rate": "421200000000000" + } + }, + "standard": { + "in": { + "capacity": "13000000000000000000", + "isEnabled": true, + "rate": "900000000000000" + }, + "out": { + "capacity": "13000000000000000000", + "isEnabled": true, + "rate": "900000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "8175000000000000000", + "isEnabled": true, + "rate": "555900000000000" + }, + "out": { + "capacity": "10575000000000000000", + "isEnabled": true, + "rate": "719100000000000" + } + }, + "standard": { + "in": { + "capacity": "25000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + }, + "out": { + "capacity": "25000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "6981000000000000000", + "isEnabled": true, + "rate": "483300000000000" + }, + "out": { + "capacity": "5317000000000000000", + "isEnabled": true, + "rate": "368100000000000" + } + }, + "standard": { + "in": { + "capacity": "13000000000000000000", + "isEnabled": true, + "rate": "900000000000000" + }, + "out": { + "capacity": "13000000000000000000", + "isEnabled": true, + "rate": "900000000000000" + } + } + } + } + } + }, + "EARNM": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "240000000000000000000000", + "isEnabled": true, + "rate": "66662400000000000000" + }, + "out": { + "capacity": "359375000000000000000000", + "isEnabled": true, + "rate": "99820000000000000000" + } + }, + "standard": { + "in": { + "capacity": "625000000000000000000000", + "isEnabled": true, + "rate": "173600000000000000000" + }, + "out": { + "capacity": "625000000000000000000000", + "isEnabled": true, + "rate": "173600000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "311250000000000000000000", + "isEnabled": true, + "rate": "86452800000000000000" + }, + "out": { + "capacity": "340000000000000000000000", + "isEnabled": true, + "rate": "94438400000000000000" + } + }, + "standard": { + "in": { + "capacity": "625000000000000000000000", + "isEnabled": true, + "rate": "173600000000000000000" + }, + "out": { + "capacity": "625000000000000000000000", + "isEnabled": true, + "rate": "173600000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "60000000000000000000000000", + "isEnabled": true, + "rate": "16666800000000000000000" + }, + "out": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13889000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27778000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27778000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": null, + "standard": null + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "36800000000000000000000000", + "isEnabled": true, + "rate": "10222304000000000000000" + }, + "out": { + "capacity": "58400000000000000000000000", + "isEnabled": true, + "rate": "16222352000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27778000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27778000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "410625000000000000000000", + "isEnabled": true, + "rate": "114055200000000000000" + }, + "out": { + "capacity": "219375000000000000000000", + "isEnabled": true, + "rate": "60933600000000000000" + } + }, + "standard": { + "in": { + "capacity": "625000000000000000000000", + "isEnabled": true, + "rate": "173600000000000000000" + }, + "out": { + "capacity": "625000000000000000000000", + "isEnabled": true, + "rate": "173600000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "195000000000000000000000", + "isEnabled": true, + "rate": "54163200000000000000" + }, + "out": { + "capacity": "266250000000000000000000", + "isEnabled": true, + "rate": "73953600000000000000" + } + }, + "standard": { + "in": { + "capacity": "625000000000000000000000", + "isEnabled": true, + "rate": "173600000000000000000" + }, + "out": { + "capacity": "625000000000000000000000", + "isEnabled": true, + "rate": "173600000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "23300000000000000000000000", + "isEnabled": true, + "rate": "6472274000000000000000" + }, + "out": { + "capacity": "29750000000000000000000000", + "isEnabled": true, + "rate": "8263955000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13889000000000000000000" + }, + "out": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13889000000000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13889000000000000000000" + }, + "out": { + "capacity": "45700000000000000000000000", + "isEnabled": true, + "rate": "12694546000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27778000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27778000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "62700000000000000000000000", + "isEnabled": true, + "rate": "17416806000000000000000" + }, + "out": { + "capacity": "63100000000000000000000000", + "isEnabled": true, + "rate": "17527918000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27778000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000000", + "isEnabled": true, + "rate": "27778000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "29250000000000000000000000", + "isEnabled": true, + "rate": "8125065000000000000000" + }, + "out": { + "capacity": "29350000000000000000000000", + "isEnabled": true, + "rate": "8152843000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13889000000000000000000" + }, + "out": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13889000000000000000000" + } + } + } + } + } + }, + "EDEN": { + "bsc-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "egETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "62400000000000000000", + "isEnabled": true, + "rate": "5778240000000000" + }, + "out": { + "capacity": "61200000000000000000", + "isEnabled": true, + "rate": "5667120000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "55200000000000000000", + "isEnabled": true, + "rate": "5111520000000000" + }, + "out": { + "capacity": "69200000000000000000", + "isEnabled": true, + "rate": "6407920000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + }, + "sonic-mainnet": { + "custom": null, + "standard": null + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "65500000000000000000", + "isEnabled": true, + "rate": "6065300000000000" + }, + "out": { + "capacity": "64400000000000000000", + "isEnabled": true, + "rate": "5963440000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + } + } + } + }, + "elizaOS": { + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "EmCH": { + "avalanche-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "enzoBTC": { + "bsc-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-hashkey-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-hashkey-1": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "ETHx": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "598000000000000000000", + "isEnabled": true, + "rate": "33488000000000000" + }, + "out": { + "capacity": "578000000000000000000", + "isEnabled": true, + "rate": "32368000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "56000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "56000000000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "464000000000000000000", + "isEnabled": true, + "rate": "25984000000000000" + }, + "out": { + "capacity": "572000000000000000000", + "isEnabled": true, + "rate": "32032000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "56000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "56000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "469000000000000000000", + "isEnabled": true, + "rate": "26264000000000000" + }, + "out": { + "capacity": "603000000000000000000", + "isEnabled": true, + "rate": "33768000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "56000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "56000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "632000000000000000000", + "isEnabled": true, + "rate": "35392000000000000" + }, + "out": { + "capacity": "668000000000000000000", + "isEnabled": true, + "rate": "37408000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "56000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "56000000000000000" + } + } + } + } + } + }, + "eUSX": { + "plasma-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "FEED": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": null, + "remote": { + "shibarium-mainnet": { + "custom": null, + "standard": null + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "FF": { + "bsc-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "FHE": { + "bsc-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mind-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mind-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mind-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "FLUID": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1254000000000000000000000", + "isEnabled": true, + "rate": "14513888888888888888" + }, + "out": { + "capacity": "802000000000000000000000", + "isEnabled": true, + "rate": "9282407407407407407" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1292000000000000000000000", + "isEnabled": true, + "rate": "14953703703703703703" + }, + "out": { + "capacity": "828000000000000000000000", + "isEnabled": true, + "rate": "9583333333333333333" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "186500000000000000000000", + "isEnabled": true, + "rate": "2158551000000000000" + }, + "out": { + "capacity": "317500000000000000000000", + "isEnabled": true, + "rate": "3674745000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "216000000000000000000000", + "isEnabled": true, + "rate": "2499999999999999999" + }, + "out": { + "capacity": "215000000000000000000000", + "isEnabled": true, + "rate": "2488425925925925925" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787037037037037037" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787037037037037037" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1202000000000000000000000", + "isEnabled": true, + "rate": "13912037037037037036" + }, + "out": { + "capacity": "1250000000000000000000000", + "isEnabled": true, + "rate": "14467592592592592592" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "668000000000000000000000", + "isEnabled": true, + "rate": "7731481481481481481" + }, + "out": { + "capacity": "840000000000000000000000", + "isEnabled": true, + "rate": "9722222222222222222" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "341000000000000000000000", + "isEnabled": true, + "rate": "3946734000000000000" + }, + "out": { + "capacity": "286500000000000000000000", + "isEnabled": true, + "rate": "3315951000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "315500000000000000000000", + "isEnabled": true, + "rate": "3651620370370370370" + }, + "out": { + "capacity": "260000000000000000000000", + "isEnabled": true, + "rate": "3009259259259259259" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787037037037037037" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787037037037037037" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "864000000000000000000000", + "isEnabled": true, + "rate": "9999999999999999999" + }, + "out": { + "capacity": "1066000000000000000000000", + "isEnabled": true, + "rate": "12337962962962962962" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "762000000000000000000000", + "isEnabled": true, + "rate": "8819444444444444444" + }, + "out": { + "capacity": "902000000000000000000000", + "isEnabled": true, + "rate": "10439814814814814814" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148148148148148148" + } + } + }, + "plasma-mainnet": { + "custom": null, + "standard": null + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314814814814814814" + }, + "out": { + "capacity": "336500000000000000000000", + "isEnabled": true, + "rate": "3894675925925925925" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787037037037037037" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787037037037037037" + } + } + } + } + }, + "plasma-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "152500000000000000000000", + "isEnabled": true, + "rate": "1765035000000000000" + }, + "out": { + "capacity": "206500000000000000000000", + "isEnabled": true, + "rate": "2390031000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "239000000000000000000000", + "isEnabled": true, + "rate": "2766186000000000000" + }, + "out": { + "capacity": "312000000000000000000000", + "isEnabled": true, + "rate": "3611088000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "206000000000000000000000", + "isEnabled": true, + "rate": "2384244000000000000" + }, + "out": { + "capacity": "159000000000000000000000", + "isEnabled": true, + "rate": "1840266000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "208500000000000", + "isEnabled": true, + "rate": "2413179000" + }, + "out": { + "capacity": "302500000000000000000000", + "isEnabled": true, + "rate": "3501135000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "5787000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "315500000000000", + "isEnabled": true, + "rate": "14606451100" + }, + "out": { + "capacity": "288000000000000", + "isEnabled": true, + "rate": "13333305600" + } + }, + "standard": { + "in": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "23148100000" + }, + "out": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "23148100000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "200500000000000", + "isEnabled": true, + "rate": "9282388100" + }, + "out": { + "capacity": "264500000000000", + "isEnabled": true, + "rate": "12245344900" + } + }, + "standard": { + "in": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "23148100000" + }, + "out": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "23148100000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "333000000000000", + "isEnabled": true, + "rate": "15416634600" + }, + "out": { + "capacity": "262500000000000", + "isEnabled": true, + "rate": "12152752500" + } + }, + "standard": { + "in": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "23148100000" + }, + "out": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "23148100000" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "235500000000000", + "isEnabled": true, + "rate": "2725677000" + }, + "out": { + "capacity": "268000000000000", + "isEnabled": true, + "rate": "3101832000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "5787000000" + }, + "out": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "5787000000" + } + } + } + } + } + }, + "GEN": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "GHO": { + "avalanche-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "798000000000000000000000", + "isEnabled": true, + "rate": "159600000000000000000" + }, + "out": { + "capacity": "961500000000000000000000", + "isEnabled": true, + "rate": "192300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "462000000000000000000000", + "isEnabled": true, + "rate": "92400000000000000000" + }, + "out": { + "capacity": "1026000000000000000000000", + "isEnabled": true, + "rate": "205200000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "973500000000000000000000", + "isEnabled": true, + "rate": "194700000000000000000" + }, + "out": { + "capacity": "645000000000000000000000", + "isEnabled": true, + "rate": "129000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "690000000000000000000000", + "isEnabled": true, + "rate": "138000000000000000000" + }, + "out": { + "capacity": "901500000000000000000000", + "isEnabled": true, + "rate": "180300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "693000000000000000000000", + "isEnabled": true, + "rate": "138600000000000000000" + }, + "out": { + "capacity": "760500000000000000000000", + "isEnabled": true, + "rate": "152100000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "897000000000000000000000", + "isEnabled": true, + "rate": "179400000000000000000" + }, + "out": { + "capacity": "646500000000000000000000", + "isEnabled": true, + "rate": "129300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "555000000000000000000000", + "isEnabled": true, + "rate": "111000000000000000000" + }, + "out": { + "capacity": "618000000000000000000000", + "isEnabled": true, + "rate": "123600000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1038000000000000000000000", + "isEnabled": true, + "rate": "207600000000000000000" + }, + "out": { + "capacity": "888000000000000000000000", + "isEnabled": true, + "rate": "177600000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "853500000000000000000000", + "isEnabled": true, + "rate": "170700000000000000000" + }, + "out": { + "capacity": "1035000000000000000000000", + "isEnabled": true, + "rate": "207000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "912000000000000000000000", + "isEnabled": true, + "rate": "182400000000000000000" + }, + "out": { + "capacity": "1005000000000000000000000", + "isEnabled": true, + "rate": "201000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "559500000000000000000000", + "isEnabled": true, + "rate": "111900000000000000000" + }, + "out": { + "capacity": "825000000000000000000000", + "isEnabled": true, + "rate": "165000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "643500000000000000000000", + "isEnabled": true, + "rate": "128700000000000000000" + }, + "out": { + "capacity": "744000000000000000000000", + "isEnabled": true, + "rate": "148800000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "864000000000000000000000", + "isEnabled": true, + "rate": "172800000000000000000" + }, + "out": { + "capacity": "496500000000000000000000", + "isEnabled": true, + "rate": "99300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "769500000000000000000000", + "isEnabled": true, + "rate": "153900000000000000000" + }, + "out": { + "capacity": "601500000000000000000000", + "isEnabled": true, + "rate": "120300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "808500000000000000000000", + "isEnabled": true, + "rate": "161700000000000000000" + }, + "out": { + "capacity": "714000000000000000000000", + "isEnabled": true, + "rate": "142800000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "1000500000000000000000000", + "isEnabled": true, + "rate": "200100000000000000000" + }, + "out": { + "capacity": "856500000000000000000000", + "isEnabled": true, + "rate": "171300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "460500000000000000000000", + "isEnabled": true, + "rate": "92100000000000000000" + }, + "out": { + "capacity": "672000000000000000000000", + "isEnabled": true, + "rate": "134400000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-ink-1": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "907500000000000000000000", + "isEnabled": true, + "rate": "181500000000000000000" + }, + "out": { + "capacity": "936000000000000000000000", + "isEnabled": true, + "rate": "187200000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "906000000000000000000000", + "isEnabled": true, + "rate": "181200000000000000000" + }, + "out": { + "capacity": "754500000000000000000000", + "isEnabled": true, + "rate": "150900000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "811500000000000000000000", + "isEnabled": true, + "rate": "162300000000000000000" + }, + "out": { + "capacity": "655500000000000000000000", + "isEnabled": true, + "rate": "131100000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "561000000000000000000000", + "isEnabled": true, + "rate": "112200000000000000000" + }, + "out": { + "capacity": "894000000000000000000000", + "isEnabled": true, + "rate": "178800000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "829500000000000000000000", + "isEnabled": true, + "rate": "165900000000000000000" + }, + "out": { + "capacity": "519000000000000000000000", + "isEnabled": true, + "rate": "103800000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "997500000000000000000000", + "isEnabled": true, + "rate": "199500000000000000000" + }, + "out": { + "capacity": "981000000000000000000000", + "isEnabled": true, + "rate": "196200000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "861000000000000000000000", + "isEnabled": true, + "rate": "172200000000000000000" + }, + "out": { + "capacity": "933000000000000000000000", + "isEnabled": true, + "rate": "186600000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "852000000000000000000000", + "isEnabled": true, + "rate": "170400000000000000000" + }, + "out": { + "capacity": "751500000000000000000000", + "isEnabled": true, + "rate": "150300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "616500000000000000000000", + "isEnabled": true, + "rate": "123300000000000000000" + }, + "out": { + "capacity": "1006500000000000000000000", + "isEnabled": true, + "rate": "201300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "766500000000000000000000", + "isEnabled": true, + "rate": "153300000000000000000" + }, + "out": { + "capacity": "540000000000000000000000", + "isEnabled": true, + "rate": "108000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "541500000000000000000000", + "isEnabled": true, + "rate": "108300000000000000000" + }, + "out": { + "capacity": "708000000000000000000000", + "isEnabled": true, + "rate": "141600000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + } + } + }, + "plasma-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "574500000000000000000000", + "isEnabled": true, + "rate": "114900000000000000000" + }, + "out": { + "capacity": "583500000000000000000000", + "isEnabled": true, + "rate": "116700000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "936000000000000000000000", + "isEnabled": true, + "rate": "187200000000000000000" + }, + "out": { + "capacity": "487500000000000000000000", + "isEnabled": true, + "rate": "97500000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "846000000000000000000000", + "isEnabled": true, + "rate": "169200000000000000000" + }, + "out": { + "capacity": "783000000000000000000000", + "isEnabled": true, + "rate": "156600000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "865500000000000000000000", + "isEnabled": true, + "rate": "173100000000000000000" + }, + "out": { + "capacity": "951000000000000000000000", + "isEnabled": true, + "rate": "190200000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "642000000000000000000000", + "isEnabled": true, + "rate": "128400000000000000000" + }, + "out": { + "capacity": "604500000000000000000000", + "isEnabled": true, + "rate": "120900000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + } + } + }, + "xdai-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "847500000000000000000000", + "isEnabled": true, + "rate": "169500000000000000000" + }, + "out": { + "capacity": "1026000000000000000000000", + "isEnabled": true, + "rate": "205200000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "654000000000000000000000", + "isEnabled": true, + "rate": "130800000000000000000" + }, + "out": { + "capacity": "492000000000000000000000", + "isEnabled": true, + "rate": "98400000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "666000000000000000000000", + "isEnabled": true, + "rate": "133200000000000000000" + }, + "out": { + "capacity": "642000000000000000000000", + "isEnabled": true, + "rate": "128400000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "478500000000000000000000", + "isEnabled": true, + "rate": "95700000000000000000" + }, + "out": { + "capacity": "508500000000000000000000", + "isEnabled": true, + "rate": "101700000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "808500000000000000000000", + "isEnabled": true, + "rate": "161700000000000000000" + }, + "out": { + "capacity": "525000000000000000000000", + "isEnabled": true, + "rate": "105000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "822000000000000000000000", + "isEnabled": true, + "rate": "164400000000000000000" + }, + "out": { + "capacity": "924000000000000000000000", + "isEnabled": true, + "rate": "184800000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "300000000000000000000" + } + } + } + } + } + }, + "GRT": { + "avalanche-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "302000000000000000000000", + "isEnabled": true, + "rate": "3495370369140000000" + }, + "out": { + "capacity": "587000000000000000000000", + "isEnabled": true, + "rate": "6793981479090000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11574074070000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11574074070000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "554000000000000000000000", + "isEnabled": true, + "rate": "6412037034780000000" + }, + "out": { + "capacity": "534000000000000000000000", + "isEnabled": true, + "rate": "6180555553380000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11574074070000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11574074070000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "316000000000000000000000", + "isEnabled": true, + "rate": "3657407406120000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "5787037035000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11574074070000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11574074070000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "611000000000000000000000", + "isEnabled": true, + "rate": "7071759256770000000" + }, + "out": { + "capacity": "466000000000000000000000", + "isEnabled": true, + "rate": "5393518516620000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11574074070000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11574074070000000000" + } + } + } + } + } + }, + "hyETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "15120000000000000000", + "isEnabled": true, + "rate": "1080000000000000" + }, + "out": { + "capacity": "16436000000000000000", + "isEnabled": true, + "rate": "1174000000000000" + } + }, + "standard": { + "in": { + "capacity": "28000000000000000000", + "isEnabled": true, + "rate": "2000000000000000" + }, + "out": { + "capacity": "28000000000000000000", + "isEnabled": true, + "rate": "2000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "272000000000000000000", + "isEnabled": true, + "rate": "18876800000000000" + }, + "out": { + "capacity": "189000000000000000000", + "isEnabled": true, + "rate": "13116600000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000", + "isEnabled": true, + "rate": "34700000000000000" + }, + "out": { + "capacity": "500000000000000000000", + "isEnabled": true, + "rate": "34700000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "10612000000000000000", + "isEnabled": true, + "rate": "758000000000000" + }, + "out": { + "capacity": "13692000000000000000", + "isEnabled": true, + "rate": "978000000000000" + } + }, + "standard": { + "in": { + "capacity": "28000000000000000000", + "isEnabled": true, + "rate": "2000000000000000" + }, + "out": { + "capacity": "28000000000000000000", + "isEnabled": true, + "rate": "2000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "11452000000000000000", + "isEnabled": true, + "rate": "818000000000000" + }, + "out": { + "capacity": "12572000000000000000", + "isEnabled": true, + "rate": "898000000000000" + } + }, + "standard": { + "in": { + "capacity": "28000000000000000000", + "isEnabled": true, + "rate": "2000000000000000" + }, + "out": { + "capacity": "28000000000000000000", + "isEnabled": true, + "rate": "2000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": null, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + } + } + } + }, + "IBTC": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "189450000", + "isEnabled": true, + "rate": "35069" + }, + "out": { + "capacity": "266400000", + "isEnabled": true, + "rate": "49313" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "210150000", + "isEnabled": true, + "rate": "38901" + }, + "out": { + "capacity": "135900000", + "isEnabled": true, + "rate": "25156" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "202050000", + "isEnabled": true, + "rate": "37401" + }, + "out": { + "capacity": "184950000", + "isEnabled": true, + "rate": "34236" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "225450000", + "isEnabled": true, + "rate": "41733" + }, + "out": { + "capacity": "265050000", + "isEnabled": true, + "rate": "49063" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "243450000", + "isEnabled": true, + "rate": "45065" + }, + "out": { + "capacity": "266850000", + "isEnabled": true, + "rate": "49396" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "267300000", + "isEnabled": true, + "rate": "49480" + }, + "out": { + "capacity": "204300000", + "isEnabled": true, + "rate": "37818" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "220950000", + "isEnabled": true, + "rate": "40900" + }, + "out": { + "capacity": "170100000", + "isEnabled": true, + "rate": "31487" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "264600000", + "isEnabled": true, + "rate": "48980" + }, + "out": { + "capacity": "156150000", + "isEnabled": true, + "rate": "28905" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "295650000", + "isEnabled": true, + "rate": "54728" + }, + "out": { + "capacity": "173250000", + "isEnabled": true, + "rate": "32070" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "231750000", + "isEnabled": true, + "rate": "42899" + }, + "out": { + "capacity": "278100000", + "isEnabled": true, + "rate": "51479" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "167400000", + "isEnabled": true, + "rate": "30987" + }, + "out": { + "capacity": "234900000", + "isEnabled": true, + "rate": "43482" + } + }, + "standard": { + "in": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + }, + "out": { + "capacity": "450000000", + "isEnabled": true, + "rate": "83300" + } + } + } + } + } + }, + "ILMT": { + "bsc-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "447000000000000", + "isEnabled": true, + "rate": "124166666666" + }, + "out": { + "capacity": "6390000000000000000000000", + "isEnabled": true, + "rate": "1775000000001420000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000", + "isEnabled": true, + "rate": "277777777778" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "2777777777780000000000" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "531000000000000", + "isEnabled": true, + "rate": "147500000000" + }, + "out": { + "capacity": "671000000000000", + "isEnabled": true, + "rate": "186388888889" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000", + "isEnabled": true, + "rate": "277777777778" + }, + "out": { + "capacity": "1000000000000000", + "isEnabled": true, + "rate": "277777777778" + } + } + } + } + } + }, + "IXT": { + "bsc-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "JASMY": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "2120000000000000000000000", + "isEnabled": true, + "rate": "588888851200000000000" + }, + "out": { + "capacity": "3280000000000000000000000", + "isEnabled": true, + "rate": "911111052800000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "1388888800000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "1388888800000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "2380000000000000000000000", + "isEnabled": true, + "rate": "661111068800000000000" + }, + "out": { + "capacity": "2335000000000000000000000", + "isEnabled": true, + "rate": "648611069600000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "1388888800000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "1388888800000000000000" + } + } + } + } + } + }, + "JCT": { + "bsc-mainnet": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "kHYPE": { + "hyperliquid-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "KNET": { + "bsc-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "LAND": { + "bsc-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "10520000000000000000000", + "isEnabled": true, + "rate": "2919300000000000000" + }, + "out": { + "capacity": "6600000000000000000000", + "isEnabled": true, + "rate": "1831500000000000000" + } + }, + "standard": { + "in": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + }, + "out": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "9640000000000000000000", + "isEnabled": true, + "rate": "2675100000000000000" + }, + "out": { + "capacity": "12320000000000000000000", + "isEnabled": true, + "rate": "3418800000000000000" + } + }, + "standard": { + "in": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + }, + "out": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "10140000000000000000000", + "isEnabled": true, + "rate": "2813850000000000000" + }, + "out": { + "capacity": "13840000000000000000000", + "isEnabled": true, + "rate": "3840600000000000000" + } + }, + "standard": { + "in": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + }, + "out": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "11620000000000000000000", + "isEnabled": true, + "rate": "3224550000000000000" + }, + "out": { + "capacity": "10340000000000000000000", + "isEnabled": true, + "rate": "2869350000000000000" + } + }, + "standard": { + "in": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + }, + "out": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "6660000000000000000000", + "isEnabled": true, + "rate": "1848150000000000000" + }, + "out": { + "capacity": "10280000000000000000000", + "isEnabled": true, + "rate": "2852700000000000000" + } + }, + "standard": { + "in": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + }, + "out": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "10060000000000000000000", + "isEnabled": true, + "rate": "2791650000000000000" + }, + "out": { + "capacity": "13040000000000000000000", + "isEnabled": true, + "rate": "3618600000000000000" + } + }, + "standard": { + "in": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + }, + "out": { + "capacity": "20000000000000000000000", + "isEnabled": true, + "rate": "5550000000000000000" + } + } + } + } + } + }, + "LBTC": { + "avalanche-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "2605000000", + "isEnabled": true, + "rate": "241203" + }, + "out": { + "capacity": "2145000000", + "isEnabled": true, + "rate": "198611" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1880000000", + "isEnabled": true, + "rate": "174074" + }, + "out": { + "capacity": "1795000000", + "isEnabled": true, + "rate": "166203" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "2080000000", + "isEnabled": true, + "rate": "192592" + }, + "out": { + "capacity": "2305000000", + "isEnabled": true, + "rate": "213425" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "2890000000", + "isEnabled": true, + "rate": "267592" + }, + "out": { + "capacity": "3255000000", + "isEnabled": true, + "rate": "301388" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "polygon-mainnet-katana": { + "custom": { + "in": { + "capacity": "2975000000", + "isEnabled": true, + "rate": "275462" + }, + "out": { + "capacity": "1780000000", + "isEnabled": true, + "rate": "164814" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1980000000", + "isEnabled": true, + "rate": "183333" + }, + "out": { + "capacity": "3430000000", + "isEnabled": true, + "rate": "317592" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "stable-mainnet": { + "custom": { + "in": { + "capacity": "3350000000", + "isEnabled": true, + "rate": "310185" + }, + "out": { + "capacity": "2880000000", + "isEnabled": true, + "rate": "266666" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "berachain-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "3165000000", + "isEnabled": true, + "rate": "293055" + }, + "out": { + "capacity": "2425000000", + "isEnabled": true, + "rate": "224537" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "3420000000", + "isEnabled": true, + "rate": "316666" + }, + "out": { + "capacity": "1690000000", + "isEnabled": true, + "rate": "156481" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "2305000000", + "isEnabled": true, + "rate": "213425" + }, + "out": { + "capacity": "1710000000", + "isEnabled": true, + "rate": "158333" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "3140000000", + "isEnabled": true, + "rate": "290740" + }, + "out": { + "capacity": "1505000000", + "isEnabled": true, + "rate": "139351" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "polygon-mainnet-katana": { + "custom": { + "in": { + "capacity": "2775000000", + "isEnabled": true, + "rate": "256944" + }, + "out": { + "capacity": "1885000000", + "isEnabled": true, + "rate": "174537" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "3170000000", + "isEnabled": true, + "rate": "293518" + }, + "out": { + "capacity": "2445000000", + "isEnabled": true, + "rate": "226388" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "stable-mainnet": { + "custom": { + "in": { + "capacity": "2585000000", + "isEnabled": true, + "rate": "239351" + }, + "out": { + "capacity": "2665000000", + "isEnabled": true, + "rate": "246759" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "corn-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "2040000000", + "isEnabled": true, + "rate": "188888" + }, + "out": { + "capacity": "1550000000", + "isEnabled": true, + "rate": "143518" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1835000000", + "isEnabled": true, + "rate": "169907" + }, + "out": { + "capacity": "2040000000", + "isEnabled": true, + "rate": "188888" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "bsc-mainnet": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": null, + "standard": null + }, + "monad-mainnet": { + "custom": null, + "standard": null + }, + "polygon-mainnet-katana": { + "custom": null, + "standard": null + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "2840000000", + "isEnabled": true, + "rate": "262962" + }, + "out": { + "capacity": "1800000000", + "isEnabled": true, + "rate": "166666" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "stable-mainnet": { + "custom": null, + "standard": null + } + } + }, + "etherlink-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1515000000", + "isEnabled": true, + "rate": "140277" + }, + "out": { + "capacity": "2630000000", + "isEnabled": true, + "rate": "243518" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "2730000000", + "isEnabled": true, + "rate": "252777" + }, + "out": { + "capacity": "2345000000", + "isEnabled": true, + "rate": "217129" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "2095000000", + "isEnabled": true, + "rate": "193981" + }, + "out": { + "capacity": "2805000000", + "isEnabled": true, + "rate": "259722" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1555000000", + "isEnabled": true, + "rate": "143981" + }, + "out": { + "capacity": "2600000000", + "isEnabled": true, + "rate": "240740" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "corn-mainnet": { + "custom": { + "in": { + "capacity": "2240000000", + "isEnabled": true, + "rate": "207407" + }, + "out": { + "capacity": "1695000000", + "isEnabled": true, + "rate": "156944" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "2820000000", + "isEnabled": true, + "rate": "261111" + }, + "out": { + "capacity": "3490000000", + "isEnabled": true, + "rate": "323148" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "etherlink-mainnet": { + "custom": { + "in": { + "capacity": "3260000000", + "isEnabled": true, + "rate": "301851" + }, + "out": { + "capacity": "1590000000", + "isEnabled": true, + "rate": "147222" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "1705000000", + "isEnabled": true, + "rate": "157870" + }, + "out": { + "capacity": "2200000000", + "isEnabled": true, + "rate": "203703" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "polygon-mainnet-katana": { + "custom": { + "in": { + "capacity": "2975000000", + "isEnabled": true, + "rate": "275462" + }, + "out": { + "capacity": "3015000000", + "isEnabled": true, + "rate": "279166" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "2530000000", + "isEnabled": true, + "rate": "234259" + }, + "out": { + "capacity": "3130000000", + "isEnabled": true, + "rate": "289814" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "stable-mainnet": { + "custom": null, + "standard": null + }, + "tac-mainnet": { + "custom": { + "in": { + "capacity": "2700000000", + "isEnabled": true, + "rate": "250000" + }, + "out": { + "capacity": "2595000000", + "isEnabled": true, + "rate": "240277" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "monad-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "2085000000", + "isEnabled": true, + "rate": "193055" + }, + "out": { + "capacity": "3255000000", + "isEnabled": true, + "rate": "301388" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1740000000", + "isEnabled": true, + "rate": "161111" + }, + "out": { + "capacity": "3395000000", + "isEnabled": true, + "rate": "314351" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1655000000", + "isEnabled": true, + "rate": "153240" + }, + "out": { + "capacity": "1630000000", + "isEnabled": true, + "rate": "150925" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "2720000000", + "isEnabled": true, + "rate": "251851" + }, + "out": { + "capacity": "3260000000", + "isEnabled": true, + "rate": "301851" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "polygon-mainnet-katana": { + "custom": null, + "standard": null + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1910000000", + "isEnabled": true, + "rate": "176851" + }, + "out": { + "capacity": "1560000000", + "isEnabled": true, + "rate": "144444" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "polygon-mainnet-katana": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "2710000000", + "isEnabled": true, + "rate": "250925" + }, + "out": { + "capacity": "2365000000", + "isEnabled": true, + "rate": "218981" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "2535000000", + "isEnabled": true, + "rate": "234722" + }, + "out": { + "capacity": "3400000000", + "isEnabled": true, + "rate": "314814" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1850000000", + "isEnabled": true, + "rate": "171296" + }, + "out": { + "capacity": "2830000000", + "isEnabled": true, + "rate": "262037" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "2200000000", + "isEnabled": true, + "rate": "203703" + }, + "out": { + "capacity": "2695000000", + "isEnabled": true, + "rate": "249537" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "2745000000", + "isEnabled": true, + "rate": "254166" + }, + "out": { + "capacity": "3405000000", + "isEnabled": true, + "rate": "315277" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1615000000", + "isEnabled": true, + "rate": "149537" + }, + "out": { + "capacity": "3045000000", + "isEnabled": true, + "rate": "281944" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "stable-mainnet": { + "custom": { + "in": { + "capacity": "2195000000", + "isEnabled": true, + "rate": "203240" + }, + "out": { + "capacity": "3000000000", + "isEnabled": true, + "rate": "277777" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "2235000000", + "isEnabled": true, + "rate": "206944" + }, + "out": { + "capacity": "3220000000", + "isEnabled": true, + "rate": "298148" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "2855000000", + "isEnabled": true, + "rate": "264351" + }, + "out": { + "capacity": "3280000000", + "isEnabled": true, + "rate": "303703" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "2860000000", + "isEnabled": true, + "rate": "264814" + }, + "out": { + "capacity": "1525000000", + "isEnabled": true, + "rate": "141203" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1805000000", + "isEnabled": true, + "rate": "167129" + }, + "out": { + "capacity": "2605000000", + "isEnabled": true, + "rate": "241203" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "3260000000", + "isEnabled": true, + "rate": "301851" + }, + "out": { + "capacity": "1630000000", + "isEnabled": true, + "rate": "150925" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "polygon-mainnet-katana": { + "custom": { + "in": { + "capacity": "2250000000", + "isEnabled": true, + "rate": "208333" + }, + "out": { + "capacity": "3380000000", + "isEnabled": true, + "rate": "312962" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "stable-mainnet": { + "custom": { + "in": { + "capacity": "3230000000", + "isEnabled": true, + "rate": "299074" + }, + "out": { + "capacity": "2370000000", + "isEnabled": true, + "rate": "219444" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "stable-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1900000000", + "isEnabled": true, + "rate": "175925" + }, + "out": { + "capacity": "1950000000", + "isEnabled": true, + "rate": "180555" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "3115000000", + "isEnabled": true, + "rate": "288425" + }, + "out": { + "capacity": "1970000000", + "isEnabled": true, + "rate": "182407" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "2070000000", + "isEnabled": true, + "rate": "191666" + }, + "out": { + "capacity": "2325000000", + "isEnabled": true, + "rate": "215277" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + }, + "polygon-mainnet-katana": { + "custom": { + "in": { + "capacity": "1760000000", + "isEnabled": true, + "rate": "162962" + }, + "out": { + "capacity": "3205000000", + "isEnabled": true, + "rate": "296759" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "2255000000", + "isEnabled": true, + "rate": "208796" + }, + "out": { + "capacity": "1965000000", + "isEnabled": true, + "rate": "181944" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + }, + "tac-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "2475000000", + "isEnabled": true, + "rate": "229166" + }, + "out": { + "capacity": "1790000000", + "isEnabled": true, + "rate": "165740" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" + } + } + } + } + } + }, + "LDY": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1635000000000000000000000", + "isEnabled": true, + "rate": "18922400000000000000" + }, + "out": { + "capacity": "1113000000000000000000000", + "isEnabled": true, + "rate": "12881120000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1995000000000000000000000", + "isEnabled": true, + "rate": "23088800000000000000" + }, + "out": { + "capacity": "1224000000000000000000000", + "isEnabled": true, + "rate": "14165760000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1215000000000000000000000", + "isEnabled": true, + "rate": "14061600000000000000" + }, + "out": { + "capacity": "1647000000000000000000000", + "isEnabled": true, + "rate": "19061280000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1101000000000000000000000", + "isEnabled": true, + "rate": "12742240000000000000" + }, + "out": { + "capacity": "1644000000000000000000000", + "isEnabled": true, + "rate": "19026560000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1812000000000000000000000", + "isEnabled": true, + "rate": "20970880000000000000" + }, + "out": { + "capacity": "1185000000000000000000000", + "isEnabled": true, + "rate": "13714400000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1260000000000000000000000", + "isEnabled": true, + "rate": "14582400000000000000" + }, + "out": { + "capacity": "1119000000000000000000000", + "isEnabled": true, + "rate": "12950560000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000" + } + } + } + } + } + }, + "LEASH": { + "avalanche-mainnet": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "celo-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-andromeda-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-blast-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-mantle-1": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-mode-1": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-scroll-1": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-zircuit-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-zksync-1": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "celo-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-andromeda-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-blast-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-mantle-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-scroll-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-zircuit-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polkadot-mainnet-astar": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "polkadot-mainnet-astar": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "wemix-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "xdai-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "LEND": { + "avalanche-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "LINK": { + "0g-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ab-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "aptos-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "3135000000000", + "isEnabled": true, + "rate": "870276000" + }, + "out": { + "capacity": "1990000000000", + "isEnabled": true, + "rate": "552424000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388000000" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1595000000000", + "isEnabled": true, + "rate": "442772000" + }, + "out": { + "capacity": "1945000000000", + "isEnabled": true, + "rate": "539932000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388000000" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1885000000000", + "isEnabled": true, + "rate": "523276000" + }, + "out": { + "capacity": "3380000000000", + "isEnabled": true, + "rate": "938288000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388000000" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388000000" + } + } + } + } + }, + "celo-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "19350000000000000000000", + "isEnabled": true, + "rate": "5371560000000000000" + }, + "out": { + "capacity": "32800000000000000000000", + "isEnabled": true, + "rate": "9105280000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + } + } + }, + "ethereum-mainnet-andromeda-1": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "32600000000000000000000", + "isEnabled": true, + "rate": "9049760000000000000" + }, + "out": { + "capacity": "29850000000000000000000", + "isEnabled": true, + "rate": "8286360000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "aptos-mainnet": { + "custom": { + "in": { + "capacity": "2285000000000", + "isEnabled": true, + "rate": "634316000" + }, + "out": { + "capacity": "15550000000000000000000", + "isEnabled": true, + "rate": "4316680000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "ethereum-mainnet-blast-1": { + "custom": { + "in": { + "capacity": "17150000000000000000000", + "isEnabled": true, + "rate": "4760840000000000000" + }, + "out": { + "capacity": "19500000000000000000000", + "isEnabled": true, + "rate": "5413200000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "16550000000000000000000", + "isEnabled": true, + "rate": "4594280000000000000" + }, + "out": { + "capacity": "25850000000000000000000", + "isEnabled": true, + "rate": "7175960000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "24950000000000000000000", + "isEnabled": true, + "rate": "6926120000000000000" + }, + "out": { + "capacity": "20300000000000000000000", + "isEnabled": true, + "rate": "5635280000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "ronin-mainnet": { + "custom": null, + "standard": null + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "19850000000000", + "isEnabled": true, + "rate": "5510360000" + }, + "out": { + "capacity": "17550000000000000000000", + "isEnabled": true, + "rate": "4871880000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000", + "isEnabled": true, + "rate": "13880000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + } + } + }, + "ethereum-mainnet-blast-1": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "30850000000000000000000", + "isEnabled": true, + "rate": "8563960000000000000" + }, + "out": { + "capacity": "28350000000000000000000", + "isEnabled": true, + "rate": "7869960000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "16100000000000000000000", + "isEnabled": true, + "rate": "4469360000000000000" + }, + "out": { + "capacity": "16150000000000000000000", + "isEnabled": true, + "rate": "4483240000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + } + } + }, + "ethereum-mainnet-mode-1": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "26750000000000000000000", + "isEnabled": true, + "rate": "7425800000000000000" + }, + "out": { + "capacity": "27100000000000000000000", + "isEnabled": true, + "rate": "7522960000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "30600000000000000000000", + "isEnabled": true, + "rate": "8494560000000000000" + }, + "out": { + "capacity": "25200000000000000000000", + "isEnabled": true, + "rate": "6995520000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + } + } + }, + "ethereum-mainnet-scroll-1": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "28600000000000000000000", + "isEnabled": true, + "rate": "7939360000000000000" + }, + "out": { + "capacity": "25950000000000000000000", + "isEnabled": true, + "rate": "7203720000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + } + } + }, + "ethereum-mainnet-zksync-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "19800000000000000000000", + "isEnabled": true, + "rate": "5496480000000000000" + }, + "out": { + "capacity": "24400000000000000000000", + "isEnabled": true, + "rate": "6773440000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + } + } + }, + "jovay-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "0g-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ab-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "aptos-mainnet": { + "custom": { + "in": { + "capacity": "1710000000000", + "isEnabled": true, + "rate": "474696000" + }, + "out": { + "capacity": "22100000000000000000000", + "isEnabled": true, + "rate": "6134960000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "celo-mainnet": { + "custom": { + "in": { + "capacity": "19600000000000000000000", + "isEnabled": true, + "rate": "5440960000000000000" + }, + "out": { + "capacity": "26250000000000000000000", + "isEnabled": true, + "rate": "7287000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "ethereum-mainnet-andromeda-1": { + "custom": { + "in": { + "capacity": "17050000000000000000000", + "isEnabled": true, + "rate": "4733080000000000000" + }, + "out": { + "capacity": "29900000000000000000000", + "isEnabled": true, + "rate": "8300240000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "33650000000000000000000", + "isEnabled": true, + "rate": "9341240000000000000" + }, + "out": { + "capacity": "24250000000000000000000", + "isEnabled": true, + "rate": "6731800000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "ethereum-mainnet-blast-1": { + "custom": { + "in": { + "capacity": "23700000000000000000000", + "isEnabled": true, + "rate": "6579120000000000000" + }, + "out": { + "capacity": "32350000000000000000000", + "isEnabled": true, + "rate": "8980360000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "16950000000000000000000", + "isEnabled": true, + "rate": "4705320000000000000" + }, + "out": { + "capacity": "22950000000000000000000", + "isEnabled": true, + "rate": "6370920000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "ethereum-mainnet-scroll-1": { + "custom": { + "in": { + "capacity": "25500000000000000000000", + "isEnabled": true, + "rate": "7078800000000000000" + }, + "out": { + "capacity": "28350000000000000000000", + "isEnabled": true, + "rate": "7869960000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "20150000000000000000000", + "isEnabled": true, + "rate": "5593640000000000000" + }, + "out": { + "capacity": "20500000000000000000000", + "isEnabled": true, + "rate": "5690800000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "jovay-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "morph-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polkadot-mainnet-astar": { + "custom": { + "in": { + "capacity": "31900000000000000000000", + "isEnabled": true, + "rate": "2953940000000000000" + }, + "out": { + "capacity": "28450000000000000000000", + "isEnabled": true, + "rate": "2634470000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + }, + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "22800000000000000000000", + "isEnabled": true, + "rate": "2111280000000000000" + }, + "out": { + "capacity": "25550000000000000000000", + "isEnabled": true, + "rate": "2365930000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "17550000000000", + "isEnabled": true, + "rate": "4871880000" + }, + "out": { + "capacity": "21750000000000000000000", + "isEnabled": true, + "rate": "6037800000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000", + "isEnabled": true, + "rate": "13880000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "31350000000000000000000", + "isEnabled": true, + "rate": "2903010000000000000" + }, + "out": { + "capacity": "30600000000000000000000", + "isEnabled": true, + "rate": "2833560000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "16250000000000000000000", + "isEnabled": true, + "rate": "1504750000000000000" + }, + "out": { + "capacity": "27450000000000000000000", + "isEnabled": true, + "rate": "2541870000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + }, + "stable-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "tac-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "19200000000000000000000", + "isEnabled": true, + "rate": "1777920000000000000" + }, + "out": { + "capacity": "33900000000000000000000", + "isEnabled": true, + "rate": "3139140000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + }, + "xdc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "morph-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "plasma-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "polkadot-mainnet-astar": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "21200000000000000000000", + "isEnabled": true, + "rate": "1963120000000000000" + }, + "out": { + "capacity": "26600000000000000000000", + "isEnabled": true, + "rate": "2463160000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "23850000000000000000000", + "isEnabled": true, + "rate": "2208510000000000000" + }, + "out": { + "capacity": "18600000000000000000000", + "isEnabled": true, + "rate": "1722360000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "28450000000000000000000", + "isEnabled": true, + "rate": "2634470000000000000" + }, + "out": { + "capacity": "27350000000000000000000", + "isEnabled": true, + "rate": "2532610000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "33250000000000000000000", + "isEnabled": true, + "rate": "3078950000000000000" + }, + "out": { + "capacity": "23750000000000000000000", + "isEnabled": true, + "rate": "2199250000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "21100000000000", + "isEnabled": true, + "rate": "5857360000" + }, + "out": { + "capacity": "20750000000000", + "isEnabled": true, + "rate": "5760200000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000", + "isEnabled": true, + "rate": "13880000000" + }, + "out": { + "capacity": "50000000000000", + "isEnabled": true, + "rate": "13880000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "25300000000000", + "isEnabled": true, + "rate": "7023280000" + }, + "out": { + "capacity": "30700000000000", + "isEnabled": true, + "rate": "8522320000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000", + "isEnabled": true, + "rate": "13880000000" + }, + "out": { + "capacity": "50000000000000", + "isEnabled": true, + "rate": "13880000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "18300000000000", + "isEnabled": true, + "rate": "5080080000" + }, + "out": { + "capacity": "26100000000000", + "isEnabled": true, + "rate": "7245360000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000", + "isEnabled": true, + "rate": "13880000000" + }, + "out": { + "capacity": "50000000000000", + "isEnabled": true, + "rate": "13880000000" + } + } + } + } + }, + "soneium-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "28800000000000000000000", + "isEnabled": true, + "rate": "2666880000000000000" + }, + "out": { + "capacity": "18050000000000000000000", + "isEnabled": true, + "rate": "1671430000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + }, + "polkadot-mainnet-astar": { + "custom": { + "in": { + "capacity": "18250000000000000000000", + "isEnabled": true, + "rate": "1689950000000000000" + }, + "out": { + "capacity": "19350000000000000000000", + "isEnabled": true, + "rate": "1791810000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "aptos-mainnet": { + "custom": { + "in": { + "capacity": "2045000000000", + "isEnabled": true, + "rate": "567692000" + }, + "out": { + "capacity": "21000000000000000000000", + "isEnabled": true, + "rate": "5829600000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "22300000000000000000000", + "isEnabled": true, + "rate": "2064980000000000000" + }, + "out": { + "capacity": "16200000000000000000000", + "isEnabled": true, + "rate": "1500120000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "19650000000000", + "isEnabled": true, + "rate": "5454840000" + }, + "out": { + "capacity": "17400000000000000000000", + "isEnabled": true, + "rate": "4830240000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000", + "isEnabled": true, + "rate": "13880000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "13880000000000000000" + } + } + } + } + }, + "stable-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "tac-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "wemix-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "32900000000000000000000", + "isEnabled": true, + "rate": "3046540000000000000" + }, + "out": { + "capacity": "29200000000000000000000", + "isEnabled": true, + "rate": "2703920000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "4630000000000000000" + } + } + } + } + }, + "xdc-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "LsETH": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "LUA": { + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "LUAUSD": { + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "LUISA": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "LYP": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "matic-mainnet": { + "custom": { + "in": { + "capacity": "15100000000000000000000", + "isEnabled": true, + "rate": "25166666666656600000" + }, + "out": { + "capacity": "19000000000000000000000", + "isEnabled": true, + "rate": "31666666666654000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "83333333333300000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "83333333333300000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "19450000000000000000000", + "isEnabled": true, + "rate": "32416666666653700000" + }, + "out": { + "capacity": "20450000000000000000000", + "isEnabled": true, + "rate": "34083333333319700000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "83333333333300000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "83333333333300000000" + } + } + } + } + } + }, + "mBTC": { + "bsc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "194000000", + "isEnabled": true, + "rate": "8981" + }, + "out": { + "capacity": "164800000", + "isEnabled": true, + "rate": "7629" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "170000000", + "isEnabled": true, + "rate": "7870" + }, + "out": { + "capacity": "213200000", + "isEnabled": true, + "rate": "9870" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "250400000", + "isEnabled": true, + "rate": "11592" + }, + "out": { + "capacity": "235200000", + "isEnabled": true, + "rate": "10888" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + }, + "ethereum-mainnet-zircuit-1": { + "custom": { + "in": { + "capacity": "222000000", + "isEnabled": true, + "rate": "10277" + }, + "out": { + "capacity": "122000000", + "isEnabled": true, + "rate": "5647" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "161600000", + "isEnabled": true, + "rate": "7481" + }, + "out": { + "capacity": "195200000", + "isEnabled": true, + "rate": "9036" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "132800000", + "isEnabled": true, + "rate": "6147" + }, + "out": { + "capacity": "228400000", + "isEnabled": true, + "rate": "10573" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + } + } + }, + "ethereum-mainnet-zircuit-1": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "246000000", + "isEnabled": true, + "rate": "11388" + }, + "out": { + "capacity": "267600000", + "isEnabled": true, + "rate": "12388" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "208400000", + "isEnabled": true, + "rate": "9647" + }, + "out": { + "capacity": "234800000", + "isEnabled": true, + "rate": "10870" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "132800000", + "isEnabled": true, + "rate": "6147" + }, + "out": { + "capacity": "266000000", + "isEnabled": true, + "rate": "12314" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + }, + "ethereum-mainnet-zircuit-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "157600000", + "isEnabled": true, + "rate": "7296" + }, + "out": { + "capacity": "135600000", + "isEnabled": true, + "rate": "6277" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "244800000", + "isEnabled": true, + "rate": "11333" + }, + "out": { + "capacity": "263200000", + "isEnabled": true, + "rate": "12184" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "136400000", + "isEnabled": true, + "rate": "6314" + }, + "out": { + "capacity": "214400000", + "isEnabled": true, + "rate": "9925" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "154800000", + "isEnabled": true, + "rate": "7166" + }, + "out": { + "capacity": "155200000", + "isEnabled": true, + "rate": "7184" + } + }, + "standard": { + "in": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + }, + "out": { + "capacity": "400000000", + "isEnabled": true, + "rate": "18518" + } + } + } + } + } + }, + "mDLP": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "280800000000000000000000", + "isEnabled": true, + "rate": "3246750000000000000" + }, + "out": { + "capacity": "187616000000000000000000", + "isEnabled": true, + "rate": "2169310000000000000" + } + }, + "standard": { + "in": { + "capacity": "416000000000000000000000", + "isEnabled": true, + "rate": "4810000000000000000" + }, + "out": { + "capacity": "416000000000000000000000", + "isEnabled": true, + "rate": "4810000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "279968000000000000000000", + "isEnabled": true, + "rate": "3237130000000000000" + }, + "out": { + "capacity": "173472000000000000000000", + "isEnabled": true, + "rate": "2005770000000000000" + } + }, + "standard": { + "in": { + "capacity": "416000000000000000000000", + "isEnabled": true, + "rate": "4810000000000000000" + }, + "out": { + "capacity": "416000000000000000000000", + "isEnabled": true, + "rate": "4810000000000000000" + } + } + } + } + } + }, + "MEEM": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "6120000000000000000000", + "isEnabled": true, + "rate": "1701360000000000000" + }, + "out": { + "capacity": "4140000000000000000000", + "isEnabled": true, + "rate": "1150920000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "2780000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "2780000000000000000" + } + } + } + } + } + }, + "Memento": { + "avalanche-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "300000000000000000000", + "isEnabled": true, + "rate": "3472200000000000" + }, + "out": { + "capacity": "356000000000000000000", + "isEnabled": true, + "rate": "4120344000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "433400000000000000000", + "isEnabled": true, + "rate": "5016203514000000" + }, + "out": { + "capacity": "452000000000000000000", + "isEnabled": true, + "rate": "5231448000000000" + } + }, + "standard": { + "in": { + "capacity": "1100000000000000000000", + "isEnabled": true, + "rate": "12731481000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "729300000000000000000", + "isEnabled": true, + "rate": "8440971903000000" + }, + "out": { + "capacity": "344000000000000000000", + "isEnabled": true, + "rate": "3981456000000000" + } + }, + "standard": { + "in": { + "capacity": "1100000000000000000000", + "isEnabled": true, + "rate": "12731481000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "742500000000000000000", + "isEnabled": true, + "rate": "8593749675000000" + }, + "out": { + "capacity": "478000000000000000000", + "isEnabled": true, + "rate": "5532372000000000" + } + }, + "standard": { + "in": { + "capacity": "1100000000000000000000", + "isEnabled": true, + "rate": "12731481000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "33275000000000000000000", + "isEnabled": true, + "rate": "385127314770000000" + }, + "out": { + "capacity": "18950000000000000000000", + "isEnabled": true, + "rate": "219328703816000000" + } + }, + "standard": { + "in": { + "capacity": "55000000000000000000000", + "isEnabled": true, + "rate": "636574074000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "578703704000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "701800000000000000000", + "isEnabled": true, + "rate": "8122684878000000" + }, + "out": { + "capacity": "674000000000000000000", + "isEnabled": true, + "rate": "7800876000000000" + } + }, + "standard": { + "in": { + "capacity": "1100000000000000000000", + "isEnabled": true, + "rate": "12731481000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "437800000000000000000", + "isEnabled": true, + "rate": "5067129438000000" + }, + "out": { + "capacity": "659000000000000000000", + "isEnabled": true, + "rate": "7627266000000000" + } + }, + "standard": { + "in": { + "capacity": "1100000000000000000000", + "isEnabled": true, + "rate": "12731481000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "19635000000000000000000", + "isEnabled": true, + "rate": "227256944418000000" + }, + "out": { + "capacity": "20650000000000000000000", + "isEnabled": true, + "rate": "239004629752000000" + } + }, + "standard": { + "in": { + "capacity": "55000000000000000000000", + "isEnabled": true, + "rate": "636574074000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "578703704000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "672100000000000000000", + "isEnabled": true, + "rate": "7778934891000000" + }, + "out": { + "capacity": "572000000000000000000", + "isEnabled": true, + "rate": "6620328000000000" + } + }, + "standard": { + "in": { + "capacity": "1100000000000000000000", + "isEnabled": true, + "rate": "12731481000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "730400000000000000000", + "isEnabled": true, + "rate": "8453703384000000" + }, + "out": { + "capacity": "483000000000000000000", + "isEnabled": true, + "rate": "5590242000000000" + } + }, + "standard": { + "in": { + "capacity": "1100000000000000000000", + "isEnabled": true, + "rate": "12731481000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "695200000000000000000", + "isEnabled": true, + "rate": "8046295992000000" + }, + "out": { + "capacity": "415000000000000000000", + "isEnabled": true, + "rate": "4803210000000000" + } + }, + "standard": { + "in": { + "capacity": "1100000000000000000000", + "isEnabled": true, + "rate": "12731481000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "499400000000000000000", + "isEnabled": true, + "rate": "5780092374000000" + }, + "out": { + "capacity": "615000000000000000000", + "isEnabled": true, + "rate": "7118010000000000" + } + }, + "standard": { + "in": { + "capacity": "1100000000000000000000", + "isEnabled": true, + "rate": "12731481000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574000000000000" + } + } + } + } + } + }, + "METO": { + "bsc-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "matic-mainnet": { + "custom": { + "in": { + "capacity": "46307692354000000000000000", + "isEnabled": true, + "rate": "12863247040000000000000" + }, + "out": { + "capacity": "31000000031000000000000000", + "isEnabled": true, + "rate": "8611110560000000000000" + } + }, + "standard": { + "in": { + "capacity": "76923077000000000000000000", + "isEnabled": true, + "rate": "21367520000000000000000" + }, + "out": { + "capacity": "76923077000000000000000000", + "isEnabled": true, + "rate": "21367520000000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "38692307731000000000000000", + "isEnabled": true, + "rate": "10747862560000000000000" + }, + "out": { + "capacity": "35846153882000000000000000", + "isEnabled": true, + "rate": "9957264320000000000000" + } + }, + "standard": { + "in": { + "capacity": "76923077000000000000000000", + "isEnabled": true, + "rate": "21367520000000000000000" + }, + "out": { + "capacity": "76923077000000000000000000", + "isEnabled": true, + "rate": "21367520000000000000000" + } + } + } + } + } + }, + "MEW": { + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1610000000000", + "isEnabled": true, + "rate": "447222221" + }, + "out": { + "capacity": "2315000000000", + "isEnabled": true, + "rate": "643055555" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 2, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1980000000000", + "isEnabled": true, + "rate": "549999999" + }, + "out": { + "capacity": "2670000000000", + "isEnabled": true, + "rate": "741666666" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "2220000000000", + "isEnabled": true, + "rate": "616666666" + }, + "out": { + "capacity": "3005000000000", + "isEnabled": true, + "rate": "834722221" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "2045000000000", + "isEnabled": true, + "rate": "568055555" + }, + "out": { + "capacity": "2415000000000", + "isEnabled": true, + "rate": "670833332" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "3030000000000", + "isEnabled": true, + "rate": "841666666" + }, + "out": { + "capacity": "3415000000000", + "isEnabled": true, + "rate": "948611110" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "3310000000000", + "isEnabled": true, + "rate": "919444443" + }, + "out": { + "capacity": "3270000000000", + "isEnabled": true, + "rate": "908333332" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1980000000000", + "isEnabled": true, + "rate": "549999999" + }, + "out": { + "capacity": "2895000000000", + "isEnabled": true, + "rate": "804166666" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "3460000000000", + "isEnabled": true, + "rate": "961111110" + }, + "out": { + "capacity": "3345000000000", + "isEnabled": true, + "rate": "929166666" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "1388888888" + } + } + } + } + } + }, + "MICHI": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "5450000000000", + "isEnabled": true, + "rate": "42903609" + }, + "out": { + "capacity": "5870000000000", + "isEnabled": true, + "rate": "46209943" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "78722220" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "78722220" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "3680000000000", + "isEnabled": true, + "rate": "28969776" + }, + "out": { + "capacity": "4350000000000", + "isEnabled": true, + "rate": "34244165" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "78722220" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "78722220" + } + } + } + } + } + }, + "MILO": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "2430000000000000000000000", + "isEnabled": true, + "rate": "56249640000000000000" + }, + "out": { + "capacity": "3360000000000000000000000", + "isEnabled": true, + "rate": "77777280000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "115740000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "115740000000000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1560000000000000000000000", + "isEnabled": true, + "rate": "36110880000000000000" + }, + "out": { + "capacity": "2105000000000000000000000", + "isEnabled": true, + "rate": "48726540000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "115740000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "115740000000000000000" + } + } + } + } + } + }, + "mmETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "41300000000000000000", + "isEnabled": true, + "rate": "3824380000000000" + }, + "out": { + "capacity": "36600000000000000000", + "isEnabled": true, + "rate": "3389160000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "51800000000000000000", + "isEnabled": true, + "rate": "4796680000000000" + }, + "out": { + "capacity": "62000000000000000000", + "isEnabled": true, + "rate": "5741200000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + } + } + } + }, + "mstETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "62800000000000000000", + "isEnabled": true, + "rate": "5815280000000000" + }, + "out": { + "capacity": "30600000000000000000", + "isEnabled": true, + "rate": "2833560000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "69400000000000000000", + "isEnabled": true, + "rate": "6426440000000000" + }, + "out": { + "capacity": "40800000000000000000", + "isEnabled": true, + "rate": "3778080000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "54500000000000000000", + "isEnabled": true, + "rate": "5046700000000000" + }, + "out": { + "capacity": "64000000000000000000", + "isEnabled": true, + "rate": "5926400000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "42800000000000000000", + "isEnabled": true, + "rate": "3963280000000000" + }, + "out": { + "capacity": "57500000000000000000", + "isEnabled": true, + "rate": "5324500000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + } + } + } + }, + "mswETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "30700000000000000000", + "isEnabled": true, + "rate": "2842820000000000" + }, + "out": { + "capacity": "68700000000000000000", + "isEnabled": true, + "rate": "6361620000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "52800000000000000000", + "isEnabled": true, + "rate": "4889280000000000" + }, + "out": { + "capacity": "52000000000000000000", + "isEnabled": true, + "rate": "4815200000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "9260000000000000" + } + } + } + } + } + }, + "MVI": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "774367000000000000000", + "isEnabled": true, + "rate": "55760000000000000" + }, + "out": { + "capacity": "402182000000000000000", + "isEnabled": true, + "rate": "28960000000000000" + } + }, + "standard": { + "in": { + "capacity": "1111000000000000000000", + "isEnabled": true, + "rate": "80000000000000000" + }, + "out": { + "capacity": "1111000000000000000000", + "isEnabled": true, + "rate": "80000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "2203113000000000000000", + "isEnabled": true, + "rate": "152030000000000000" + }, + "out": { + "capacity": "1506516000000000000000", + "isEnabled": true, + "rate": "103960000000000000" + } + }, + "standard": { + "in": { + "capacity": "3333000000000000000000", + "isEnabled": true, + "rate": "230000000000000000" + }, + "out": { + "capacity": "3333000000000000000000", + "isEnabled": true, + "rate": "230000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "482174000000000000000", + "isEnabled": true, + "rate": "34720000000000000" + }, + "out": { + "capacity": "595496000000000000000", + "isEnabled": true, + "rate": "42880000000000000" + } + }, + "standard": { + "in": { + "capacity": "1111000000000000000000", + "isEnabled": true, + "rate": "80000000000000000" + }, + "out": { + "capacity": "1111000000000000000000", + "isEnabled": true, + "rate": "80000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "564388000000000000000", + "isEnabled": true, + "rate": "40640000000000000" + }, + "out": { + "capacity": "539946000000000000000", + "isEnabled": true, + "rate": "38880000000000000" + } + }, + "standard": { + "in": { + "capacity": "1111000000000000000000", + "isEnabled": true, + "rate": "80000000000000000" + }, + "out": { + "capacity": "1111000000000000000000", + "isEnabled": true, + "rate": "80000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1739826000000000000000", + "isEnabled": true, + "rate": "120060000000000000" + }, + "out": { + "capacity": "1566510000000000000000", + "isEnabled": true, + "rate": "108100000000000000" + } + }, + "standard": { + "in": { + "capacity": "3333000000000000000000", + "isEnabled": true, + "rate": "230000000000000000" + }, + "out": { + "capacity": "3333000000000000000000", + "isEnabled": true, + "rate": "230000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "586608000000000000000", + "isEnabled": true, + "rate": "42240000000000000" + }, + "out": { + "capacity": "553278000000000000000", + "isEnabled": true, + "rate": "39840000000000000" + } + }, + "standard": { + "in": { + "capacity": "1111000000000000000000", + "isEnabled": true, + "rate": "80000000000000000" + }, + "out": { + "capacity": "1111000000000000000000", + "isEnabled": true, + "rate": "80000000000000000" + } + } + } + } + } + }, + "mwBETH": { + "bsc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "336500000000000000000", + "isEnabled": true, + "rate": "30958000000000000" + }, + "out": { + "capacity": "262000000000000000000", + "isEnabled": true, + "rate": "24104000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000", + "isEnabled": true, + "rate": "46000000000000000" + }, + "out": { + "capacity": "500000000000000000000", + "isEnabled": true, + "rate": "46000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "329500000000000000000", + "isEnabled": true, + "rate": "30314000000000000" + }, + "out": { + "capacity": "211500000000000000000", + "isEnabled": true, + "rate": "19458000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000", + "isEnabled": true, + "rate": "46000000000000000" + }, + "out": { + "capacity": "500000000000000000000", + "isEnabled": true, + "rate": "46000000000000000" + } + } + } + } + } + }, + "MYST": { + "avalanche-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "NEIRO": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "NEKO": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "NPC": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "NUON": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "45700000000000000000000", + "isEnabled": true, + "rate": "25386350000000000000" + }, + "out": { + "capacity": "55300000000000000000000", + "isEnabled": true, + "rate": "30719150000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "44600000000000000000000", + "isEnabled": true, + "rate": "24775300000000000000" + }, + "out": { + "capacity": "42700000000000000000000", + "isEnabled": true, + "rate": "23719850000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "51000000000000000000000", + "isEnabled": true, + "rate": "28330500000000000000" + }, + "out": { + "capacity": "34800000000000000000000", + "isEnabled": true, + "rate": "19331400000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "55400000000000000000000", + "isEnabled": true, + "rate": "30774700000000000000" + }, + "out": { + "capacity": "58900000000000000000000", + "isEnabled": true, + "rate": "32718950000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "62000000000000000000000", + "isEnabled": true, + "rate": "34441000000000000000" + }, + "out": { + "capacity": "48300000000000000000000", + "isEnabled": true, + "rate": "26830650000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "54500000000000000000000", + "isEnabled": true, + "rate": "30274750000000000000" + }, + "out": { + "capacity": "45700000000000000000000", + "isEnabled": true, + "rate": "25386350000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + } + }, + "NXPC": { + "avalanche-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "OHM": { + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "ORNG": { + "avalanche-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "OSIS": { + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "matic-mainnet": { + "custom": { + "in": { + "capacity": "11250225000000000000000", + "isEnabled": true, + "rate": "3105000000000000000" + }, + "out": { + "capacity": "5266772000000000000000", + "isEnabled": true, + "rate": "1453600000000000000" + } + }, + "standard": { + "in": { + "capacity": "16667000000000000000000", + "isEnabled": true, + "rate": "4600000000000000000" + }, + "out": { + "capacity": "16667000000000000000000", + "isEnabled": true, + "rate": "4600000000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "7616819000000000000000", + "isEnabled": true, + "rate": "2102200000000000000" + }, + "out": { + "capacity": "7516817000000000000000", + "isEnabled": true, + "rate": "2074600000000000000" + } + }, + "standard": { + "in": { + "capacity": "16667000000000000000000", + "isEnabled": true, + "rate": "4600000000000000000" + }, + "out": { + "capacity": "16667000000000000000000", + "isEnabled": true, + "rate": "4600000000000000000" + } + } + } + } + } + }, + "OVER": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "oXAUT": { + "avalanche-mainnet": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "6730000000000", + "isEnabled": true, + "rate": "3365000000" + }, + "out": { + "capacity": "6670000000000", + "isEnabled": true, + "rate": "3335000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + }, + "ethereum-mainnet-worldchain-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "6040000000000", + "isEnabled": true, + "rate": "3020000000" + }, + "out": { + "capacity": "3660000000000", + "isEnabled": true, + "rate": "1830000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "4170000000000", + "isEnabled": true, + "rate": "2085000000" + }, + "out": { + "capacity": "5240000000000", + "isEnabled": true, + "rate": "2620000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "5400000000000", + "isEnabled": true, + "rate": "2700000000" + }, + "out": { + "capacity": "4830000000000", + "isEnabled": true, + "rate": "2415000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-worldchain-1": { + "custom": { + "in": { + "capacity": "3950000000000", + "isEnabled": true, + "rate": "1975000000" + }, + "out": { + "capacity": "4760000000000", + "isEnabled": true, + "rate": "2380000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + } + }, + "PEPE": { + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "28300000000000000000", + "isEnabled": true, + "rate": "7861111111111111" + }, + "out": { + "capacity": "26800000000000000000000000000", + "isEnabled": true, + "rate": "7444444444444445040000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000", + "isEnabled": true, + "rate": "13888888888888890" + }, + "out": { + "capacity": "50000000000000000000000000000", + "isEnabled": true, + "rate": "13888888888888890000000000" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "320000000000000", + "isEnabled": true, + "rate": "88888888888" + }, + "out": { + "capacity": "316500000000000", + "isEnabled": true, + "rate": "87916666666" + } + }, + "standard": { + "in": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "138888888889" + }, + "out": { + "capacity": "500000000000000", + "isEnabled": true, + "rate": "138888888889" + } + } + } + } + } + }, + "PFVS": { + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "pippin": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "PIXEL": { + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "139200000000000000000000000", + "isEnabled": true, + "rate": "1611111100800000000000" + }, + "out": { + "capacity": "103140000000000000000000000", + "isEnabled": true, + "rate": "1193750000000000000000" + } + }, + "standard": { + "in": { + "capacity": "300000000000000000000000000", + "isEnabled": true, + "rate": "3472222200000000000000" + }, + "out": { + "capacity": "270000000000000000000000000", + "isEnabled": true, + "rate": "3125000000000000000000" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "203700000000000000000000000", + "isEnabled": true, + "rate": "2357638873800000000000" + }, + "out": { + "capacity": "99900000000000000000000000", + "isEnabled": true, + "rate": "1156250000000000000000" + } + }, + "standard": { + "in": { + "capacity": "300000000000000000000000000", + "isEnabled": true, + "rate": "3472222200000000000000" + }, + "out": { + "capacity": "270000000000000000000000000", + "isEnabled": true, + "rate": "3125000000000000000000" + } + } + } + } + } + }, + "PTsUSDE": { + "mainnet": { + "minBlockConfirmation": 10, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "pufETH": { + "berachain-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "soneium-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "RDP": { + "bsc-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "23600000000000000000000", + "isEnabled": true, + "rate": "273760000000000000" + }, + "out": { + "capacity": "22900000000000000000000", + "isEnabled": true, + "rate": "265640000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "580000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "580000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "24050000000000000000000", + "isEnabled": true, + "rate": "278980000000000000" + }, + "out": { + "capacity": "16350000000000000000000", + "isEnabled": true, + "rate": "189660000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "580000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "580000000000000000" + } + } + } + } + } + }, + "REG": { + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "matic-mainnet": { + "custom": { + "in": { + "capacity": "25650000000000000000000", + "isEnabled": true, + "rate": "7182000000000000000" + }, + "out": { + "capacity": "20300000000000000000000", + "isEnabled": true, + "rate": "5684000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "18450000000000000000000", + "isEnabled": true, + "rate": "5166000000000000000" + }, + "out": { + "capacity": "22450000000000000000000", + "isEnabled": true, + "rate": "6286000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "20650000000000000000000", + "isEnabled": true, + "rate": "5782000000000000000" + }, + "out": { + "capacity": "31050000000000000000000", + "isEnabled": true, + "rate": "8694000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "21050000000000000000000", + "isEnabled": true, + "rate": "5894000000000000000" + }, + "out": { + "capacity": "27850000000000000000000", + "isEnabled": true, + "rate": "7798000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + } + } + } + } + }, + "xdai-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "21050000000000000000000", + "isEnabled": true, + "rate": "5894000000000000000" + }, + "out": { + "capacity": "24850000000000000000000", + "isEnabled": true, + "rate": "6958000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "31450000000000000000000", + "isEnabled": true, + "rate": "8806000000000000000" + }, + "out": { + "capacity": "31250000000000000000000", + "isEnabled": true, + "rate": "8750000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "14000000000000000000" + } + } + } + } + } + }, + "RETH": { + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "909000000000000000000", + "isEnabled": true, + "rate": "2922435000000000" + }, + "out": { + "capacity": "765000000000000000000", + "isEnabled": true, + "rate": "2459475000000000" + } + }, + "standard": { + "in": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + }, + "out": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + } + } + }, + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "720000000000000000000", + "isEnabled": true, + "rate": "2314800000000000" + }, + "out": { + "capacity": "1209600000000000000000", + "isEnabled": true, + "rate": "3888864000000000" + } + }, + "standard": { + "in": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + }, + "out": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + } + } + }, + "tac-mainnet": { + "custom": null, + "standard": null + } + } + }, + "plasma-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "925200000000000000000", + "isEnabled": true, + "rate": "2974518000000000" + }, + "out": { + "capacity": "864000000000000000000", + "isEnabled": true, + "rate": "2777760000000000" + } + }, + "standard": { + "in": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + }, + "out": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "833400000000000000000", + "isEnabled": true, + "rate": "2679381000000000" + }, + "out": { + "capacity": "709200000000000000000", + "isEnabled": true, + "rate": "2280078000000000" + } + }, + "standard": { + "in": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + }, + "out": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + } + } + } + } + }, + "tac-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1117800000000000000000", + "isEnabled": true, + "rate": "3593727000000000" + }, + "out": { + "capacity": "1206000000000000000000", + "isEnabled": true, + "rate": "3877290000000000" + } + }, + "standard": { + "in": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + }, + "out": { + "capacity": "1800000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + } + } + } + } + } + }, + "RIZE": { + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "rsETH": { + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-zircuit-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-zircuit-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-zircuit-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-zircuit-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "SAS": { + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "bsc-mainnet": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "savBTC": { + "avalanche-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "savETH": { + "avalanche-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "savUSD": { + "avalanche-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polygon-mainnet-katana": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polygon-mainnet-katana": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 8, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polygon-mainnet-katana": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "plasma-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "polygon-mainnet-katana": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "SD": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "204288000000000000000000", + "isEnabled": true, + "rate": "2364208000000000000" + }, + "out": { + "capacity": "181248000000000000000000", + "isEnabled": true, + "rate": "2097568000000000000" + } + }, + "standard": { + "in": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + }, + "out": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "139008000000000000000000", + "isEnabled": true, + "rate": "1608728000000000000" + }, + "out": { + "capacity": "221952000000000000000000", + "isEnabled": true, + "rate": "2568632000000000000" + } + }, + "standard": { + "in": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + }, + "out": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "135552000000000000000000", + "isEnabled": true, + "rate": "1568732000000000000" + }, + "out": { + "capacity": "121344000000000000000000", + "isEnabled": true, + "rate": "1404304000000000000" + } + }, + "standard": { + "in": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + }, + "out": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "185856000000000000000000", + "isEnabled": true, + "rate": "2150896000000000000" + }, + "out": { + "capacity": "220032000000000000000000", + "isEnabled": true, + "rate": "2546412000000000000" + } + }, + "standard": { + "in": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + }, + "out": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "235776000000000000000000", + "isEnabled": true, + "rate": "2728616000000000000" + }, + "out": { + "capacity": "203904000000000000000000", + "isEnabled": true, + "rate": "2359764000000000000" + } + }, + "standard": { + "in": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + }, + "out": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "268032000000000000000000", + "isEnabled": true, + "rate": "3101912000000000000" + }, + "out": { + "capacity": "248064000000000000000000", + "isEnabled": true, + "rate": "2870824000000000000" + } + }, + "standard": { + "in": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + }, + "out": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4444000000000000000" + } + } + } + } + } + }, + "sDAI": { + "ethereum-mainnet-mode-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "135500000000000000000000", + "isEnabled": true, + "rate": "37614800000000000000" + }, + "out": { + "capacity": "133250000000000000000000", + "isEnabled": true, + "rate": "36990200000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "69400000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "69400000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "133000000000000000000000", + "isEnabled": true, + "rate": "36920800000000000000" + }, + "out": { + "capacity": "82500000000000000000000", + "isEnabled": true, + "rate": "22902000000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "69400000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "69400000000000000000" + } + } + } + } + } + }, + "SDL": { + "ethereum-mainnet-andromeda-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "302250000000000000000000", + "isEnabled": true, + "rate": "83622500000000000000" + }, + "out": { + "capacity": "436500000000000000000000", + "isEnabled": true, + "rate": "120765000000000000000" + } + }, + "standard": { + "in": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + }, + "out": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-andromeda-1": { + "custom": { + "in": { + "capacity": "311250000000000000000000", + "isEnabled": true, + "rate": "86112500000000000000" + }, + "out": { + "capacity": "444750000000000000000000", + "isEnabled": true, + "rate": "123047500000000000000" + } + }, + "standard": { + "in": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + }, + "out": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "331500000000000000000000", + "isEnabled": true, + "rate": "91715000000000000000" + }, + "out": { + "capacity": "261750000000000000000000", + "isEnabled": true, + "rate": "72417500000000000000" + } + }, + "standard": { + "in": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + }, + "out": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-andromeda-1": { + "custom": { + "in": { + "capacity": "353250000000000000000000", + "isEnabled": true, + "rate": "97732500000000000000" + }, + "out": { + "capacity": "327750000000000000000000", + "isEnabled": true, + "rate": "90677500000000000000" + } + }, + "standard": { + "in": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + }, + "out": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "378750000000000000000000", + "isEnabled": true, + "rate": "104787500000000000000" + }, + "out": { + "capacity": "240750000000000000000000", + "isEnabled": true, + "rate": "66607500000000000000" + } + }, + "standard": { + "in": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + }, + "out": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "207500000000000000000" + } + } + } + } + } + }, + "SDM": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 10, + "remote": { + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": null, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": null, + "standard": null + } + } + } + }, + "sDOLA": { + "berachain-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 9, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "SDT": { + "bsc-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "345500000000000000000000", + "isEnabled": true, + "rate": "95966080000000000000" + }, + "out": { + "capacity": "245000000000000000000000", + "isEnabled": true, + "rate": "68051200000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "174500000000000000000000", + "isEnabled": true, + "rate": "48469120000000000000" + }, + "out": { + "capacity": "342500000000000000000000", + "isEnabled": true, + "rate": "95132800000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "326500000000000000000000", + "isEnabled": true, + "rate": "90688640000000000000" + }, + "out": { + "capacity": "292000000000000000000000", + "isEnabled": true, + "rate": "81105920000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "314500000000000000000000", + "isEnabled": true, + "rate": "87355520000000000000" + }, + "out": { + "capacity": "222000000000000000000000", + "isEnabled": true, + "rate": "61662720000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "246000000000000000000000", + "isEnabled": true, + "rate": "68328960000000000000" + }, + "out": { + "capacity": "287500000000000000000000", + "isEnabled": true, + "rate": "79856000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + }, + "out": { + "capacity": "500000000000000000000000", + "isEnabled": true, + "rate": "138880000000000000000" + } + } + } + } + } + }, + "SDY": { + "avalanche-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1680000000000000000000000", + "isEnabled": true, + "rate": "19488000000000000000" + }, + "out": { + "capacity": "2880000000000000000000000", + "isEnabled": true, + "rate": "33408000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "3240000000000000000000000", + "isEnabled": true, + "rate": "37584000000000000000" + }, + "out": { + "capacity": "2095000000000000000000000", + "isEnabled": true, + "rate": "24302000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "3040000000000000000000000", + "isEnabled": true, + "rate": "35264000000000000000" + }, + "out": { + "capacity": "1780000000000000000000000", + "isEnabled": true, + "rate": "20648000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "3420000000000000000000000", + "isEnabled": true, + "rate": "39672000000000000000" + }, + "out": { + "capacity": "3270000000000000000000000", + "isEnabled": true, + "rate": "37932000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "2640000000000000000000000", + "isEnabled": true, + "rate": "30624000000000000000" + }, + "out": { + "capacity": "3215000000000000000000000", + "isEnabled": true, + "rate": "37294000000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "58000000000000000000" + } + } + } + } + } + }, + "SHIB": { + "avalanche-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "celo-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-andromeda-1": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-blast-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-mantle-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-mode-1": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-scroll-1": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-zircuit-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-zksync-1": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "celo-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-andromeda-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-blast-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-mantle-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-scroll-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-zircuit-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polkadot-mainnet-astar": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "xdai-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "polkadot-mainnet-astar": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "wemix-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "xdai-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "SHIPA": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": null, + "remote": { + "shibarium-mainnet": { + "custom": null, + "standard": null + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "SHIRO": { + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "SILO": { + "avalanche-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "sINV": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "6230000000000000000000", + "isEnabled": true, + "rate": "68530000000000000" + }, + "out": { + "capacity": "6970000000000000000000", + "isEnabled": true, + "rate": "76670000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "4090000000000000000000", + "isEnabled": true, + "rate": "44990000000000000" + }, + "out": { + "capacity": "5190000000000000000000", + "isEnabled": true, + "rate": "57090000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "6020000000000000000000", + "isEnabled": true, + "rate": "66220000000000000" + }, + "out": { + "capacity": "5920000000000000000000", + "isEnabled": true, + "rate": "65120000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "5780000000000000000000", + "isEnabled": true, + "rate": "63580000000000000" + }, + "out": { + "capacity": "5340000000000000000000", + "isEnabled": true, + "rate": "58740000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "6800000000000000000000", + "isEnabled": true, + "rate": "74800000000000000" + }, + "out": { + "capacity": "3700000000000000000000", + "isEnabled": true, + "rate": "40700000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "3170000000000000000000", + "isEnabled": true, + "rate": "34870000000000000" + }, + "out": { + "capacity": "6150000000000000000000", + "isEnabled": true, + "rate": "67650000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "5490000000000000000000", + "isEnabled": true, + "rate": "60390000000000000" + }, + "out": { + "capacity": "5850000000000000000000", + "isEnabled": true, + "rate": "64350000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "3670000000000000000000", + "isEnabled": true, + "rate": "40370000000000000" + }, + "out": { + "capacity": "6250000000000000000000", + "isEnabled": true, + "rate": "68750000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "4580000000000000000000", + "isEnabled": true, + "rate": "50380000000000000" + }, + "out": { + "capacity": "4720000000000000000000", + "isEnabled": true, + "rate": "51920000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + }, + "out": { + "capacity": "10000000000000000000000", + "isEnabled": true, + "rate": "110000000000000000" + } + } + } + } + } + }, + "SKYA": { + "bsc-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "soneium-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "SNOW": { + "bsc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 10, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "SOIL": { + "mainnet": { + "minBlockConfirmation": 10, + "remote": { + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "SolvBTC": { + "avalanche-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1085000000000000000", + "isEnabled": true, + "rate": "50231160000000" + }, + "out": { + "capacity": "1522500000000000000", + "isEnabled": true, + "rate": "70485660000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1030000000000000000", + "isEnabled": true, + "rate": "47684880000000" + }, + "out": { + "capacity": "1645000000000000000", + "isEnabled": true, + "rate": "76156920000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1045000000000000000", + "isEnabled": true, + "rate": "48379320000000" + }, + "out": { + "capacity": "1497500000000000000", + "isEnabled": true, + "rate": "69328260000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1500000000000000000", + "isEnabled": true, + "rate": "69444000000000" + }, + "out": { + "capacity": "1662500000000000000", + "isEnabled": true, + "rate": "76967100000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1705000000000000000", + "isEnabled": true, + "rate": "78934680000000" + }, + "out": { + "capacity": "1662500000000000000", + "isEnabled": true, + "rate": "76967100000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "860000000000000000", + "isEnabled": true, + "rate": "39814560000000" + }, + "out": { + "capacity": "897500000000000000", + "isEnabled": true, + "rate": "41550660000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1185000000000000000", + "isEnabled": true, + "rate": "54860760000000" + }, + "out": { + "capacity": "965000000000000000", + "isEnabled": true, + "rate": "44675640000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "837500000000000000", + "isEnabled": true, + "rate": "38772900000000" + }, + "out": { + "capacity": "1055000000000000000", + "isEnabled": true, + "rate": "48842280000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1027500000000000000", + "isEnabled": true, + "rate": "47569140000000" + }, + "out": { + "capacity": "1575000000000000000", + "isEnabled": true, + "rate": "72916200000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "berachain-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1197500000000000000", + "isEnabled": true, + "rate": "55439460000000" + }, + "out": { + "capacity": "1255000000000000000", + "isEnabled": true, + "rate": "58101480000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1122500000000000000", + "isEnabled": true, + "rate": "51967260000000" + }, + "out": { + "capacity": "1412500000000000000", + "isEnabled": true, + "rate": "65393100000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1225000000000000000", + "isEnabled": true, + "rate": "56712600000000" + }, + "out": { + "capacity": "1372500000000000000", + "isEnabled": true, + "rate": "63541260000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "bitcoin-mainnet-bob-1": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1602500000000000000", + "isEnabled": true, + "rate": "74189340000000" + }, + "out": { + "capacity": "1192500000000000000", + "isEnabled": true, + "rate": "55207980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "782500000000000000", + "isEnabled": true, + "rate": "36226620000000" + }, + "out": { + "capacity": "1567500000000000000", + "isEnabled": true, + "rate": "72568980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1167500000000000000", + "isEnabled": true, + "rate": "54050580000000" + }, + "out": { + "capacity": "847500000000000000", + "isEnabled": true, + "rate": "39235860000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1585000000000000000", + "isEnabled": true, + "rate": "73379160000000" + }, + "out": { + "capacity": "885000000000000000", + "isEnabled": true, + "rate": "40971960000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "835000000000000000", + "isEnabled": true, + "rate": "38657160000000" + }, + "out": { + "capacity": "1297500000000000000", + "isEnabled": true, + "rate": "60069060000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1645000000000000000", + "isEnabled": true, + "rate": "76156920000000" + }, + "out": { + "capacity": "1675000000000000000", + "isEnabled": true, + "rate": "77545800000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1042500000000000000", + "isEnabled": true, + "rate": "48263580000000" + }, + "out": { + "capacity": "1277500000000000000", + "isEnabled": true, + "rate": "59143140000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "817500000000000000", + "isEnabled": true, + "rate": "37846980000000" + }, + "out": { + "capacity": "1067500000000000000", + "isEnabled": true, + "rate": "49420980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1142500000000000000", + "isEnabled": true, + "rate": "52893180000000" + }, + "out": { + "capacity": "997500000000000000", + "isEnabled": true, + "rate": "46180260000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "927500000000000000", + "isEnabled": true, + "rate": "42939540000000" + }, + "out": { + "capacity": "1227500000000000000", + "isEnabled": true, + "rate": "56828340000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1255000000000000000", + "isEnabled": true, + "rate": "58101480000000" + }, + "out": { + "capacity": "765000000000000000", + "isEnabled": true, + "rate": "35416440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1255000000000000000", + "isEnabled": true, + "rate": "58101480000000" + }, + "out": { + "capacity": "1140000000000000000", + "isEnabled": true, + "rate": "52777440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1230000000000000000", + "isEnabled": true, + "rate": "56944080000000" + }, + "out": { + "capacity": "1137500000000000000", + "isEnabled": true, + "rate": "52661700000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1492500000000000000", + "isEnabled": true, + "rate": "69096780000000" + }, + "out": { + "capacity": "930000000000000000", + "isEnabled": true, + "rate": "43055280000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1735000000000000000", + "isEnabled": true, + "rate": "80323560000000" + }, + "out": { + "capacity": "1460000000000000000", + "isEnabled": true, + "rate": "67592160000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1745000000000000000", + "isEnabled": true, + "rate": "80786520000000" + }, + "out": { + "capacity": "1547500000000000000", + "isEnabled": true, + "rate": "71643060000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1610000000000000000", + "isEnabled": true, + "rate": "74536560000000" + }, + "out": { + "capacity": "762500000000000000", + "isEnabled": true, + "rate": "35300700000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1282500000000000000", + "isEnabled": true, + "rate": "59374620000000" + }, + "out": { + "capacity": "1015000000000000000", + "isEnabled": true, + "rate": "46990440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1467500000000000000", + "isEnabled": true, + "rate": "67939380000000" + }, + "out": { + "capacity": "1135000000000000000", + "isEnabled": true, + "rate": "52545960000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1435000000000000000", + "isEnabled": true, + "rate": "66434760000000" + }, + "out": { + "capacity": "1347500000000000000", + "isEnabled": true, + "rate": "62383860000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1520000000000000000", + "isEnabled": true, + "rate": "70369920000000" + }, + "out": { + "capacity": "1327500000000000000", + "isEnabled": true, + "rate": "61457940000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": null, + "standard": null + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "875000000000000000", + "isEnabled": true, + "rate": "40509000000000" + }, + "out": { + "capacity": "1392500000000000000", + "isEnabled": true, + "rate": "64467180000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "251250000", + "isEnabled": true, + "rate": "11631" + }, + "out": { + "capacity": "2977500000000000000", + "isEnabled": true, + "rate": "137846340000000" + } + }, + "standard": { + "in": { + "capacity": "750000000", + "isEnabled": true, + "rate": "34722" + }, + "out": { + "capacity": "7500000000000000000", + "isEnabled": true, + "rate": "347220000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1437500000000000000", + "isEnabled": true, + "rate": "66550500000000" + }, + "out": { + "capacity": "840000000000000000", + "isEnabled": true, + "rate": "38888640000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": null, + "standard": null + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1330000000000000000", + "isEnabled": true, + "rate": "61573680000000" + }, + "out": { + "capacity": "1270000000000000000", + "isEnabled": true, + "rate": "58795920000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1197500000000000000", + "isEnabled": true, + "rate": "55439460000000" + }, + "out": { + "capacity": "1667500000000000000", + "isEnabled": true, + "rate": "77198580000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1382500000000000000", + "isEnabled": true, + "rate": "64004220000000" + }, + "out": { + "capacity": "1570000000000000000", + "isEnabled": true, + "rate": "72684720000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1447500000000000000", + "isEnabled": true, + "rate": "67013460000000" + }, + "out": { + "capacity": "1380000000000000000", + "isEnabled": true, + "rate": "63888480000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1217500000000000000", + "isEnabled": true, + "rate": "56365380000000" + }, + "out": { + "capacity": "1287500000000000000", + "isEnabled": true, + "rate": "59606100000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "952500000000000000", + "isEnabled": true, + "rate": "44096940000000" + }, + "out": { + "capacity": "1172500000000000000", + "isEnabled": true, + "rate": "54282060000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1035000000000000000", + "isEnabled": true, + "rate": "47916360000000" + }, + "out": { + "capacity": "980000000000000000", + "isEnabled": true, + "rate": "45370080000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1652500000000000000", + "isEnabled": true, + "rate": "76504140000000" + }, + "out": { + "capacity": "1105000000000000000", + "isEnabled": true, + "rate": "51157080000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1565000000000000000", + "isEnabled": true, + "rate": "72453240000000" + }, + "out": { + "capacity": "780000000000000000", + "isEnabled": true, + "rate": "36110880000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1582500000000000000", + "isEnabled": true, + "rate": "73263420000000" + }, + "out": { + "capacity": "980000000000000000", + "isEnabled": true, + "rate": "45370080000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1140000000000000000", + "isEnabled": true, + "rate": "52777440000000" + }, + "out": { + "capacity": "847500000000000000", + "isEnabled": true, + "rate": "39235860000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1675000000000000000", + "isEnabled": true, + "rate": "77545800000000" + }, + "out": { + "capacity": "1602500000000000000", + "isEnabled": true, + "rate": "74189340000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1062500000000000000", + "isEnabled": true, + "rate": "49189500000000" + }, + "out": { + "capacity": "1145000000000000000", + "isEnabled": true, + "rate": "53008920000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1090000000000000000", + "isEnabled": true, + "rate": "50462640000000" + }, + "out": { + "capacity": "1430000000000000000", + "isEnabled": true, + "rate": "66203280000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-ink-1": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1450000000000000000", + "isEnabled": true, + "rate": "67129200000000" + }, + "out": { + "capacity": "1145000000000000000", + "isEnabled": true, + "rate": "53008920000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1730000000000000000", + "isEnabled": true, + "rate": "80092080000000" + }, + "out": { + "capacity": "1547500000000000000", + "isEnabled": true, + "rate": "71643060000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "987500000000000000", + "isEnabled": true, + "rate": "45717300000000" + }, + "out": { + "capacity": "895000000000000000", + "isEnabled": true, + "rate": "41434920000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1135000000000000000", + "isEnabled": true, + "rate": "52545960000000" + }, + "out": { + "capacity": "907500000000000000", + "isEnabled": true, + "rate": "42013620000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1560000000000000000", + "isEnabled": true, + "rate": "72221760000000" + }, + "out": { + "capacity": "1277500000000000000", + "isEnabled": true, + "rate": "59143140000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1285000000000000000", + "isEnabled": true, + "rate": "59490360000000" + }, + "out": { + "capacity": "1300000000000000000", + "isEnabled": true, + "rate": "60184800000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1727500000000000000", + "isEnabled": true, + "rate": "79976340000000" + }, + "out": { + "capacity": "1155000000000000000", + "isEnabled": true, + "rate": "53471880000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1270000000000000000", + "isEnabled": true, + "rate": "58795920000000" + }, + "out": { + "capacity": "1277500000000000000", + "isEnabled": true, + "rate": "59143140000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1285000000000000000", + "isEnabled": true, + "rate": "59490360000000" + }, + "out": { + "capacity": "1477500000000000000", + "isEnabled": true, + "rate": "68402340000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1400000000000000000", + "isEnabled": true, + "rate": "64814400000000" + }, + "out": { + "capacity": "850000000000000000", + "isEnabled": true, + "rate": "39351600000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1012500000000000000", + "isEnabled": true, + "rate": "46874700000000" + }, + "out": { + "capacity": "827500000000000000", + "isEnabled": true, + "rate": "38309940000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1077500000000000000", + "isEnabled": true, + "rate": "49883940000000" + }, + "out": { + "capacity": "1432500000000000000", + "isEnabled": true, + "rate": "66319020000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1175000000000000000", + "isEnabled": true, + "rate": "54397800000000" + }, + "out": { + "capacity": "1462500000000000000", + "isEnabled": true, + "rate": "67707900000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "817500000000000000", + "isEnabled": true, + "rate": "37846980000000" + }, + "out": { + "capacity": "817500000000000000", + "isEnabled": true, + "rate": "37846980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1047500000000000000", + "isEnabled": true, + "rate": "48495060000000" + }, + "out": { + "capacity": "942500000000000000", + "isEnabled": true, + "rate": "43633980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "937500000000000000", + "isEnabled": true, + "rate": "43402500000000" + }, + "out": { + "capacity": "1155000000000000000", + "isEnabled": true, + "rate": "53471880000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1202500000000000000", + "isEnabled": true, + "rate": "55670940000000" + }, + "out": { + "capacity": "910000000000000000", + "isEnabled": true, + "rate": "42129360000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1285000000000000000", + "isEnabled": true, + "rate": "59490360000000" + }, + "out": { + "capacity": "1450000000000000000", + "isEnabled": true, + "rate": "67129200000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1160000000000000000", + "isEnabled": true, + "rate": "53703360000000" + }, + "out": { + "capacity": "1527500000000000000", + "isEnabled": true, + "rate": "70717140000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-taiko-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "775000000000000000", + "isEnabled": true, + "rate": "35879400000000" + }, + "out": { + "capacity": "1107500000000000000", + "isEnabled": true, + "rate": "51272820000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-zksync-1": { + "minBlockConfirmation": 6, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "855000000000000000", + "isEnabled": true, + "rate": "39583080000000" + }, + "out": { + "capacity": "1380000000000000000", + "isEnabled": true, + "rate": "63888480000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1382500000000000000", + "isEnabled": true, + "rate": "64004220000000" + }, + "out": { + "capacity": "902500000000000000", + "isEnabled": true, + "rate": "41782140000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "95850000000000000000", + "isEnabled": true, + "rate": "1109367900000000" + }, + "out": { + "capacity": "1577500000000000000", + "isEnabled": true, + "rate": "73031940000000" + } + }, + "standard": { + "in": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1736100000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1242500000000000000", + "isEnabled": true, + "rate": "57522780000000" + }, + "out": { + "capacity": "1140000000000000000", + "isEnabled": true, + "rate": "52777440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "hyperliquid-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1237500000000000000", + "isEnabled": true, + "rate": "57291300000000" + }, + "out": { + "capacity": "997500000000000000", + "isEnabled": true, + "rate": "46180260000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1640000000000000000", + "isEnabled": true, + "rate": "75925440000000" + }, + "out": { + "capacity": "777500000000000000", + "isEnabled": true, + "rate": "35995140000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "845000000000000000", + "isEnabled": true, + "rate": "39120120000000" + }, + "out": { + "capacity": "1390000000000000000", + "isEnabled": true, + "rate": "64351440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1737500000000000000", + "isEnabled": true, + "rate": "80439300000000" + }, + "out": { + "capacity": "792500000000000000", + "isEnabled": true, + "rate": "36689580000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1382500000000000000", + "isEnabled": true, + "rate": "64004220000000" + }, + "out": { + "capacity": "897500000000000000", + "isEnabled": true, + "rate": "41550660000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1137500000000000000", + "isEnabled": true, + "rate": "52661700000000" + }, + "out": { + "capacity": "1645000000000000000", + "isEnabled": true, + "rate": "76156920000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1470000000000000000", + "isEnabled": true, + "rate": "68055120000000" + }, + "out": { + "capacity": "867500000000000000", + "isEnabled": true, + "rate": "40161780000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1557500000000000000", + "isEnabled": true, + "rate": "72106020000000" + }, + "out": { + "capacity": "1695000000000000000", + "isEnabled": true, + "rate": "78471720000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "752500000000000000", + "isEnabled": true, + "rate": "34837740000000" + }, + "out": { + "capacity": "1117500000000000000", + "isEnabled": true, + "rate": "51735780000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-taiko-1": { + "custom": { + "in": { + "capacity": "1702500000000000000", + "isEnabled": true, + "rate": "78818940000000" + }, + "out": { + "capacity": "1325000000000000000", + "isEnabled": true, + "rate": "61342200000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1040000000000000000", + "isEnabled": true, + "rate": "48147840000000" + }, + "out": { + "capacity": "82950000000000000000", + "isEnabled": true, + "rate": "960008000000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1736000000000000" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1592500000000000000", + "isEnabled": true, + "rate": "73726380000000" + }, + "out": { + "capacity": "810000000000000000", + "isEnabled": true, + "rate": "37499760000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "757500000000000000", + "isEnabled": true, + "rate": "35069220000000" + }, + "out": { + "capacity": "1390000000000000000", + "isEnabled": true, + "rate": "64351440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "3260000000000000000", + "isEnabled": true, + "rate": "37731240000000" + }, + "out": { + "capacity": "13500000000000000000", + "isEnabled": true, + "rate": "156249000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000", + "isEnabled": true, + "rate": "57870000000000" + }, + "out": { + "capacity": "30000000000000000000", + "isEnabled": true, + "rate": "347220000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1565000000000000000", + "isEnabled": true, + "rate": "72453240000000" + }, + "out": { + "capacity": "1740000000000000000", + "isEnabled": true, + "rate": "80555040000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "101000000", + "isEnabled": true, + "rate": "4675" + }, + "out": { + "capacity": "1557500000000000000", + "isEnabled": true, + "rate": "72106020000000" + } + }, + "standard": { + "in": { + "capacity": "250000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1350000000000000000", + "isEnabled": true, + "rate": "62499600000000" + }, + "out": { + "capacity": "24120000000000000000", + "isEnabled": true, + "rate": "279164880000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "60000000000000000000", + "isEnabled": true, + "rate": "694440000000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "875000000000000000", + "isEnabled": true, + "rate": "40509000000000" + }, + "out": { + "capacity": "930000000000000000", + "isEnabled": true, + "rate": "43055280000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "947500000000000000", + "isEnabled": true, + "rate": "43865460000000" + }, + "out": { + "capacity": "1037500000000000000", + "isEnabled": true, + "rate": "48032100000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1455000000000000000", + "isEnabled": true, + "rate": "67360680000000" + }, + "out": { + "capacity": "997500000000000000", + "isEnabled": true, + "rate": "46180260000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1692500000000000000", + "isEnabled": true, + "rate": "78355980000000" + }, + "out": { + "capacity": "1597500000000000000", + "isEnabled": true, + "rate": "73957860000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "765000000000000000", + "isEnabled": true, + "rate": "35416440000000" + }, + "out": { + "capacity": "935000000000000000", + "isEnabled": true, + "rate": "43286760000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1632500000000000000", + "isEnabled": true, + "rate": "75578220000000" + }, + "out": { + "capacity": "1592500000000000000", + "isEnabled": true, + "rate": "73726380000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "810000000000000000", + "isEnabled": true, + "rate": "37499760000000" + }, + "out": { + "capacity": "915000000000000000", + "isEnabled": true, + "rate": "42360840000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "830000000000000000", + "isEnabled": true, + "rate": "38425680000000" + }, + "out": { + "capacity": "927500000000000000", + "isEnabled": true, + "rate": "42939540000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1645000000000000000", + "isEnabled": true, + "rate": "76156920000000" + }, + "out": { + "capacity": "982500000000000000", + "isEnabled": true, + "rate": "45485820000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1590000000000000000", + "isEnabled": true, + "rate": "73610640000000" + }, + "out": { + "capacity": "1212500000000000000", + "isEnabled": true, + "rate": "56133900000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "807500000000000000", + "isEnabled": true, + "rate": "37384020000000" + }, + "out": { + "capacity": "1662500000000000000", + "isEnabled": true, + "rate": "76967100000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "855000000000000000", + "isEnabled": true, + "rate": "39583080000000" + }, + "out": { + "capacity": "1230000000000000000", + "isEnabled": true, + "rate": "56944080000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "monad-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "19530000000000000000", + "isEnabled": true, + "rate": "226040220000000" + }, + "out": { + "capacity": "2240000000000000000", + "isEnabled": true, + "rate": "25925760000000" + } + }, + "standard": { + "in": { + "capacity": "30000000000000000000", + "isEnabled": true, + "rate": "347220000000000" + }, + "out": { + "capacity": "5000000000000000000", + "isEnabled": true, + "rate": "57870000000000" + } + } + } + } + }, + "sei-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1277500000000000000", + "isEnabled": true, + "rate": "59143140000000" + }, + "out": { + "capacity": "1317500000000000000", + "isEnabled": true, + "rate": "60994980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1125000000000000000", + "isEnabled": true, + "rate": "52083000000000" + }, + "out": { + "capacity": "1040000000000000000", + "isEnabled": true, + "rate": "48147840000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "912500000000000000", + "isEnabled": true, + "rate": "42245100000000" + }, + "out": { + "capacity": "1135000000000000000", + "isEnabled": true, + "rate": "52545960000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "820000000000000000", + "isEnabled": true, + "rate": "37962720000000" + }, + "out": { + "capacity": "1060000000000000000", + "isEnabled": true, + "rate": "49073760000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1377500000000000000", + "isEnabled": true, + "rate": "63772740000000" + }, + "out": { + "capacity": "1097500000000000000", + "isEnabled": true, + "rate": "50809860000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "750000000000000000", + "isEnabled": true, + "rate": "34722000000000" + }, + "out": { + "capacity": "930000000000000000", + "isEnabled": true, + "rate": "43055280000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "419250000", + "isEnabled": true, + "rate": "19409" + }, + "out": { + "capacity": "415500000", + "isEnabled": true, + "rate": "19235" + } + }, + "standard": { + "in": { + "capacity": "750000000", + "isEnabled": true, + "rate": "34722" + }, + "out": { + "capacity": "750000000", + "isEnabled": true, + "rate": "34722" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "160000000", + "isEnabled": true, + "rate": "7407" + }, + "out": { + "capacity": "155500000", + "isEnabled": true, + "rate": "7199" + } + }, + "standard": { + "in": { + "capacity": "250000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "250000000", + "isEnabled": true, + "rate": "11574" + } + } + } + } + }, + "soneium-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "990000000000000000", + "isEnabled": true, + "rate": "45833040000000" + }, + "out": { + "capacity": "1147500000000000000", + "isEnabled": true, + "rate": "53124660000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1487500000000000000", + "isEnabled": true, + "rate": "68865300000000" + }, + "out": { + "capacity": "1390000000000000000", + "isEnabled": true, + "rate": "64351440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "39600000000000000000", + "isEnabled": true, + "rate": "458330400000000" + }, + "out": { + "capacity": "912500000000000000", + "isEnabled": true, + "rate": "42245100000000" + } + }, + "standard": { + "in": { + "capacity": "60000000000000000000", + "isEnabled": true, + "rate": "694440000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1257500000000000000", + "isEnabled": true, + "rate": "58217220000000" + }, + "out": { + "capacity": "1390000000000000000", + "isEnabled": true, + "rate": "64351440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1340000000000000000", + "isEnabled": true, + "rate": "62036640000000" + }, + "out": { + "capacity": "1330000000000000000", + "isEnabled": true, + "rate": "61573680000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + } + }, + "SolvBTC.BERA": { + "berachain-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1215000000000000000", + "isEnabled": true, + "rate": "56249640000000" + }, + "out": { + "capacity": "800000000000000000", + "isEnabled": true, + "rate": "37036800000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "947500000000000000", + "isEnabled": true, + "rate": "43865460000000" + }, + "out": { + "capacity": "762500000000000000", + "isEnabled": true, + "rate": "35300700000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "887500000000000000", + "isEnabled": true, + "rate": "41087700000000" + }, + "out": { + "capacity": "1537500000000000000", + "isEnabled": true, + "rate": "71180100000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "bitcoin-mainnet-bob-1": { + "minBlockConfirmation": 10, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1572500000000000000", + "isEnabled": true, + "rate": "72800460000000" + }, + "out": { + "capacity": "970000000000000000", + "isEnabled": true, + "rate": "44907120000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1057500000000000000", + "isEnabled": true, + "rate": "48958020000000" + }, + "out": { + "capacity": "1330000000000000000", + "isEnabled": true, + "rate": "61573680000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1050000000000000000", + "isEnabled": true, + "rate": "48610800000000" + }, + "out": { + "capacity": "1720000000000000000", + "isEnabled": true, + "rate": "79629120000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1667500000000000000", + "isEnabled": true, + "rate": "77198580000000" + }, + "out": { + "capacity": "985000000000000000", + "isEnabled": true, + "rate": "45601560000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1645000000000000000", + "isEnabled": true, + "rate": "76156920000000" + }, + "out": { + "capacity": "1337500000000000000", + "isEnabled": true, + "rate": "61920900000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "932500000000000000", + "isEnabled": true, + "rate": "43171020000000" + }, + "out": { + "capacity": "1087500000000000000", + "isEnabled": true, + "rate": "50346900000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1435000000000000000", + "isEnabled": true, + "rate": "66434760000000" + }, + "out": { + "capacity": "1140000000000000000", + "isEnabled": true, + "rate": "52777440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1422500000000000000", + "isEnabled": true, + "rate": "65856060000000" + }, + "out": { + "capacity": "1525000000000000000", + "isEnabled": true, + "rate": "70601400000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1380000000000000000", + "isEnabled": true, + "rate": "63888480000000" + }, + "out": { + "capacity": "1255000000000000000", + "isEnabled": true, + "rate": "58101480000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + } + }, + "SolvBTC.JUP": { + "bitcoin-mainnet-bob-1": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "810000000000000000", + "isEnabled": true, + "rate": "37499760000000" + }, + "out": { + "capacity": "1457500000000000000", + "isEnabled": true, + "rate": "67476420000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1282500000000000000", + "isEnabled": true, + "rate": "59374620000000" + }, + "out": { + "capacity": "1132500000000000000", + "isEnabled": true, + "rate": "52430220000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1225000000000000000", + "isEnabled": true, + "rate": "56712600000000" + }, + "out": { + "capacity": "1142500000000000000", + "isEnabled": true, + "rate": "52893180000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "2940000000", + "isEnabled": true, + "rate": "34027" + }, + "out": { + "capacity": "34850000000000000000", + "isEnabled": true, + "rate": "403353900000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "57870" + }, + "out": { + "capacity": "50000000000000000000", + "isEnabled": true, + "rate": "578700000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "33900000000000000000", + "isEnabled": true, + "rate": "392358600000000" + }, + "out": { + "capacity": "53800000000000000000", + "isEnabled": true, + "rate": "622681200000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "1157400000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "1157400000000000" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1675000000", + "isEnabled": true, + "rate": "19386" + }, + "out": { + "capacity": "1845000000", + "isEnabled": true, + "rate": "21354" + } + }, + "standard": { + "in": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "57870" + }, + "out": { + "capacity": "5000000000", + "isEnabled": true, + "rate": "57870" + } + } + } + } + }, + "soneium-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1457500000000000000", + "isEnabled": true, + "rate": "67476420000000" + }, + "out": { + "capacity": "1075000000000000000", + "isEnabled": true, + "rate": "49768200000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "69000000000000000000", + "isEnabled": true, + "rate": "798606000000000" + }, + "out": { + "capacity": "67600000000000000000", + "isEnabled": true, + "rate": "782402400000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "1157400000000000" + }, + "out": { + "capacity": "100000000000000000000", + "isEnabled": true, + "rate": "1157400000000000" + } + } + } + } + } + }, + "STABLE": { + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "4704000000000000000000", + "isEnabled": true, + "rate": "54432000000000000" + }, + "out": { + "capacity": "2716000000000000000000", + "isEnabled": true, + "rate": "31428000000000000" + } + }, + "standard": { + "in": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + }, + "out": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "3661000000000000000000", + "isEnabled": true, + "rate": "42363000000000000" + }, + "out": { + "capacity": "3430000000000000000000", + "isEnabled": true, + "rate": "39690000000000000" + } + }, + "standard": { + "in": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + }, + "out": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "3976000000000000000000", + "isEnabled": true, + "rate": "46008000000000000" + }, + "out": { + "capacity": "3766000000000000000000", + "isEnabled": true, + "rate": "43578000000000000" + } + }, + "standard": { + "in": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + }, + "out": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "2625000000000000000000", + "isEnabled": true, + "rate": "30375000000000000" + }, + "out": { + "capacity": "4809000000000000000000", + "isEnabled": true, + "rate": "55647000000000000" + } + }, + "standard": { + "in": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + }, + "out": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "3528000000000000000000", + "isEnabled": true, + "rate": "40824000000000000" + }, + "out": { + "capacity": "3885000000000000000000", + "isEnabled": true, + "rate": "44955000000000000" + } + }, + "standard": { + "in": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + }, + "out": { + "capacity": "7000000000000000000000", + "isEnabled": true, + "rate": "81000000000000000" + } + } + } + } + } + }, + "STABUL": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + } + } + } + }, + "stBTC": { + "bitcoin-mainnet-bsquared-1": { + "minBlockConfirmation": 5, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bitcoin-mainnet-bsquared-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "STBU": { + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 10, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "stTAO": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "145600000000", + "isEnabled": true, + "rate": "15142400" + }, + "out": { + "capacity": "209200000000", + "isEnabled": true, + "rate": "21756800" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "157600000000", + "isEnabled": true, + "rate": "16390400" + }, + "out": { + "capacity": "269600000000", + "isEnabled": true, + "rate": "28038400" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "191600000000", + "isEnabled": true, + "rate": "19926400" + }, + "out": { + "capacity": "129200000000", + "isEnabled": true, + "rate": "13436800" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "134400000000", + "isEnabled": true, + "rate": "13977600" + }, + "out": { + "capacity": "243600000000", + "isEnabled": true, + "rate": "25334400" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "241600000000", + "isEnabled": true, + "rate": "25126400" + }, + "out": { + "capacity": "121600000000", + "isEnabled": true, + "rate": "12646400" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "184400000000", + "isEnabled": true, + "rate": "19177600" + }, + "out": { + "capacity": "207600000000", + "isEnabled": true, + "rate": "21590400" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "145200000000", + "isEnabled": true, + "rate": "15100800" + }, + "out": { + "capacity": "139200000000", + "isEnabled": true, + "rate": "14476800" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "272400000000", + "isEnabled": true, + "rate": "28329600" + }, + "out": { + "capacity": "272400000000", + "isEnabled": true, + "rate": "28329600" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "234000000000", + "isEnabled": true, + "rate": "24336000" + }, + "out": { + "capacity": "159200000000", + "isEnabled": true, + "rate": "16556800" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "232000000000", + "isEnabled": true, + "rate": "24128000" + }, + "out": { + "capacity": "133200000000", + "isEnabled": true, + "rate": "13852800" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "241600000000", + "isEnabled": true, + "rate": "25126400" + }, + "out": { + "capacity": "123600000000", + "isEnabled": true, + "rate": "12854400" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "127600000000", + "isEnabled": true, + "rate": "13270400" + }, + "out": { + "capacity": "233200000000", + "isEnabled": true, + "rate": "24252800" + } + }, + "standard": { + "in": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + }, + "out": { + "capacity": "400000000000", + "isEnabled": true, + "rate": "41600000" + } + } + } + } + } + }, + "suBTC": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "4216000000000000000", + "isEnabled": true, + "rate": "48800200000000" + }, + "out": { + "capacity": "3976000000000000000", + "isEnabled": true, + "rate": "46022200000000" + } + }, + "standard": { + "in": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + }, + "out": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "3480000000000000000", + "isEnabled": true, + "rate": "40281000000000" + }, + "out": { + "capacity": "5272000000000000000", + "isEnabled": true, + "rate": "61023400000000" + } + }, + "standard": { + "in": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + }, + "out": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "5112000000000000000", + "isEnabled": true, + "rate": "59171400000000" + }, + "out": { + "capacity": "5400000000000000000", + "isEnabled": true, + "rate": "62505000000000" + } + }, + "standard": { + "in": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + }, + "out": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "2768000000000000000", + "isEnabled": true, + "rate": "32039600000000" + }, + "out": { + "capacity": "5280000000000000000", + "isEnabled": true, + "rate": "61116000000000" + } + }, + "standard": { + "in": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + }, + "out": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "4056000000000000000", + "isEnabled": true, + "rate": "46948200000000" + }, + "out": { + "capacity": "3696000000000000000", + "isEnabled": true, + "rate": "42781200000000" + } + }, + "standard": { + "in": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + }, + "out": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "3256000000000000000", + "isEnabled": true, + "rate": "37688200000000" + }, + "out": { + "capacity": "4528000000000000000", + "isEnabled": true, + "rate": "52411600000000" + } + }, + "standard": { + "in": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + }, + "out": { + "capacity": "8000000000000000000", + "isEnabled": true, + "rate": "92600000000000" + } + } + } + } + } + }, + "suETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "86100000000000000000", + "isEnabled": true, + "rate": "975800000000000" + }, + "out": { + "capacity": "57000000000000000000", + "isEnabled": true, + "rate": "646000000000000" + } + }, + "standard": { + "in": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + }, + "out": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "74100000000000000000", + "isEnabled": true, + "rate": "839800000000000" + }, + "out": { + "capacity": "95850000000000000000", + "isEnabled": true, + "rate": "1086300000000000" + } + }, + "standard": { + "in": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + }, + "out": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "79050000000000000000", + "isEnabled": true, + "rate": "895900000000000" + }, + "out": { + "capacity": "78600000000000000000", + "isEnabled": true, + "rate": "890800000000000" + } + }, + "standard": { + "in": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + }, + "out": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "48900000000000000000", + "isEnabled": true, + "rate": "554200000000000" + }, + "out": { + "capacity": "91350000000000000000", + "isEnabled": true, + "rate": "1035300000000000" + } + }, + "standard": { + "in": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + }, + "out": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "97200000000000000000", + "isEnabled": true, + "rate": "1101600000000000" + }, + "out": { + "capacity": "58500000000000000000", + "isEnabled": true, + "rate": "663000000000000" + } + }, + "standard": { + "in": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + }, + "out": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "62700000000000000000", + "isEnabled": true, + "rate": "710600000000000" + }, + "out": { + "capacity": "90450000000000000000", + "isEnabled": true, + "rate": "1025100000000000" + } + }, + "standard": { + "in": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + }, + "out": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1700000000000000" + } + } + } + } + } + }, + "sUSD1+": { + "bsc-mainnet": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "suUSD": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "78200000000000000000000", + "isEnabled": true, + "rate": "904774000000000000" + }, + "out": { + "capacity": "100200000000000000000000", + "isEnabled": true, + "rate": "1159314000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "89400000000000000000000", + "isEnabled": true, + "rate": "1034358000000000000" + }, + "out": { + "capacity": "101000000000000000000000", + "isEnabled": true, + "rate": "1168570000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "116000000000000000000000", + "isEnabled": true, + "rate": "1342120000000000000" + }, + "out": { + "capacity": "139200000000000000000000", + "isEnabled": true, + "rate": "1610544000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "66600000000000000000000", + "isEnabled": true, + "rate": "770562000000000000" + }, + "out": { + "capacity": "78000000000000000000000", + "isEnabled": true, + "rate": "902460000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "64800000000000000000000", + "isEnabled": true, + "rate": "749736000000000000" + }, + "out": { + "capacity": "64600000000000000000000", + "isEnabled": true, + "rate": "747422000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "71000000000000000000000", + "isEnabled": true, + "rate": "821470000000000000" + }, + "out": { + "capacity": "111600000000000000000000", + "isEnabled": true, + "rate": "1291212000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "2314000000000000000" + } + } + } + } + } + }, + "SXT": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "syrupUSDC": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "hyperliquid-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "syrupUSDT": { + "ethereum-mainnet-mantle-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-mantle-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "plasma-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "tETH": { + "avalanche-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + }, + "tac-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "tac-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "THE": { + "binance-smart-chain-mainnet-opbnb-1": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "binance-smart-chain-mainnet-opbnb-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "297000000000000000000000", + "isEnabled": true, + "rate": "165132000000000000000" + }, + "out": { + "capacity": "394500000000000000000000", + "isEnabled": true, + "rate": "219342000000000000000" + } + }, + "standard": { + "in": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "417000000000000000000" + }, + "out": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "417000000000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "432000000000000000000000", + "isEnabled": true, + "rate": "240192000000000000000" + }, + "out": { + "capacity": "390750000000000000000000", + "isEnabled": true, + "rate": "217257000000000000000" + } + }, + "standard": { + "in": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "417000000000000000000" + }, + "out": { + "capacity": "750000000000000000000000", + "isEnabled": true, + "rate": "417000000000000000000" + } + } + } + } + } + }, + "TRADE": { + "bsc-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": null, + "standard": null + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "TREE": { + "avalanche-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "TURBO": { + "bsc-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "4704000000000000000000000", + "isEnabled": true, + "rate": "1306666636800000000000" + }, + "out": { + "capacity": "3822000000000000000000000", + "isEnabled": true, + "rate": "1061666642400000000000" + } + }, + "standard": { + "in": { + "capacity": "7000000000000000000000000", + "isEnabled": true, + "rate": "1944444400000000000000" + }, + "out": { + "capacity": "7000000000000000000000000", + "isEnabled": true, + "rate": "1944444400000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "4781000000000000000000000", + "isEnabled": true, + "rate": "1328055525200000000000" + }, + "out": { + "capacity": "2744000000000000000000000", + "isEnabled": true, + "rate": "762222204800000000000" + } + }, + "standard": { + "in": { + "capacity": "7000000000000000000000000", + "isEnabled": true, + "rate": "1944444400000000000000" + }, + "out": { + "capacity": "7000000000000000000000000", + "isEnabled": true, + "rate": "1944444400000000000000" + } + } + } + } + } + }, + "TURTLE": { + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "una.USDC": { + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "99600000000", + "isEnabled": true, + "rate": "27665560" + }, + "out": { + "capacity": "129000000000", + "isEnabled": true, + "rate": "35831900" + } + }, + "standard": { + "in": { + "capacity": "300000000000", + "isEnabled": true, + "rate": "83330000" + }, + "out": { + "capacity": "300000000000", + "isEnabled": true, + "rate": "83330000" + } + } + } + } + }, + "wemix-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "171300000000", + "isEnabled": true, + "rate": "47581430" + }, + "out": { + "capacity": "140100000000", + "isEnabled": true, + "rate": "38915110" + } + }, + "standard": { + "in": { + "capacity": "300000000000", + "isEnabled": true, + "rate": "83330000" + }, + "out": { + "capacity": "300000000000", + "isEnabled": true, + "rate": "83330000" + } + } + } + } + } + }, + "una.WEMIX": { + "avalanche-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "62600000000000000000000", + "isEnabled": true, + "rate": "17387150000000000000" + }, + "out": { + "capacity": "118800000000000000000000", + "isEnabled": true, + "rate": "32996700000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "83000000000000000000000", + "isEnabled": true, + "rate": "23053250000000000000" + }, + "out": { + "capacity": "129000000000000000000000", + "isEnabled": true, + "rate": "35829750000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "117000000000000000000000", + "isEnabled": true, + "rate": "32496750000000000000" + }, + "out": { + "capacity": "135400000000000000000000", + "isEnabled": true, + "rate": "37607350000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 3, + "remote": { + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "71600000000000000000000", + "isEnabled": true, + "rate": "19886900000000000000" + }, + "out": { + "capacity": "90000000000000000000000", + "isEnabled": true, + "rate": "24997500000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "106600000000000000000000", + "isEnabled": true, + "rate": "29608150000000000000" + }, + "out": { + "capacity": "70200000000000000000000", + "isEnabled": true, + "rate": "19498050000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "127000000000000000000000", + "isEnabled": true, + "rate": "35274250000000000000" + }, + "out": { + "capacity": "73400000000000000000000", + "isEnabled": true, + "rate": "20386850000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + }, + "wemix-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "102000000000000000000000", + "isEnabled": true, + "rate": "28330500000000000000" + }, + "out": { + "capacity": "139000000000000000000000", + "isEnabled": true, + "rate": "38607250000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "118800000000000000000000", + "isEnabled": true, + "rate": "32996700000000000000" + }, + "out": { + "capacity": "95200000000000000000000", + "isEnabled": true, + "rate": "26441800000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "78400000000000000000000", + "isEnabled": true, + "rate": "21775600000000000000" + }, + "out": { + "capacity": "131400000000000000000000", + "isEnabled": true, + "rate": "36496350000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "63400000000000000000000", + "isEnabled": true, + "rate": "17609350000000000000" + }, + "out": { + "capacity": "123800000000000000000000", + "isEnabled": true, + "rate": "34385450000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "136000000000000000000000", + "isEnabled": true, + "rate": "37774000000000000000" + }, + "out": { + "capacity": "92200000000000000000000", + "isEnabled": true, + "rate": "25608550000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "126000000000000000000000", + "isEnabled": true, + "rate": "34996500000000000000" + }, + "out": { + "capacity": "82400000000000000000000", + "isEnabled": true, + "rate": "22886600000000000000" + } + }, + "standard": { + "in": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + }, + "out": { + "capacity": "200000000000000000000000", + "isEnabled": true, + "rate": "55550000000000000000" + } + } + } + } + } + }, + "uniBTC": { + "aptos-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "94000000", + "isEnabled": true, + "rate": "1088" + }, + "out": { + "capacity": "134200000", + "isEnabled": true, + "rate": "1553" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "berachain-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "129000000", + "isEnabled": true, + "rate": "1493" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "97800000", + "isEnabled": true, + "rate": "1132" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "bitcoin-mainnet-bob-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bitcoin-mainnet-bsquared-1": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "89000000", + "isEnabled": true, + "rate": "5150" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "11574" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "aptos-mainnet": { + "custom": { + "in": { + "capacity": "139800000", + "isEnabled": true, + "rate": "1618" + }, + "out": { + "capacity": "75000000", + "isEnabled": true, + "rate": "868" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "96000000", + "isEnabled": true, + "rate": "1111" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "corn-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "120200000", + "isEnabled": true, + "rate": "1391" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "98000000", + "isEnabled": true, + "rate": "1134" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-ink-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "61400000", + "isEnabled": true, + "rate": "710" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "ethereum-mainnet-mantle-1": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "96000000", + "isEnabled": true, + "rate": "5555" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "11574" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "139800000", + "isEnabled": true, + "rate": "8090" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "11574" + } + } + } + } + }, + "ethereum-mainnet-unichain-1": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "130600000", + "isEnabled": true, + "rate": "1511" + }, + "out": { + "capacity": "93600000", + "isEnabled": true, + "rate": "1083" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "ethereum-mainnet-xlayer-1": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "70200000", + "isEnabled": true, + "rate": "812" + }, + "out": { + "capacity": "78400000", + "isEnabled": true, + "rate": "907" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "hyperliquid-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "66000000", + "isEnabled": true, + "rate": "763" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "aptos-mainnet": { + "custom": { + "in": { + "capacity": "120400000", + "isEnabled": true, + "rate": "1393" + }, + "out": { + "capacity": "125600000", + "isEnabled": true, + "rate": "1453" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "115800000", + "isEnabled": true, + "rate": "1340" + }, + "out": { + "capacity": "73400000", + "isEnabled": true, + "rate": "849" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + }, + "out": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + } + }, + "standard": { + "in": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + }, + "out": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "120400000", + "isEnabled": true, + "rate": "1393" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "bitcoin-mainnet-bsquared-1": { + "custom": { + "in": { + "capacity": "101600000", + "isEnabled": true, + "rate": "1176" + }, + "out": { + "capacity": "84000000", + "isEnabled": true, + "rate": "972" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "109000000", + "isEnabled": true, + "rate": "1261" + }, + "out": { + "capacity": "69000000", + "isEnabled": true, + "rate": "798" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "corn-mainnet": { + "custom": { + "in": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + }, + "out": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + } + }, + "standard": { + "in": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + }, + "out": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "61200000", + "isEnabled": true, + "rate": "70816" + }, + "out": { + "capacity": "113800000", + "isEnabled": true, + "rate": "131682" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "231428" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "231428" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "127000000", + "isEnabled": true, + "rate": "1470" + }, + "out": { + "capacity": "82000000", + "isEnabled": true, + "rate": "949" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "107800000", + "isEnabled": true, + "rate": "1247" + }, + "out": { + "capacity": "137800000", + "isEnabled": true, + "rate": "1595" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "ethereum-mainnet-mantle-1": { + "custom": { + "in": { + "capacity": "113600000", + "isEnabled": true, + "rate": "6574" + }, + "out": { + "capacity": "115800000", + "isEnabled": true, + "rate": "6701" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "118000000", + "isEnabled": true, + "rate": "6828" + }, + "out": { + "capacity": "78000000", + "isEnabled": true, + "rate": "4513" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "94800000", + "isEnabled": true, + "rate": "1097" + }, + "out": { + "capacity": "134400000", + "isEnabled": true, + "rate": "1555" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "ethereum-mainnet-xlayer-1": { + "custom": { + "in": { + "capacity": "91000000", + "isEnabled": true, + "rate": "1053" + }, + "out": { + "capacity": "73400000", + "isEnabled": true, + "rate": "849" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "0", + "isEnabled": true, + "rate": "0" + }, + "out": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + } + }, + "standard": { + "in": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + }, + "out": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "115200000", + "isEnabled": true, + "rate": "1333" + }, + "out": { + "capacity": "75200000", + "isEnabled": true, + "rate": "870" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + }, + "out": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + } + }, + "standard": { + "in": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + }, + "out": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + } + } + }, + "tac-mainnet": { + "custom": { + "in": { + "capacity": "137000000", + "isEnabled": true, + "rate": "1585" + }, + "out": { + "capacity": "123800000", + "isEnabled": true, + "rate": "1432" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "113200000", + "isEnabled": true, + "rate": "1310" + }, + "out": { + "capacity": "117400000", + "isEnabled": true, + "rate": "1358" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "96800000", + "isEnabled": true, + "rate": "1120" + }, + "out": { + "capacity": "117600000", + "isEnabled": true, + "rate": "1361" + } + }, + "standard": { + "in": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + }, + "out": { + "capacity": "200000000", + "isEnabled": true, + "rate": "2315" + } + } + } + } + }, + "tac-mainnet": { + "minBlockConfirmation": null, + "remote": { + "mainnet": { + "custom": null, + "standard": null + } + } + } + }, + "UNIO": { + "bsc-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "32000000000000000000000000", + "isEnabled": true, + "rate": "8888883200000000000000" + }, + "out": { + "capacity": "34650000000000000000000000", + "isEnabled": true, + "rate": "9624993840000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13888880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13888880000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "6300000000000000000000000", + "isEnabled": true, + "rate": "218400000000000000000" + }, + "out": { + "capacity": "4800000000000000000000000", + "isEnabled": true, + "rate": "166400000000000000000" + } + }, + "standard": { + "in": { + "capacity": "15000000000000000000000000", + "isEnabled": true, + "rate": "520000000000000000000" + }, + "out": { + "capacity": "15000000000000000000000000", + "isEnabled": true, + "rate": "520000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "33900000000000000000000000", + "isEnabled": true, + "rate": "9416660640000000000000" + }, + "out": { + "capacity": "23750000000000000000000000", + "isEnabled": true, + "rate": "6597218000000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13888880000000000000000" + }, + "out": { + "capacity": "50000000000000000000000000", + "isEnabled": true, + "rate": "13888880000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "6345000000000000000000000", + "isEnabled": true, + "rate": "219960000000000000000" + }, + "out": { + "capacity": "10200000000000000000000000", + "isEnabled": true, + "rate": "353600000000000000000" + } + }, + "standard": { + "in": { + "capacity": "15000000000000000000000000", + "isEnabled": true, + "rate": "520000000000000000000" + }, + "out": { + "capacity": "15000000000000000000000000", + "isEnabled": true, + "rate": "520000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "7485000000000000000000000", + "isEnabled": true, + "rate": "259480000000000000000" + }, + "out": { + "capacity": "9495000000000000000000000", + "isEnabled": true, + "rate": "329160000000000000000" + } + }, + "standard": { + "in": { + "capacity": "15000000000000000000000000", + "isEnabled": true, + "rate": "520000000000000000000" + }, + "out": { + "capacity": "15000000000000000000000000", + "isEnabled": true, + "rate": "520000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "9630000000000000000000000", + "isEnabled": true, + "rate": "333840000000000000000" + }, + "out": { + "capacity": "6120000000000000000000000", + "isEnabled": true, + "rate": "212160000000000000000" + } + }, + "standard": { + "in": { + "capacity": "15000000000000000000000000", + "isEnabled": true, + "rate": "520000000000000000000" + }, + "out": { + "capacity": "15000000000000000000000000", + "isEnabled": true, + "rate": "520000000000000000000" + } + } + } + } + } + }, + "USAGI": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 5, + "remote": { + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "USD+": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "96800000000", + "isEnabled": true, + "rate": "26620000" + }, + "out": { + "capacity": "110200000000", + "isEnabled": true, + "rate": "30305000" + } + }, + "standard": { + "in": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + }, + "out": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "77400000000", + "isEnabled": true, + "rate": "21285000" + }, + "out": { + "capacity": "87200000000", + "isEnabled": true, + "rate": "23980000" + } + }, + "standard": { + "in": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + }, + "out": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "92000000000", + "isEnabled": true, + "rate": "25300000" + }, + "out": { + "capacity": "99000000000", + "isEnabled": true, + "rate": "27225000" + } + }, + "standard": { + "in": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + }, + "out": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "86800000000", + "isEnabled": true, + "rate": "23870000" + }, + "out": { + "capacity": "82400000000", + "isEnabled": true, + "rate": "22660000" + } + }, + "standard": { + "in": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + }, + "out": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "104600000000", + "isEnabled": true, + "rate": "28765000" + }, + "out": { + "capacity": "105400000000", + "isEnabled": true, + "rate": "28985000" + } + }, + "standard": { + "in": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + }, + "out": { + "capacity": "200000000000", + "isEnabled": true, + "rate": "55000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + } + } + } + }, + "USD0": { + "bsc-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1491000000000000000000000", + "isEnabled": true, + "rate": "17395000000000000000" + }, + "out": { + "capacity": "1020000000000000000000000", + "isEnabled": true, + "rate": "11900000000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "975000000000000000000000", + "isEnabled": true, + "rate": "11375000000000000000" + }, + "out": { + "capacity": "1500000000000000000000000", + "isEnabled": true, + "rate": "17500000000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1203000000000000000000000", + "isEnabled": true, + "rate": "14035000000000000000" + }, + "out": { + "capacity": "906000000000000000000000", + "isEnabled": true, + "rate": "10570000000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1506000000000000000000000", + "isEnabled": true, + "rate": "17570000000000000000" + }, + "out": { + "capacity": "1251000000000000000000000", + "isEnabled": true, + "rate": "14595000000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + } + } + } + } + } + }, + "USD1": { + "ab-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "aptos-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "aptos-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-mantle-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ab-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "aptos-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-mantle-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "morph-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plume-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "monad-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "morph-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "plume-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "USDC": { + "0g-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "avalanche-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "19250000000", + "isEnabled": true, + "rate": "3850000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "50000000000", + "isEnabled": true, + "rate": "10000000" + } + } + } + } + }, + "bitcoin-mainnet-bob-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-unichain-1": { + "minBlockConfirmation": 8, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "0g-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "wemix-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "wemix-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "USDf": { + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "xdc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "xdc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "USDFI": { + "bsc-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "29950000000000000000000", + "isEnabled": true, + "rate": "341430000000000000" + }, + "out": { + "capacity": "18450000000000000000000", + "isEnabled": true, + "rate": "210330000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "34250000000000000000000", + "isEnabled": true, + "rate": "390450000000000000" + }, + "out": { + "capacity": "29900000000000000000000", + "isEnabled": true, + "rate": "340860000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "24500000000000000000000", + "isEnabled": true, + "rate": "279300000000000000" + }, + "out": { + "capacity": "27400000000000000000000", + "isEnabled": true, + "rate": "312360000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "20550000000000000000000", + "isEnabled": true, + "rate": "234270000000000000" + }, + "out": { + "capacity": "18600000000000000000000", + "isEnabled": true, + "rate": "212040000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "29850000000000000000000", + "isEnabled": true, + "rate": "340290000000000000" + }, + "out": { + "capacity": "30450000000000000000000", + "isEnabled": true, + "rate": "347130000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "17350000000000000000000", + "isEnabled": true, + "rate": "197790000000000000" + }, + "out": { + "capacity": "25300000000000000000000", + "isEnabled": true, + "rate": "288420000000000000" + } + }, + "standard": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + }, + "out": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "570000000000000000" + } + } + } + } + } + }, + "USDM": { + "avalanche-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "578000000000000000000000", + "isEnabled": true, + "rate": "6704800000000000000" + }, + "out": { + "capacity": "603000000000000000000000", + "isEnabled": true, + "rate": "6994800000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "616000000000000000000000", + "isEnabled": true, + "rate": "7145600000000000000" + }, + "out": { + "capacity": "343000000000000000000000", + "isEnabled": true, + "rate": "3978800000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "592000000000000000000000", + "isEnabled": true, + "rate": "6867200000000000000" + }, + "out": { + "capacity": "690000000000000000000000", + "isEnabled": true, + "rate": "8004000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "305000000000000000000000", + "isEnabled": true, + "rate": "3538000000000000000" + }, + "out": { + "capacity": "355000000000000000000000", + "isEnabled": true, + "rate": "4118000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "356000000000000000000000", + "isEnabled": true, + "rate": "4129600000000000000" + }, + "out": { + "capacity": "484000000000000000000000", + "isEnabled": true, + "rate": "5614400000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "633000000000000000000000", + "isEnabled": true, + "rate": "7342800000000000000" + }, + "out": { + "capacity": "450000000000000000000000", + "isEnabled": true, + "rate": "5220000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "496000000000000000000000", + "isEnabled": true, + "rate": "5753600000000000000" + }, + "out": { + "capacity": "501000000000000000000000", + "isEnabled": true, + "rate": "5811600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "330000000000000000000000", + "isEnabled": true, + "rate": "3828000000000000000" + }, + "out": { + "capacity": "457000000000000000000000", + "isEnabled": true, + "rate": "5301200000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "658000000000000000000000", + "isEnabled": true, + "rate": "7632800000000000000" + }, + "out": { + "capacity": "636000000000000000000000", + "isEnabled": true, + "rate": "7377600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "539000000000000000000000", + "isEnabled": true, + "rate": "6252400000000000000" + }, + "out": { + "capacity": "670000000000000000000000", + "isEnabled": true, + "rate": "7772000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "384000000000000000000000", + "isEnabled": true, + "rate": "4454400000000000000" + }, + "out": { + "capacity": "594000000000000000000000", + "isEnabled": true, + "rate": "6890400000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "567000000000000000000000", + "isEnabled": true, + "rate": "6577200000000000000" + }, + "out": { + "capacity": "573000000000000000000000", + "isEnabled": true, + "rate": "6646800000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "660000000000000000000000", + "isEnabled": true, + "rate": "7656000000000000000" + }, + "out": { + "capacity": "356000000000000000000000", + "isEnabled": true, + "rate": "4129600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "334000000000000000000000", + "isEnabled": true, + "rate": "3874400000000000000" + }, + "out": { + "capacity": "556000000000000000000000", + "isEnabled": true, + "rate": "6449600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "324000000000000000000000", + "isEnabled": true, + "rate": "3758400000000000000" + }, + "out": { + "capacity": "386000000000000000000000", + "isEnabled": true, + "rate": "4477600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "363000000000000000000000", + "isEnabled": true, + "rate": "4210800000000000000" + }, + "out": { + "capacity": "394000000000000000000000", + "isEnabled": true, + "rate": "4570400000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "563000000000000000000000", + "isEnabled": true, + "rate": "6530800000000000000" + }, + "out": { + "capacity": "601000000000000000000000", + "isEnabled": true, + "rate": "6971600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "387000000000000000000000", + "isEnabled": true, + "rate": "4489200000000000000" + }, + "out": { + "capacity": "381000000000000000000000", + "isEnabled": true, + "rate": "4419600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "387000000000000000000000", + "isEnabled": true, + "rate": "4489200000000000000" + }, + "out": { + "capacity": "542000000000000000000000", + "isEnabled": true, + "rate": "6287200000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "613000000000000000000000", + "isEnabled": true, + "rate": "7110800000000000000" + }, + "out": { + "capacity": "321000000000000000000000", + "isEnabled": true, + "rate": "3723600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "342000000000000000000000", + "isEnabled": true, + "rate": "3967200000000000000" + }, + "out": { + "capacity": "345000000000000000000000", + "isEnabled": true, + "rate": "4002000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "427000000000000000000000", + "isEnabled": true, + "rate": "4953200000000000000" + }, + "out": { + "capacity": "669000000000000000000000", + "isEnabled": true, + "rate": "7760400000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "491000000000000000000000", + "isEnabled": true, + "rate": "5695600000000000000" + }, + "out": { + "capacity": "418000000000000000000000", + "isEnabled": true, + "rate": "4848800000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + } + } + }, + "ethereum-mainnet-zksync-1": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "315000000000000000000000", + "isEnabled": true, + "rate": "3654000000000000000" + }, + "out": { + "capacity": "637000000000000000000000", + "isEnabled": true, + "rate": "7389200000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "652000000000000000000000", + "isEnabled": true, + "rate": "7563200000000000000" + }, + "out": { + "capacity": "307000000000000000000000", + "isEnabled": true, + "rate": "3561200000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "439000000000000000000000", + "isEnabled": true, + "rate": "5092400000000000000" + }, + "out": { + "capacity": "483000000000000000000000", + "isEnabled": true, + "rate": "5602800000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "300000000000000000000000", + "isEnabled": true, + "rate": "3480000000000000000" + }, + "out": { + "capacity": "674000000000000000000000", + "isEnabled": true, + "rate": "7818400000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "617000000000000000000000", + "isEnabled": true, + "rate": "7157200000000000000" + }, + "out": { + "capacity": "326000000000000000000000", + "isEnabled": true, + "rate": "3781600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "349000000000000000000000", + "isEnabled": true, + "rate": "4048400000000000000" + }, + "out": { + "capacity": "344000000000000000000000", + "isEnabled": true, + "rate": "3990400000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "582000000000000000000000", + "isEnabled": true, + "rate": "6751200000000000000" + }, + "out": { + "capacity": "313000000000000000000000", + "isEnabled": true, + "rate": "3630800000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "487000000000000000000000", + "isEnabled": true, + "rate": "5649200000000000000" + }, + "out": { + "capacity": "478000000000000000000000", + "isEnabled": true, + "rate": "5544800000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "405000000000000000000000", + "isEnabled": true, + "rate": "4698000000000000000" + }, + "out": { + "capacity": "640000000000000000000000", + "isEnabled": true, + "rate": "7424000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "401000000000000000000000", + "isEnabled": true, + "rate": "4651600000000000000" + }, + "out": { + "capacity": "665000000000000000000000", + "isEnabled": true, + "rate": "7714000000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "654000000000000000000000", + "isEnabled": true, + "rate": "7586400000000000000" + }, + "out": { + "capacity": "677000000000000000000000", + "isEnabled": true, + "rate": "7853200000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "480000000000000000000000", + "isEnabled": true, + "rate": "5568000000000000000" + }, + "out": { + "capacity": "514000000000000000000000", + "isEnabled": true, + "rate": "5962400000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "562000000000000000000000", + "isEnabled": true, + "rate": "6519200000000000000" + }, + "out": { + "capacity": "367000000000000000000000", + "isEnabled": true, + "rate": "4257200000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "322000000000000000000000", + "isEnabled": true, + "rate": "3735200000000000000" + }, + "out": { + "capacity": "686000000000000000000000", + "isEnabled": true, + "rate": "7957600000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "350000000000000000000000", + "isEnabled": true, + "rate": "4060000000000000000" + }, + "out": { + "capacity": "452000000000000000000000", + "isEnabled": true, + "rate": "5243200000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "418000000000000000000000", + "isEnabled": true, + "rate": "4848800000000000000" + }, + "out": { + "capacity": "629000000000000000000000", + "isEnabled": true, + "rate": "7296400000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "363000000000000000000000", + "isEnabled": true, + "rate": "4210800000000000000" + }, + "out": { + "capacity": "389000000000000000000000", + "isEnabled": true, + "rate": "4512400000000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + }, + "out": { + "capacity": "1000000000000000000000000", + "isEnabled": true, + "rate": "11600000000000000000" + } + } + } + } + } + }, + "USDO": { + "bsc-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "7276500000000000000000000", + "isEnabled": true, + "rate": "803880000000000000000" + }, + "out": { + "capacity": "6430000000000000000000000", + "isEnabled": true, + "rate": "745880000000000000000" + } + }, + "standard": { + "in": { + "capacity": "10500000000000000000000000", + "isEnabled": true, + "rate": "1160000000000000000000" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1160000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "5838000000000000000000000", + "isEnabled": true, + "rate": "644960000000000000000" + }, + "out": { + "capacity": "4830000000000000000000000", + "isEnabled": true, + "rate": "560280000000000000000" + } + }, + "standard": { + "in": { + "capacity": "10500000000000000000000000", + "isEnabled": true, + "rate": "1160000000000000000000" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1160000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "3391500000000000000000000", + "isEnabled": true, + "rate": "374680000000000000000" + }, + "out": { + "capacity": "5800000000000000000000000", + "isEnabled": true, + "rate": "672800000000000000000" + } + }, + "standard": { + "in": { + "capacity": "10500000000000000000000000", + "isEnabled": true, + "rate": "1160000000000000000000" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1160000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + }, + "out": { + "capacity": "2020000000000000000000000", + "isEnabled": true, + "rate": "23379641600000000000" + } + }, + "standard": { + "in": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870400000000000000" + } + } + } + } + }, + "kaia-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "7686000000000000000000000", + "isEnabled": true, + "rate": "84912000000000000000" + }, + "out": { + "capacity": "13680000000000000000000000", + "isEnabled": true, + "rate": "158688000000000000000" + } + }, + "standard": { + "in": { + "capacity": "21000000000000000000000000", + "isEnabled": true, + "rate": "232000000000000000000" + }, + "out": { + "capacity": "20000000000000000000000000", + "isEnabled": true, + "rate": "232000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 10, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "7213500000000000000000000", + "isEnabled": true, + "rate": "796920000000000000000" + }, + "out": { + "capacity": "3920000000000000000000000", + "isEnabled": true, + "rate": "454720000000000000000" + } + }, + "standard": { + "in": { + "capacity": "10500000000000000000000000", + "isEnabled": true, + "rate": "1160000000000000000000" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1160000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "3674000000000000000000000", + "isEnabled": true, + "rate": "42523169920000000000" + }, + "out": { + "capacity": "1", + "isEnabled": true, + "rate": "0" + } + }, + "standard": { + "in": { + "capacity": "5500000000000000000000000", + "isEnabled": true, + "rate": "63657440000000000000" + }, + "out": { + "capacity": "2", + "isEnabled": true, + "rate": "1" + } + } + }, + "kaia-mainnet": { + "custom": { + "in": { + "capacity": "14238000000000000000000000", + "isEnabled": true, + "rate": "157296000000000000000" + }, + "out": { + "capacity": "6420000000000000000000000", + "isEnabled": true, + "rate": "74472000000000000000" + } + }, + "standard": { + "in": { + "capacity": "21000000000000000000000000", + "isEnabled": true, + "rate": "232000000000000000000" + }, + "out": { + "capacity": "20000000000000000000000000", + "isEnabled": true, + "rate": "232000000000000000000" + } + } + } + } + } + }, + "USDT": { + "0g-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "3590000000000", + "isEnabled": true, + "rate": "1795000000" + }, + "out": { + "capacity": "5130000000000", + "isEnabled": true, + "rate": "2565000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "16850000000", + "isEnabled": true, + "rate": "3370000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "50000000000", + "isEnabled": true, + "rate": "10000000" + } + } + } + } + }, + "bitcoin-mainnet-bob-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "5960000000000", + "isEnabled": true, + "rate": "2980000000" + }, + "out": { + "capacity": "5120000000000", + "isEnabled": true, + "rate": "2560000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "4020000000000", + "isEnabled": true, + "rate": "2010000000" + }, + "out": { + "capacity": "6600000000000", + "isEnabled": true, + "rate": "3300000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "3170000000000", + "isEnabled": true, + "rate": "1585000000" + }, + "out": { + "capacity": "5890000000000", + "isEnabled": true, + "rate": "2945000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + }, + "bitcoin-mainnet-botanix": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "3040000000000", + "isEnabled": true, + "rate": "1520000000" + }, + "out": { + "capacity": "6900000000000", + "isEnabled": true, + "rate": "3450000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + }, + "celo-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "4310000000000", + "isEnabled": true, + "rate": "2155000000" + }, + "out": { + "capacity": "5170000000000", + "isEnabled": true, + "rate": "2585000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "4450000000000", + "isEnabled": true, + "rate": "2225000000" + }, + "out": { + "capacity": "5060000000000", + "isEnabled": true, + "rate": "2530000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "6730000000000", + "isEnabled": true, + "rate": "3365000000" + }, + "out": { + "capacity": "3820000000000", + "isEnabled": true, + "rate": "1910000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "celo-mainnet": { + "custom": { + "in": { + "capacity": "4620000000000", + "isEnabled": true, + "rate": "2310000000" + }, + "out": { + "capacity": "4190000000000", + "isEnabled": true, + "rate": "2095000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-hashkey-1": { + "custom": { + "in": { + "capacity": "4080000000000", + "isEnabled": true, + "rate": "2040000000" + }, + "out": { + "capacity": "4240000000000", + "isEnabled": true, + "rate": "2120000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "3600000000000", + "isEnabled": true, + "rate": "1800000000" + }, + "out": { + "capacity": "5900000000000", + "isEnabled": true, + "rate": "2950000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "3380000000000", + "isEnabled": true, + "rate": "1690000000" + }, + "out": { + "capacity": "3790000000000", + "isEnabled": true, + "rate": "1895000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + }, + "ethereum-mainnet-hashkey-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "3120000000000", + "isEnabled": true, + "rate": "1560000000" + }, + "out": { + "capacity": "3760000000000", + "isEnabled": true, + "rate": "1880000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "4980000000000", + "isEnabled": true, + "rate": "2490000000" + }, + "out": { + "capacity": "6080000000000", + "isEnabled": true, + "rate": "3040000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "4330000000000", + "isEnabled": true, + "rate": "2165000000" + }, + "out": { + "capacity": "4650000000000", + "isEnabled": true, + "rate": "2325000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 2, + "remote": { + "celo-mainnet": { + "custom": { + "in": { + "capacity": "3890000000000", + "isEnabled": true, + "rate": "1945000000" + }, + "out": { + "capacity": "4420000000000", + "isEnabled": true, + "rate": "2210000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "5030000000000", + "isEnabled": true, + "rate": "2515000000" + }, + "out": { + "capacity": "4660000000000", + "isEnabled": true, + "rate": "2330000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-hashkey-1": { + "custom": { + "in": { + "capacity": "5450000000000", + "isEnabled": true, + "rate": "2725000000" + }, + "out": { + "capacity": "6780000000000", + "isEnabled": true, + "rate": "3390000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "4100000000000", + "isEnabled": true, + "rate": "2050000000" + }, + "out": { + "capacity": "6560000000000", + "isEnabled": true, + "rate": "3280000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "5420000000000", + "isEnabled": true, + "rate": "2710000000" + }, + "out": { + "capacity": "6140000000000", + "isEnabled": true, + "rate": "3070000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "0g-mainnet": { + "custom": { + "in": { + "capacity": "5140000000000", + "isEnabled": true, + "rate": "2570000000" + }, + "out": { + "capacity": "5060000000000", + "isEnabled": true, + "rate": "2530000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "5570000000000", + "isEnabled": true, + "rate": "2785000000" + }, + "out": { + "capacity": "4390000000000", + "isEnabled": true, + "rate": "2195000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "bitcoin-mainnet-botanix": { + "custom": { + "in": { + "capacity": "3380000000000", + "isEnabled": true, + "rate": "1690000000" + }, + "out": { + "capacity": "3600000000000", + "isEnabled": true, + "rate": "1800000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "celo-mainnet": { + "custom": { + "in": { + "capacity": "4990000000000", + "isEnabled": true, + "rate": "2495000000" + }, + "out": { + "capacity": "6970000000000", + "isEnabled": true, + "rate": "3485000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "5880000000000", + "isEnabled": true, + "rate": "2940000000" + }, + "out": { + "capacity": "6300000000000", + "isEnabled": true, + "rate": "3150000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-hashkey-1": { + "custom": { + "in": { + "capacity": "5100000000000", + "isEnabled": true, + "rate": "2550000000" + }, + "out": { + "capacity": "6150000000000", + "isEnabled": true, + "rate": "3075000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "6150000000000", + "isEnabled": true, + "rate": "3075000000" + }, + "out": { + "capacity": "4040000000000", + "isEnabled": true, + "rate": "2020000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "6310000000000", + "isEnabled": true, + "rate": "3155000000" + }, + "out": { + "capacity": "6280000000000", + "isEnabled": true, + "rate": "3140000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "4540000000000", + "isEnabled": true, + "rate": "2270000000" + }, + "out": { + "capacity": "5930000000000", + "isEnabled": true, + "rate": "2965000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "4280000000000", + "isEnabled": true, + "rate": "2140000000" + }, + "out": { + "capacity": "6820000000000", + "isEnabled": true, + "rate": "3410000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "6640000000000", + "isEnabled": true, + "rate": "3320000000" + }, + "out": { + "capacity": "4700000000000", + "isEnabled": true, + "rate": "2350000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "6220000000000", + "isEnabled": true, + "rate": "3110000000" + }, + "out": { + "capacity": "6230000000000", + "isEnabled": true, + "rate": "3115000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + }, + "out": { + "capacity": "10000000000000", + "isEnabled": true, + "rate": "5000000000" + } + } + } + } + } + }, + "USELESS": { + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "USUAL": { + "bsc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1431000000000000000000000", + "isEnabled": true, + "rate": "16695000000000000000" + }, + "out": { + "capacity": "2034000000000000000000000", + "isEnabled": true, + "rate": "23730000000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1356000000000000000000000", + "isEnabled": true, + "rate": "15820000000000000000" + }, + "out": { + "capacity": "1557000000000000000000000", + "isEnabled": true, + "rate": "18165000000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1707000000000000000000000", + "isEnabled": true, + "rate": "19915000000000000000" + }, + "out": { + "capacity": "930000000000000000000000", + "isEnabled": true, + "rate": "10850000000000000000" + } + }, + "standard": { + "in": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + }, + "out": { + "capacity": "3000000000000000000000000", + "isEnabled": true, + "rate": "35000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + } + } + } + }, + "USX": { + "plasma-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": null, + "remote": { + "plasma-mainnet": { + "custom": null, + "standard": null + } + } + } + }, + "VOOI": { + "bsc-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "VRTX": { + "avalanche-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "6770000000000000000000000", + "isEnabled": true, + "rate": "677000000000000000000000" + }, + "out": { + "capacity": "3420000000000000000000000", + "isEnabled": true, + "rate": "342000000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000000000" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "2200000000000000000000000", + "isEnabled": true, + "rate": "25462800000000000000" + }, + "out": { + "capacity": "1740000000000000000000000", + "isEnabled": true, + "rate": "20138760000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + } + } + }, + "ethereum-mainnet-blast-1": { + "custom": { + "in": { + "capacity": "3160000000000000000000000", + "isEnabled": true, + "rate": "36573840000000000000" + }, + "out": { + "capacity": "1885000000000000000000000", + "isEnabled": true, + "rate": "21816990000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + } + } + }, + "ethereum-mainnet-mantle-1": { + "custom": { + "in": { + "capacity": "2810000000000000000000000", + "isEnabled": true, + "rate": "32522940000000000000" + }, + "out": { + "capacity": "3090000000000000000000000", + "isEnabled": true, + "rate": "35763660000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "5440000000000000000000000", + "isEnabled": true, + "rate": "544000000000000000000000" + }, + "out": { + "capacity": "4570000000000000000000000", + "isEnabled": true, + "rate": "457000000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000000000" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "2060000000000000000000000", + "isEnabled": true, + "rate": "23842440000000000000" + }, + "out": { + "capacity": "1895000000000000000000000", + "isEnabled": true, + "rate": "21932730000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + } + } + }, + "ethereum-mainnet-blast-1": { + "custom": { + "in": { + "capacity": "2845000000000000000000000", + "isEnabled": true, + "rate": "32928030000000000000" + }, + "out": { + "capacity": "2720000000000000000000000", + "isEnabled": true, + "rate": "31481280000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-blast-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1670000000000000000000000", + "isEnabled": true, + "rate": "19328580000000000000" + }, + "out": { + "capacity": "1530000000000000000000000", + "isEnabled": true, + "rate": "17708220000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "2715000000000000000000000", + "isEnabled": true, + "rate": "31423410000000000000" + }, + "out": { + "capacity": "1785000000000000000000000", + "isEnabled": true, + "rate": "20659590000000000000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + }, + "out": { + "capacity": "5000000000000000000000000", + "isEnabled": true, + "rate": "57870000000000000000" + } + } + } + } + }, + "ethereum-mainnet-mantle-1": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "sei-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "6690000000000000000000000", + "isEnabled": true, + "rate": "669000000000000000000000" + }, + "out": { + "capacity": "4380000000000000000000000", + "isEnabled": true, + "rate": "438000000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000000000" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "VSN": { + "bsc-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "29947500000000000000000000", + "isEnabled": true, + "rate": "25047000000000000000" + }, + "out": { + "capacity": "47850000000000000000000000", + "isEnabled": true, + "rate": "44022000000000000000" + } + }, + "standard": { + "in": { + "capacity": "82500000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + }, + "out": { + "capacity": "75000000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "33825000000000000000000000", + "isEnabled": true, + "rate": "28290000000000000000" + }, + "out": { + "capacity": "38100000000000000000000000", + "isEnabled": true, + "rate": "35052000000000000000" + } + }, + "standard": { + "in": { + "capacity": "82500000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + }, + "out": { + "capacity": "75000000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "41085000000000000000000000", + "isEnabled": true, + "rate": "34362000000000000000" + }, + "out": { + "capacity": "40650000000000000000000000", + "isEnabled": true, + "rate": "37398000000000000000" + } + }, + "standard": { + "in": { + "capacity": "82500000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + }, + "out": { + "capacity": "75000000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "53377500000000000000000000", + "isEnabled": true, + "rate": "44643000000000000000" + }, + "out": { + "capacity": "49725000000000000000000000", + "isEnabled": true, + "rate": "45747000000000000000" + } + }, + "standard": { + "in": { + "capacity": "82500000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + }, + "out": { + "capacity": "75000000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + } + } + } + } + }, + "hyperliquid-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "25162500000000000000000000", + "isEnabled": true, + "rate": "21045000000000000000" + }, + "out": { + "capacity": "32025000000000000000000000", + "isEnabled": true, + "rate": "29463000000000000000" + } + }, + "standard": { + "in": { + "capacity": "82500000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + }, + "out": { + "capacity": "75000000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "45375000000000000000000000", + "isEnabled": true, + "rate": "37950000000000000000" + }, + "out": { + "capacity": "37875000000000000000000000", + "isEnabled": true, + "rate": "34845000000000000000" + } + }, + "standard": { + "in": { + "capacity": "82500000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + }, + "out": { + "capacity": "75000000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "29370000000000000000000000", + "isEnabled": true, + "rate": "24564000000000000000" + }, + "out": { + "capacity": "52350000000000000000000000", + "isEnabled": true, + "rate": "48162000000000000000" + } + }, + "standard": { + "in": { + "capacity": "82500000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + }, + "out": { + "capacity": "75000000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "36877500000000000000000000", + "isEnabled": true, + "rate": "30843000000000000000" + }, + "out": { + "capacity": "30900000000000000000000000", + "isEnabled": true, + "rate": "28428000000000000000" + } + }, + "standard": { + "in": { + "capacity": "82500000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + }, + "out": { + "capacity": "75000000000000000000000000", + "isEnabled": true, + "rate": "69000000000000000000" + } + } + } + } + } + }, + "W0G": { + "0g-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 9, + "remote": { + "0g-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 8, + "remote": { + "0g-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "0g-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "WASTR": { + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "polkadot-mainnet-astar": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "4880000000000000000000000", + "isEnabled": true, + "rate": "1355664000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "2778000000000000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "3270000000000000000000000", + "isEnabled": true, + "rate": "908406000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "2778000000000000000000" + } + } + } + } + }, + "polkadot-mainnet-astar": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "5190000000000000000000000", + "isEnabled": true, + "rate": "1441782000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "10000000000000000000000000", + "isEnabled": true, + "rate": "2778000000000000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "10720000000000000000000000", + "isEnabled": true, + "rate": "2978016000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "20000000000000000000000000", + "isEnabled": true, + "rate": "5556000000000000000000" + } + } + } + } + }, + "soneium-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polkadot-mainnet-astar": { + "custom": null, + "standard": null + } + } + } + }, + "WBTC": { + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "2100000000", + "isEnabled": true, + "rate": "24305" + }, + "out": { + "capacity": "2381400000", + "isEnabled": true, + "rate": "27562" + } + }, + "standard": { + "in": { + "capacity": "4200000000", + "isEnabled": true, + "rate": "48610" + }, + "out": { + "capacity": "3780000000", + "isEnabled": true, + "rate": "43750" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1650600000", + "isEnabled": true, + "rate": "19103" + }, + "out": { + "capacity": "2570400000", + "isEnabled": true, + "rate": "29750" + } + }, + "standard": { + "in": { + "capacity": "4200000000", + "isEnabled": true, + "rate": "48610" + }, + "out": { + "capacity": "3780000000", + "isEnabled": true, + "rate": "43750" + } + } + } + } + } + }, + "WECO": { + "bsc-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "189000000000000000000000000", + "isEnabled": true, + "rate": "13124160000000000000000" + }, + "out": { + "capacity": "190000000000000000000000000", + "isEnabled": true, + "rate": "13193600000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "177500000000000000000000000", + "isEnabled": true, + "rate": "12325600000000000000000" + }, + "out": { + "capacity": "220500000000000000000000000", + "isEnabled": true, + "rate": "15311520000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "176000000000000000000000000", + "isEnabled": true, + "rate": "12221440000000000000000" + }, + "out": { + "capacity": "253000000000000000000000000", + "isEnabled": true, + "rate": "17568320000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "216500000000000000000000000", + "isEnabled": true, + "rate": "15033760000000000000000" + }, + "out": { + "capacity": "322500000000000000000000000", + "isEnabled": true, + "rate": "22394400000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "199500000000000000000000000", + "isEnabled": true, + "rate": "13853280000000000000000" + }, + "out": { + "capacity": "193000000000000000000000000", + "isEnabled": true, + "rate": "13401920000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "302000000000000000000000000", + "isEnabled": true, + "rate": "20970880000000000000000" + }, + "out": { + "capacity": "238000000000000000000000000", + "isEnabled": true, + "rate": "16526720000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "198500000000000000000000000", + "isEnabled": true, + "rate": "13783840000000000000000" + }, + "out": { + "capacity": "211500000000000000000000000", + "isEnabled": true, + "rate": "14686560000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + }, + "matic-mainnet": { + "custom": null, + "standard": null + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "168000000000000000000000000", + "isEnabled": true, + "rate": "11665920000000000000000" + }, + "out": { + "capacity": "167000000000000000000000000", + "isEnabled": true, + "rate": "11596480000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "204000000000000000000000000", + "isEnabled": true, + "rate": "14165760000000000000000" + }, + "out": { + "capacity": "253000000000000000000000000", + "isEnabled": true, + "rate": "17568320000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "254500000000000000000000000", + "isEnabled": true, + "rate": "17672480000000000000000" + }, + "out": { + "capacity": "168000000000000000000000000", + "isEnabled": true, + "rate": "11665920000000000000000" + } + }, + "standard": { + "in": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + }, + "out": { + "capacity": "500000000000000000000000000", + "isEnabled": true, + "rate": "34720000000000000000000" + } + } + } + } + } + }, + "WETH": { + "bitcoin-mainnet-bitlayer-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "12366000000000000000", + "isEnabled": true, + "rate": "3435000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "18000000000000000000", + "isEnabled": true, + "rate": "5000000000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "36481500000000000000", + "isEnabled": true, + "rate": "10133748660000000" + }, + "out": { + "capacity": "28314000000000000000", + "isEnabled": true, + "rate": "7864998960000000" + } + }, + "standard": { + "in": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "52635000000000000000", + "isEnabled": true, + "rate": "14620831400000000" + }, + "out": { + "capacity": "47825250000000000000", + "isEnabled": true, + "rate": "13284789910000000" + } + }, + "standard": { + "in": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "31458960000000000000", + "isEnabled": true, + "rate": "8738599999999999" + }, + "out": { + "capacity": "60076500000000000000", + "isEnabled": true, + "rate": "16687916666666666" + } + }, + "standard": { + "in": { + "capacity": "100830000000000000000", + "isEnabled": true, + "rate": "28008333333333333" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208333333333333" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "47280750000000000000", + "isEnabled": true, + "rate": "13133539930000000" + }, + "out": { + "capacity": "43923000000000000000", + "isEnabled": true, + "rate": "12200831720000000" + } + }, + "standard": { + "in": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "37389000000000000000", + "isEnabled": true, + "rate": "10385831960000000" + }, + "out": { + "capacity": "30764250000000000000", + "isEnabled": true, + "rate": "8545623870000000" + } + }, + "standard": { + "in": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "58481400000000000000", + "isEnabled": true, + "rate": "16244833333333333" + }, + "out": { + "capacity": "60984000000000000000", + "isEnabled": true, + "rate": "16939999999999999" + } + }, + "standard": { + "in": { + "capacity": "100830000000000000000", + "isEnabled": true, + "rate": "28008333333333333" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208333333333333" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "13453200000000000000", + "isEnabled": true, + "rate": "3737000000000000" + }, + "out": { + "capacity": "9120000000000000000", + "isEnabled": true, + "rate": "2533333333333333" + } + }, + "standard": { + "in": { + "capacity": "33300000000000000000", + "isEnabled": true, + "rate": "9250000000000000" + }, + "out": { + "capacity": "30000000000000000000", + "isEnabled": true, + "rate": "8333333333333333" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "61528500000000000000", + "isEnabled": true, + "rate": "17091247740000000" + }, + "out": { + "capacity": "47825250000000000000", + "isEnabled": true, + "rate": "13284789910000000" + } + }, + "standard": { + "in": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "57263250000000000000", + "isEnabled": true, + "rate": "15906456230000000" + }, + "out": { + "capacity": "36753750000000000000", + "isEnabled": true, + "rate": "10209373650000000" + } + }, + "standard": { + "in": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208330000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "31458960000000000000", + "isEnabled": true, + "rate": "8738599999999999" + }, + "out": { + "capacity": "57807750000000000000", + "isEnabled": true, + "rate": "16057708333333333" + } + }, + "standard": { + "in": { + "capacity": "100830000000000000000", + "isEnabled": true, + "rate": "28008333333333333" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208333333333333" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "36252000000000000000", + "isEnabled": true, + "rate": "10176000000000000" + }, + "out": { + "capacity": "38760000000000000000", + "isEnabled": true, + "rate": "10880000000000000" + } + }, + "standard": { + "in": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + }, + "out": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "40634490000000000000", + "isEnabled": true, + "rate": "11287358333333333" + }, + "out": { + "capacity": "33033000000000000000", + "isEnabled": true, + "rate": "9175833333333333" + } + }, + "standard": { + "in": { + "capacity": "100830000000000000000", + "isEnabled": true, + "rate": "28008333333333333" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208333333333333" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "35290500000000000000", + "isEnabled": true, + "rate": "9802916666666666" + }, + "out": { + "capacity": "40928250000000000000", + "isEnabled": true, + "rate": "11368958333333333" + } + }, + "standard": { + "in": { + "capacity": "100830000000000000000", + "isEnabled": true, + "rate": "28008333333333333" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208333333333333" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "17582400000000000000", + "isEnabled": true, + "rate": "4884000000000000" + }, + "out": { + "capacity": "17940000000000000000", + "isEnabled": true, + "rate": "4983333333333333" + } + }, + "standard": { + "in": { + "capacity": "33300000000000000000", + "isEnabled": true, + "rate": "9250000000000000" + }, + "out": { + "capacity": "30000000000000000000", + "isEnabled": true, + "rate": "8333333333333333" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "59792190000000000000", + "isEnabled": true, + "rate": "16608941666666666" + }, + "out": { + "capacity": "39476250000000000000", + "isEnabled": true, + "rate": "10965624999999999" + } + }, + "standard": { + "in": { + "capacity": "100830000000000000000", + "isEnabled": true, + "rate": "28008333333333333" + }, + "out": { + "capacity": "90750000000000000000", + "isEnabled": true, + "rate": "25208333333333333" + } + } + }, + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "WFRAGSOL": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 3, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "1000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "WHLP": { + "hyperliquid-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "WHSK": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-hashkey-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-hashkey-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-hashkey-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "WHY": { + "bsc-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "WLD": { + "ethereum-mainnet-worldchain-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "36900000000000000000000", + "isEnabled": true, + "rate": "10249971300000000000" + }, + "out": { + "capacity": "67900000000000000000000", + "isEnabled": true, + "rate": "18861058300000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27777700000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27777700000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-worldchain-1": { + "custom": { + "in": { + "capacity": "50900000000000000000000", + "isEnabled": true, + "rate": "14138849300000000000" + }, + "out": { + "capacity": "67300000000000000000000", + "isEnabled": true, + "rate": "18694392100000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27777700000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "27777700000000000000" + } + } + } + } + } + }, + "WLFI": { + "bsc-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "WMTX": { + "bsc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "602000000000", + "isEnabled": true, + "rate": "167217540" + }, + "out": { + "capacity": "532000000000", + "isEnabled": true, + "rate": "147773640" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1865000000000", + "isEnabled": true, + "rate": "86349500" + }, + "out": { + "capacity": "3305000000000", + "isEnabled": true, + "rate": "153021500" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "231500000" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "231500000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "561000000000", + "isEnabled": true, + "rate": "155828970" + }, + "out": { + "capacity": "560000000000", + "isEnabled": true, + "rate": "155551200" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 10, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "499000000000", + "isEnabled": true, + "rate": "138607230" + }, + "out": { + "capacity": "349000000000", + "isEnabled": true, + "rate": "96941730" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "617000000000", + "isEnabled": true, + "rate": "171384090" + }, + "out": { + "capacity": "382000000000", + "isEnabled": true, + "rate": "106108140" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "3255000000000", + "isEnabled": true, + "rate": "150706500" + }, + "out": { + "capacity": "2795000000000", + "isEnabled": true, + "rate": "129408500" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "231500000" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "231500000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "353000000000", + "isEnabled": true, + "rate": "98052810" + }, + "out": { + "capacity": "324000000000", + "isEnabled": true, + "rate": "89997480" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "494000000000", + "isEnabled": true, + "rate": "137218380" + }, + "out": { + "capacity": "529000000000", + "isEnabled": true, + "rate": "146940330" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "384000000000", + "isEnabled": true, + "rate": "106663680" + }, + "out": { + "capacity": "368000000000", + "isEnabled": true, + "rate": "102219360" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "351000000000", + "isEnabled": true, + "rate": "97497270" + }, + "out": { + "capacity": "497000000000", + "isEnabled": true, + "rate": "138051690" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "306000000000", + "isEnabled": true, + "rate": "84997620" + }, + "out": { + "capacity": "638000000000", + "isEnabled": true, + "rate": "177217260" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 5, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "2600000000000", + "isEnabled": true, + "rate": "120380000" + }, + "out": { + "capacity": "2820000000000", + "isEnabled": true, + "rate": "130566000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "231500000" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "231500000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "2600000000000", + "isEnabled": true, + "rate": "120380000" + }, + "out": { + "capacity": "3420000000000", + "isEnabled": true, + "rate": "158346000" + } + }, + "standard": { + "in": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "231500000" + }, + "out": { + "capacity": "5000000000000", + "isEnabled": true, + "rate": "231500000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "606000000000", + "isEnabled": true, + "rate": "168328620" + }, + "out": { + "capacity": "536000000000", + "isEnabled": true, + "rate": "148884720" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "681000000000", + "isEnabled": true, + "rate": "189161370" + }, + "out": { + "capacity": "666000000000", + "isEnabled": true, + "rate": "184994820" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "533000000000", + "isEnabled": true, + "rate": "148051410" + }, + "out": { + "capacity": "626000000000", + "isEnabled": true, + "rate": "173884020" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "501000000000", + "isEnabled": true, + "rate": "139162770" + }, + "out": { + "capacity": "581000000000", + "isEnabled": true, + "rate": "161384370" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "567000000000", + "isEnabled": true, + "rate": "157495590" + }, + "out": { + "capacity": "484000000000", + "isEnabled": true, + "rate": "134440680" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "382000000000", + "isEnabled": true, + "rate": "106108140" + }, + "out": { + "capacity": "495000000000", + "isEnabled": true, + "rate": "137496150" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "277770000" + } + } + } + } + } + }, + "wOETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "70566000000000000000", + "isEnabled": true, + "rate": "19808000000000000" + }, + "out": { + "capacity": "78774000000000000000", + "isEnabled": true, + "rate": "22112000000000000" + } + }, + "standard": { + "in": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + }, + "out": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "924000000000000000000", + "isEnabled": true, + "rate": "256872000000000000" + }, + "out": { + "capacity": "825000000000000000000", + "isEnabled": true, + "rate": "229350000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000", + "isEnabled": true, + "rate": "417000000000000000" + }, + "out": { + "capacity": "1500000000000000000000", + "isEnabled": true, + "rate": "417000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "77178000000000000000", + "isEnabled": true, + "rate": "21664000000000000" + }, + "out": { + "capacity": "39102000000000000000", + "isEnabled": true, + "rate": "10976000000000000" + } + }, + "standard": { + "in": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + }, + "out": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "400000000000000000000", + "isEnabled": true, + "rate": "111120000000000000" + }, + "out": { + "capacity": "682000000000000000000", + "isEnabled": true, + "rate": "189459600000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "277800000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "277800000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "493500000000000000000", + "isEnabled": true, + "rate": "137193000000000000" + }, + "out": { + "capacity": "484500000000000000000", + "isEnabled": true, + "rate": "134691000000000000" + } + }, + "standard": { + "in": { + "capacity": "1500000000000000000000", + "isEnabled": true, + "rate": "417000000000000000" + }, + "out": { + "capacity": "1500000000000000000000", + "isEnabled": true, + "rate": "417000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "414000000000000000000", + "isEnabled": true, + "rate": "115009200000000000" + }, + "out": { + "capacity": "671000000000000000000", + "isEnabled": true, + "rate": "186403800000000000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "277800000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "277800000000000000" + } + } + } + } + } + }, + "WOLF": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "WOW": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "shibarium-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "shibarium-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "WSDM": { + "bsc-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "657000000000", + "isEnabled": true, + "rate": "7884000" + }, + "out": { + "capacity": "596000000000", + "isEnabled": true, + "rate": "7152000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "513000000000", + "isEnabled": true, + "rate": "6156000" + }, + "out": { + "capacity": "558000000000", + "isEnabled": true, + "rate": "6696000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "575000000000", + "isEnabled": true, + "rate": "6900000" + }, + "out": { + "capacity": "574000000000", + "isEnabled": true, + "rate": "6888000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 10, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "305000000000", + "isEnabled": true, + "rate": "3660000" + }, + "out": { + "capacity": "406000000000", + "isEnabled": true, + "rate": "4872000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "522000000000", + "isEnabled": true, + "rate": "6264000" + }, + "out": { + "capacity": "386000000000", + "isEnabled": true, + "rate": "4632000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "500000000000", + "isEnabled": true, + "rate": "6000000" + }, + "out": { + "capacity": "527000000000", + "isEnabled": true, + "rate": "6324000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "598000000000", + "isEnabled": true, + "rate": "7176000" + }, + "out": { + "capacity": "459000000000", + "isEnabled": true, + "rate": "5508000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "674000000000", + "isEnabled": true, + "rate": "8088000" + }, + "out": { + "capacity": "364000000000", + "isEnabled": true, + "rate": "4368000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "485000000000", + "isEnabled": true, + "rate": "5820000" + }, + "out": { + "capacity": "380000000000", + "isEnabled": true, + "rate": "4560000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "315000000000", + "isEnabled": true, + "rate": "3780000" + }, + "out": { + "capacity": "578000000000", + "isEnabled": true, + "rate": "6936000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "474000000000", + "isEnabled": true, + "rate": "5688000" + }, + "out": { + "capacity": "300000000000", + "isEnabled": true, + "rate": "3600000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "394000000000", + "isEnabled": true, + "rate": "4728000" + }, + "out": { + "capacity": "362000000000", + "isEnabled": true, + "rate": "4344000" + } + }, + "standard": { + "in": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + }, + "out": { + "capacity": "1000000000000", + "isEnabled": true, + "rate": "12000000" + } + } + } + } + } + }, + "wstETH": { + "0g-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "71706000000000000000", + "isEnabled": true, + "rate": "20128000000000000" + }, + "out": { + "capacity": "56202000000000000000", + "isEnabled": true, + "rate": "15776000000000000" + } + }, + "standard": { + "in": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + }, + "out": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + } + } + } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "12366000000000000000", + "isEnabled": true, + "rate": "3435000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "18000000000000000000", + "isEnabled": true, + "rate": "5000000000000000" + } + } + } + } + }, + "ethereum-mainnet-ink-1": { + "minBlockConfirmation": 4, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1296000000000000000000", + "isEnabled": true, + "rate": "14999999994720000" + }, + "out": { + "capacity": "742000000000000000000", + "isEnabled": true, + "rate": "8587962959940000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "1342000000000000000000", + "isEnabled": true, + "rate": "15532407401940000" + }, + "out": { + "capacity": "614000000000000000000", + "isEnabled": true, + "rate": "7106481478980000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "946000000000000000000", + "isEnabled": true, + "rate": "10949074070220000" + }, + "out": { + "capacity": "1282000000000000000000", + "isEnabled": true, + "rate": "14837962957740000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "0g-mainnet": { + "custom": null, + "standard": null + }, + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "67944000000000000000", + "isEnabled": true, + "rate": "19072000000000000" + }, + "out": { + "capacity": "75354000000000000000", + "isEnabled": true, + "rate": "21152000000000000" + } + }, + "standard": { + "in": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + }, + "out": { + "capacity": "114000000000000000000", + "isEnabled": true, + "rate": "32000000000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "950000000000000000000", + "isEnabled": true, + "rate": "10995370366500000" + }, + "out": { + "capacity": "730000000000000000000", + "isEnabled": true, + "rate": "8449074071100000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "678000000000000000000", + "isEnabled": true, + "rate": "7847222219460000" + }, + "out": { + "capacity": "806000000000000000000", + "isEnabled": true, + "rate": "9328703700420000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "658000000000000000000", + "isEnabled": true, + "rate": "7615740738060000" + }, + "out": { + "capacity": "1274000000000000000000", + "isEnabled": true, + "rate": "14745370365180000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + } + } + }, + "monad-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1234000000000000000000", + "isEnabled": true, + "rate": "14282407402380000" + }, + "out": { + "capacity": "664000000000000000000", + "isEnabled": true, + "rate": "7685185182480000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1268000000000000000000", + "isEnabled": true, + "rate": "14675925920760000" + }, + "out": { + "capacity": "1256000000000000000000", + "isEnabled": true, + "rate": "14537037031920000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "892000000000000000000", + "isEnabled": true, + "rate": "10324074070440000" + }, + "out": { + "capacity": "1292000000000000000000", + "isEnabled": true, + "rate": "14953703698440000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + } + } + }, + "plasma-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-ink-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "11574074070000000" + }, + "out": { + "capacity": "1124000000000000000000", + "isEnabled": true, + "rate": "13009259254680000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + }, + "monad-mainnet": { + "custom": { + "in": { + "capacity": "1244000000000000000000", + "isEnabled": true, + "rate": "14398148143080000" + }, + "out": { + "capacity": "634000000000000000000", + "isEnabled": true, + "rate": "7337962960380000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + }, + "out": { + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" + } + } + } + } + } + }, + "wstLINK": { + "avalanche-mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "9795000000000000000000", + "isEnabled": true, + "rate": "2612000000000000000" + }, + "out": { + "capacity": "7230000000000000000000", + "isEnabled": true, + "rate": "1928000000000000000" + } + }, + "standard": { + "in": { + "capacity": "15000000000000000000000", + "isEnabled": true, + "rate": "4000000000000000000" + }, + "out": { + "capacity": "15000000000000000000000", + "isEnabled": true, + "rate": "4000000000000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "5805000000000000000000", + "isEnabled": true, + "rate": "1548000000000000000" + }, + "out": { + "capacity": "10245000000000000000000", + "isEnabled": true, + "rate": "2732000000000000000" + } + }, + "standard": { + "in": { + "capacity": "15000000000000000000000", + "isEnabled": true, + "rate": "4000000000000000000" + }, + "out": { + "capacity": "15000000000000000000000", + "isEnabled": true, + "rate": "4000000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "wstPOL": { + "avalanche-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "wUSDx": { + "bsc-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "228830000000", + "isEnabled": true, + "rate": "63563837" + }, + "out": { + "capacity": "314580000000", + "isEnabled": true, + "rate": "87383262" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "185710000000", + "isEnabled": true, + "rate": "51586069" + }, + "out": { + "capacity": "327320000000", + "isEnabled": true, + "rate": "90922148" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "231280000000", + "isEnabled": true, + "rate": "64244392" + }, + "out": { + "capacity": "265580000000", + "isEnabled": true, + "rate": "73772162" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "237650000000", + "isEnabled": true, + "rate": "66013835" + }, + "out": { + "capacity": "249900000000", + "isEnabled": true, + "rate": "69416610" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "315070000000", + "isEnabled": true, + "rate": "87519373" + }, + "out": { + "capacity": "215110000000", + "isEnabled": true, + "rate": "59752729" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "294980000000", + "isEnabled": true, + "rate": "81938822" + }, + "out": { + "capacity": "187180000000", + "isEnabled": true, + "rate": "51994402" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "299390000000", + "isEnabled": true, + "rate": "83163821" + }, + "out": { + "capacity": "193060000000", + "isEnabled": true, + "rate": "53627734" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "289590000000", + "isEnabled": true, + "rate": "80441601" + }, + "out": { + "capacity": "331730000000", + "isEnabled": true, + "rate": "92147147" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "189630000000", + "isEnabled": true, + "rate": "52674957" + }, + "out": { + "capacity": "155330000000", + "isEnabled": true, + "rate": "43147187" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "248430000000", + "isEnabled": true, + "rate": "69008277" + }, + "out": { + "capacity": "154350000000", + "isEnabled": true, + "rate": "42874965" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "325360000000", + "isEnabled": true, + "rate": "90377704" + }, + "out": { + "capacity": "316540000000", + "isEnabled": true, + "rate": "87927706" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "165620000000", + "isEnabled": true, + "rate": "46005518" + }, + "out": { + "capacity": "161700000000", + "isEnabled": true, + "rate": "44916630" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "297920000000", + "isEnabled": true, + "rate": "82755488" + }, + "out": { + "capacity": "212660000000", + "isEnabled": true, + "rate": "59072174" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "261660000000", + "isEnabled": true, + "rate": "72683274" + }, + "out": { + "capacity": "246470000000", + "isEnabled": true, + "rate": "68463833" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "271460000000", + "isEnabled": true, + "rate": "75405494" + }, + "out": { + "capacity": "184240000000", + "isEnabled": true, + "rate": "51177736" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "267540000000", + "isEnabled": true, + "rate": "74316606" + }, + "out": { + "capacity": "317520000000", + "isEnabled": true, + "rate": "88199928" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "308210000000", + "isEnabled": true, + "rate": "85613819" + }, + "out": { + "capacity": "213150000000", + "isEnabled": true, + "rate": "59208285" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "171500000000", + "isEnabled": true, + "rate": "47638850" + }, + "out": { + "capacity": "318500000000", + "isEnabled": true, + "rate": "88472150" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + } + } + }, + "ethereum-mainnet-mode-1": { + "minBlockConfirmation": 7, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "202860000000", + "isEnabled": true, + "rate": "56349954" + }, + "out": { + "capacity": "197960000000", + "isEnabled": true, + "rate": "54988844" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "179340000000", + "isEnabled": true, + "rate": "49816626" + }, + "out": { + "capacity": "266560000000", + "isEnabled": true, + "rate": "74044384" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "182280000000", + "isEnabled": true, + "rate": "50633292" + }, + "out": { + "capacity": "218540000000", + "isEnabled": true, + "rate": "60705506" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "247450000000", + "isEnabled": true, + "rate": "68736055" + }, + "out": { + "capacity": "173950000000", + "isEnabled": true, + "rate": "48319405" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "247940000000", + "isEnabled": true, + "rate": "68872166" + }, + "out": { + "capacity": "163660000000", + "isEnabled": true, + "rate": "45461074" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "294980000000", + "isEnabled": true, + "rate": "81938822" + }, + "out": { + "capacity": "173950000000", + "isEnabled": true, + "rate": "48319405" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 5, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "282240000000", + "isEnabled": true, + "rate": "78399936" + }, + "out": { + "capacity": "239610000000", + "isEnabled": true, + "rate": "66558279" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "188160000000", + "isEnabled": true, + "rate": "52266624" + }, + "out": { + "capacity": "267540000000", + "isEnabled": true, + "rate": "74316606" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "235690000000", + "isEnabled": true, + "rate": "65469391" + }, + "out": { + "capacity": "174440000000", + "isEnabled": true, + "rate": "48455516" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "250880000000", + "isEnabled": true, + "rate": "69688832" + }, + "out": { + "capacity": "303310000000", + "isEnabled": true, + "rate": "84252709" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "269500000000", + "isEnabled": true, + "rate": "74861050" + }, + "out": { + "capacity": "281260000000", + "isEnabled": true, + "rate": "78127714" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "177870000000", + "isEnabled": true, + "rate": "49408293" + }, + "out": { + "capacity": "202860000000", + "isEnabled": true, + "rate": "56349954" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "181790000000", + "isEnabled": true, + "rate": "50497181" + }, + "out": { + "capacity": "338100000000", + "isEnabled": true, + "rate": "93916590" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "260680000000", + "isEnabled": true, + "rate": "72411052" + }, + "out": { + "capacity": "148960000000", + "isEnabled": true, + "rate": "41377744" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "254800000000", + "isEnabled": true, + "rate": "70777720" + }, + "out": { + "capacity": "186690000000", + "isEnabled": true, + "rate": "51858291" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "226870000000", + "isEnabled": true, + "rate": "63019393" + }, + "out": { + "capacity": "295960000000", + "isEnabled": true, + "rate": "82211044" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": null, + "standard": null + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "269010000000", + "isEnabled": true, + "rate": "74724939" + }, + "out": { + "capacity": "158760000000", + "isEnabled": true, + "rate": "44099964" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "325360000000", + "isEnabled": true, + "rate": "90377704" + }, + "out": { + "capacity": "295470000000", + "isEnabled": true, + "rate": "82074933" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "214130000000", + "isEnabled": true, + "rate": "59480507" + }, + "out": { + "capacity": "261660000000", + "isEnabled": true, + "rate": "72683274" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "248920000000", + "isEnabled": true, + "rate": "69144388" + }, + "out": { + "capacity": "184240000000", + "isEnabled": true, + "rate": "51177736" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-mode-1": { + "custom": { + "in": { + "capacity": "158760000000", + "isEnabled": true, + "rate": "44099964" + }, + "out": { + "capacity": "249900000000", + "isEnabled": true, + "rate": "69416610" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "303800000000", + "isEnabled": true, + "rate": "84388820" + }, + "out": { + "capacity": "246470000000", + "isEnabled": true, + "rate": "68463833" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "213640000000", + "isEnabled": true, + "rate": "59344396" + }, + "out": { + "capacity": "250390000000", + "isEnabled": true, + "rate": "69552721" + } + }, + "standard": { + "in": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + }, + "out": { + "capacity": "490000000000", + "isEnabled": true, + "rate": "136111000" + } + } + } + } + } + }, + "xGold": { + "bsc-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "hedera-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "hyperliquid-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "hedera-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "bsc-mainnet": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "XLAB": { + "bsc-mainnet": { + "minBlockConfirmation": 1, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "xrETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "xRPL": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "xSILO": { + "avalanche-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "xSolvBTC": { + "avalanche-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "950000000000000000", + "isEnabled": true, + "rate": "43981200000000" + }, + "out": { + "capacity": "1235000000000000000", + "isEnabled": true, + "rate": "57175560000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1335000000000000000", + "isEnabled": true, + "rate": "61805160000000" + }, + "out": { + "capacity": "1057500000000000000", + "isEnabled": true, + "rate": "48958020000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1537500000000000000", + "isEnabled": true, + "rate": "71180100000000" + }, + "out": { + "capacity": "1240000000000000000", + "isEnabled": true, + "rate": "57407040000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1167500000000000000", + "isEnabled": true, + "rate": "54050580000000" + }, + "out": { + "capacity": "1492500000000000000", + "isEnabled": true, + "rate": "69096780000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1460000000000000000", + "isEnabled": true, + "rate": "67592160000000" + }, + "out": { + "capacity": "1727500000000000000", + "isEnabled": true, + "rate": "79976340000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1317500000000000000", + "isEnabled": true, + "rate": "60994980000000" + }, + "out": { + "capacity": "885000000000000000", + "isEnabled": true, + "rate": "40971960000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1457500000000000000", + "isEnabled": true, + "rate": "67476420000000" + }, + "out": { + "capacity": "885000000000000000", + "isEnabled": true, + "rate": "40971960000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1130000000000000000", + "isEnabled": true, + "rate": "52314480000000" + }, + "out": { + "capacity": "800000000000000000", + "isEnabled": true, + "rate": "37036800000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "berachain-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "857500000000000000", + "isEnabled": true, + "rate": "39698820000000" + }, + "out": { + "capacity": "1092500000000000000", + "isEnabled": true, + "rate": "50578380000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1650000000000000000", + "isEnabled": true, + "rate": "76388400000000" + }, + "out": { + "capacity": "1027500000000000000", + "isEnabled": true, + "rate": "47569140000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "810000000000000000", + "isEnabled": true, + "rate": "37499760000000" + }, + "out": { + "capacity": "1267500000000000000", + "isEnabled": true, + "rate": "58680180000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "bitcoin-mainnet-bob-1": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1297500000000000000", + "isEnabled": true, + "rate": "60069060000000" + }, + "out": { + "capacity": "960000000000000000", + "isEnabled": true, + "rate": "44444160000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "887500000000000000", + "isEnabled": true, + "rate": "41087700000000" + }, + "out": { + "capacity": "1027500000000000000", + "isEnabled": true, + "rate": "47569140000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "922500000000000000", + "isEnabled": true, + "rate": "42708060000000" + }, + "out": { + "capacity": "1150000000000000000", + "isEnabled": true, + "rate": "53240400000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "997500000000000000", + "isEnabled": true, + "rate": "46180260000000" + }, + "out": { + "capacity": "1552500000000000000", + "isEnabled": true, + "rate": "71874540000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "792500000000000000", + "isEnabled": true, + "rate": "36689580000000" + }, + "out": { + "capacity": "1035000000000000000", + "isEnabled": true, + "rate": "47916360000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1472500000000000000", + "isEnabled": true, + "rate": "68170860000000" + }, + "out": { + "capacity": "1395000000000000000", + "isEnabled": true, + "rate": "64582920000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1672500000000000000", + "isEnabled": true, + "rate": "77430060000000" + }, + "out": { + "capacity": "857500000000000000", + "isEnabled": true, + "rate": "39698820000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1035000000000000000", + "isEnabled": true, + "rate": "47916360000000" + }, + "out": { + "capacity": "1187500000000000000", + "isEnabled": true, + "rate": "54976500000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "920000000000000000", + "isEnabled": true, + "rate": "42592320000000" + }, + "out": { + "capacity": "1522500000000000000", + "isEnabled": true, + "rate": "70485660000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1102500000000000000", + "isEnabled": true, + "rate": "51041340000000" + }, + "out": { + "capacity": "1515000000000000000", + "isEnabled": true, + "rate": "70138440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1072500000000000000", + "isEnabled": true, + "rate": "49652460000000" + }, + "out": { + "capacity": "917500000000000000", + "isEnabled": true, + "rate": "42476580000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1007500000000000000", + "isEnabled": true, + "rate": "46643220000000" + }, + "out": { + "capacity": "937500000000000000", + "isEnabled": true, + "rate": "43402500000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "910000000000000000", + "isEnabled": true, + "rate": "42129360000000" + }, + "out": { + "capacity": "1447500000000000000", + "isEnabled": true, + "rate": "67013460000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "berachain-mainnet": { + "custom": null, + "standard": null + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "790000000000000000", + "isEnabled": true, + "rate": "36573840000000" + }, + "out": { + "capacity": "880000000000000000", + "isEnabled": true, + "rate": "40740480000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "872500000000000000", + "isEnabled": true, + "rate": "40393260000000" + }, + "out": { + "capacity": "1317500000000000000", + "isEnabled": true, + "rate": "60994980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1005000000000000000", + "isEnabled": true, + "rate": "46527480000000" + }, + "out": { + "capacity": "1310000000000000000", + "isEnabled": true, + "rate": "60647760000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "865000000000000000", + "isEnabled": true, + "rate": "40046040000000" + }, + "out": { + "capacity": "1645000000000000000", + "isEnabled": true, + "rate": "76156920000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1087500000000000000", + "isEnabled": true, + "rate": "50346900000000" + }, + "out": { + "capacity": "1432500000000000000", + "isEnabled": true, + "rate": "66319020000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1220000000000000000", + "isEnabled": true, + "rate": "56481120000000" + }, + "out": { + "capacity": "1592500000000000000", + "isEnabled": true, + "rate": "73726380000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1337500000000000000", + "isEnabled": true, + "rate": "61920900000000" + }, + "out": { + "capacity": "1622500000000000000", + "isEnabled": true, + "rate": "75115260000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "770000000000000000", + "isEnabled": true, + "rate": "35647920000000" + }, + "out": { + "capacity": "750000000000000000", + "isEnabled": true, + "rate": "34722000000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1147500000000000000", + "isEnabled": true, + "rate": "53124660000000" + }, + "out": { + "capacity": "1625000000000000000", + "isEnabled": true, + "rate": "75231000000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "109250000", + "isEnabled": true, + "rate": "5057" + }, + "out": { + "capacity": "1305000000000000000", + "isEnabled": true, + "rate": "60416280000000" + } + }, + "standard": { + "in": { + "capacity": "250000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1307500000000000000", + "isEnabled": true, + "rate": "60532020000000" + }, + "out": { + "capacity": "792500000000000000", + "isEnabled": true, + "rate": "36689580000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": null, + "standard": null + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1365000000000000000", + "isEnabled": true, + "rate": "63194040000000" + }, + "out": { + "capacity": "1002500000000000000", + "isEnabled": true, + "rate": "46411740000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "795000000000000000", + "isEnabled": true, + "rate": "36805320000000" + }, + "out": { + "capacity": "1267500000000000000", + "isEnabled": true, + "rate": "58680180000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1487500000000000000", + "isEnabled": true, + "rate": "68865300000000" + }, + "out": { + "capacity": "1200000000000000000", + "isEnabled": true, + "rate": "55555200000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1150000000000000000", + "isEnabled": true, + "rate": "53240400000000" + }, + "out": { + "capacity": "1192500000000000000", + "isEnabled": true, + "rate": "55207980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": null, + "standard": null + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 3, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1677500000000000000", + "isEnabled": true, + "rate": "77661540000000" + }, + "out": { + "capacity": "1550000000000000000", + "isEnabled": true, + "rate": "71758800000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "752500000000000000", + "isEnabled": true, + "rate": "34837740000000" + }, + "out": { + "capacity": "850000000000000000", + "isEnabled": true, + "rate": "39351600000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "772500000000000000", + "isEnabled": true, + "rate": "35763660000000" + }, + "out": { + "capacity": "1375000000000000000", + "isEnabled": true, + "rate": "63657000000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1050000000000000000", + "isEnabled": true, + "rate": "48610800000000" + }, + "out": { + "capacity": "1452500000000000000", + "isEnabled": true, + "rate": "67244940000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1010000000000000000", + "isEnabled": true, + "rate": "46758960000000" + }, + "out": { + "capacity": "800000000000000000", + "isEnabled": true, + "rate": "37036800000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1725000000000000000", + "isEnabled": true, + "rate": "79860600000000" + }, + "out": { + "capacity": "1552500000000000000", + "isEnabled": true, + "rate": "71874540000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1297500000000000000", + "isEnabled": true, + "rate": "60069060000000" + }, + "out": { + "capacity": "1255000000000000000", + "isEnabled": true, + "rate": "58101480000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "982500000000000000", + "isEnabled": true, + "rate": "45485820000000" + }, + "out": { + "capacity": "1667500000000000000", + "isEnabled": true, + "rate": "77198580000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-ink-1": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "997500000000000000", + "isEnabled": true, + "rate": "46180260000000" + }, + "out": { + "capacity": "1352500000000000000", + "isEnabled": true, + "rate": "62615340000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1600000000000000000", + "isEnabled": true, + "rate": "74073600000000" + }, + "out": { + "capacity": "1220000000000000000", + "isEnabled": true, + "rate": "56481120000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1080000000000000000", + "isEnabled": true, + "rate": "49999680000000" + }, + "out": { + "capacity": "1417500000000000000", + "isEnabled": true, + "rate": "65624580000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1620000000000000000", + "isEnabled": true, + "rate": "74999520000000" + }, + "out": { + "capacity": "1215000000000000000", + "isEnabled": true, + "rate": "56249640000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1397500000000000000", + "isEnabled": true, + "rate": "64698660000000" + }, + "out": { + "capacity": "1175000000000000000", + "isEnabled": true, + "rate": "54397800000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1145000000000000000", + "isEnabled": true, + "rate": "53008920000000" + }, + "out": { + "capacity": "860000000000000000", + "isEnabled": true, + "rate": "39814560000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1350000000000000000", + "isEnabled": true, + "rate": "62499600000000" + }, + "out": { + "capacity": "1137500000000000000", + "isEnabled": true, + "rate": "52661700000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1527500000000000000", + "isEnabled": true, + "rate": "70717140000000" + }, + "out": { + "capacity": "775000000000000000", + "isEnabled": true, + "rate": "35879400000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1440000000000000000", + "isEnabled": true, + "rate": "66666240000000" + }, + "out": { + "capacity": "1505000000000000000", + "isEnabled": true, + "rate": "69675480000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1117500000000000000", + "isEnabled": true, + "rate": "51735780000000" + }, + "out": { + "capacity": "1362500000000000000", + "isEnabled": true, + "rate": "63078300000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1337500000000000000", + "isEnabled": true, + "rate": "61920900000000" + }, + "out": { + "capacity": "1127500000000000000", + "isEnabled": true, + "rate": "52198740000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-linea-1": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1607500000000000000", + "isEnabled": true, + "rate": "74420820000000" + }, + "out": { + "capacity": "1747500000000000000", + "isEnabled": true, + "rate": "80902260000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1685000000000000000", + "isEnabled": true, + "rate": "78008760000000" + }, + "out": { + "capacity": "885000000000000000", + "isEnabled": true, + "rate": "40971960000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1625000000000000000", + "isEnabled": true, + "rate": "75231000000000" + }, + "out": { + "capacity": "765000000000000000", + "isEnabled": true, + "rate": "35416440000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "837500000000000000", + "isEnabled": true, + "rate": "38772900000000" + }, + "out": { + "capacity": "1442500000000000000", + "isEnabled": true, + "rate": "66781980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1335000000000000000", + "isEnabled": true, + "rate": "61805160000000" + }, + "out": { + "capacity": "767500000000000000", + "isEnabled": true, + "rate": "35532180000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1262500000000000000", + "isEnabled": true, + "rate": "58448700000000" + }, + "out": { + "capacity": "915000000000000000", + "isEnabled": true, + "rate": "42360840000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1127500000000000000", + "isEnabled": true, + "rate": "52198740000000" + }, + "out": { + "capacity": "1712500000000000000", + "isEnabled": true, + "rate": "79281900000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1747500000000000000", + "isEnabled": true, + "rate": "80902260000000" + }, + "out": { + "capacity": "1512500000000000000", + "isEnabled": true, + "rate": "70022700000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-taiko-1": { + "minBlockConfirmation": 1, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1387500000000000000", + "isEnabled": true, + "rate": "64235700000000" + }, + "out": { + "capacity": "1557500000000000000", + "isEnabled": true, + "rate": "72106020000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "ethereum-mainnet-zksync-1": { + "minBlockConfirmation": 3, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1140000000000000000", + "isEnabled": true, + "rate": "52777440000000" + }, + "out": { + "capacity": "1472500000000000000", + "isEnabled": true, + "rate": "68170860000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "752500000000000000", + "isEnabled": true, + "rate": "34837740000000" + }, + "out": { + "capacity": "775000000000000000", + "isEnabled": true, + "rate": "35879400000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "63600000000000000000", + "isEnabled": true, + "rate": "736064000000000" + }, + "out": { + "capacity": "1580000000000000000", + "isEnabled": true, + "rate": "73147680000000" + } + }, + "standard": { + "in": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1736000000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1327500000000000000", + "isEnabled": true, + "rate": "61457940000000" + }, + "out": { + "capacity": "1260000000000000000", + "isEnabled": true, + "rate": "58332960000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "hyperliquid-mainnet": { + "minBlockConfirmation": 4, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1080000000000000000", + "isEnabled": true, + "rate": "49999680000000" + }, + "out": { + "capacity": "1510000000000000000", + "isEnabled": true, + "rate": "69906960000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1032500000000000000", + "isEnabled": true, + "rate": "47800620000000" + }, + "out": { + "capacity": "865000000000000000", + "isEnabled": true, + "rate": "40046040000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "1690000000000000000", + "isEnabled": true, + "rate": "78240240000000" + }, + "out": { + "capacity": "1535000000000000000", + "isEnabled": true, + "rate": "71064360000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "berachain-mainnet": { + "custom": { + "in": { + "capacity": "1147500000000000000", + "isEnabled": true, + "rate": "53124660000000" + }, + "out": { + "capacity": "1137500000000000000", + "isEnabled": true, + "rate": "52661700000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1620000000000000000", + "isEnabled": true, + "rate": "74999520000000" + }, + "out": { + "capacity": "1117500000000000000", + "isEnabled": true, + "rate": "51735780000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1107500000000000000", + "isEnabled": true, + "rate": "51272820000000" + }, + "out": { + "capacity": "1365000000000000000", + "isEnabled": true, + "rate": "63194040000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1390000000000000000", + "isEnabled": true, + "rate": "64351440000000" + }, + "out": { + "capacity": "1522500000000000000", + "isEnabled": true, + "rate": "70485660000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1672500000000000000", + "isEnabled": true, + "rate": "77430060000000" + }, + "out": { + "capacity": "1412500000000000000", + "isEnabled": true, + "rate": "65393100000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": null, + "standard": null + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1617500000000000000", + "isEnabled": true, + "rate": "74883780000000" + }, + "out": { + "capacity": "812500000000000000", + "isEnabled": true, + "rate": "37615500000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-taiko-1": { + "custom": { + "in": { + "capacity": "1472500000000000000", + "isEnabled": true, + "rate": "68170860000000" + }, + "out": { + "capacity": "1290000000000000000", + "isEnabled": true, + "rate": "59721840000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1465000000000000000", + "isEnabled": true, + "rate": "67823640000000" + }, + "out": { + "capacity": "92700000000000000000", + "isEnabled": true, + "rate": "1072848000000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "150000000000000000000", + "isEnabled": true, + "rate": "1736000000000000" + } + } + }, + "hyperliquid-mainnet": { + "custom": { + "in": { + "capacity": "1050000000000000000", + "isEnabled": true, + "rate": "48610800000000" + }, + "out": { + "capacity": "1465000000000000000", + "isEnabled": true, + "rate": "67823640000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1332500000000000000", + "isEnabled": true, + "rate": "61689420000000" + }, + "out": { + "capacity": "1422500000000000000", + "isEnabled": true, + "rate": "65856060000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "monad-mainnet": { + "custom": null, + "standard": null + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1675000000000000000", + "isEnabled": true, + "rate": "77545800000000" + }, + "out": { + "capacity": "1730000000000000000", + "isEnabled": true, + "rate": "80092080000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "138750000", + "isEnabled": true, + "rate": "6423" + }, + "out": { + "capacity": "980000000000000000", + "isEnabled": true, + "rate": "45370080000000" + } + }, + "standard": { + "in": { + "capacity": "250000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "922500000000000000", + "isEnabled": true, + "rate": "42708060000000" + }, + "out": { + "capacity": "26220000000000000000", + "isEnabled": true, + "rate": "303470280000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "60000000000000000000", + "isEnabled": true, + "rate": "694440000000000" + } + } + }, + "sonic-mainnet": { + "custom": null, + "standard": null + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "957500000000000000", + "isEnabled": true, + "rate": "44328420000000" + }, + "out": { + "capacity": "1535000000000000000", + "isEnabled": true, + "rate": "71064360000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bitcoin-mainnet-bob-1": { + "custom": null, + "standard": null + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1417500000000000000", + "isEnabled": true, + "rate": "65624580000000" + }, + "out": { + "capacity": "862500000000000000", + "isEnabled": true, + "rate": "39930300000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1370000000000000000", + "isEnabled": true, + "rate": "63425520000000" + }, + "out": { + "capacity": "1042500000000000000", + "isEnabled": true, + "rate": "48263580000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "862500000000000000", + "isEnabled": true, + "rate": "39930300000000" + }, + "out": { + "capacity": "1192500000000000000", + "isEnabled": true, + "rate": "55207980000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1162500000000000000", + "isEnabled": true, + "rate": "53819100000000" + }, + "out": { + "capacity": "1170000000000000000", + "isEnabled": true, + "rate": "54166320000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-linea-1": { + "custom": { + "in": { + "capacity": "1560000000000000000", + "isEnabled": true, + "rate": "72221760000000" + }, + "out": { + "capacity": "1220000000000000000", + "isEnabled": true, + "rate": "56481120000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-zksync-1": { + "custom": { + "in": { + "capacity": "1295000000000000000", + "isEnabled": true, + "rate": "59953320000000" + }, + "out": { + "capacity": "1357500000000000000", + "isEnabled": true, + "rate": "62846820000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1120000000000000000", + "isEnabled": true, + "rate": "51851520000000" + }, + "out": { + "capacity": "1160000000000000000", + "isEnabled": true, + "rate": "53703360000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "sei-mainnet": { + "custom": { + "in": { + "capacity": "1127500000000000000", + "isEnabled": true, + "rate": "52198740000000" + }, + "out": { + "capacity": "772500000000000000", + "isEnabled": true, + "rate": "35763660000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "soneium-mainnet": { + "custom": { + "in": { + "capacity": "1217500000000000000", + "isEnabled": true, + "rate": "56365380000000" + }, + "out": { + "capacity": "807500000000000000", + "isEnabled": true, + "rate": "37384020000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "monad-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "10110000000000000000", + "isEnabled": true, + "rate": "117013140000000" + }, + "out": { + "capacity": "1610000000000000000", + "isEnabled": true, + "rate": "18634140000000" + } + }, + "standard": { + "in": { + "capacity": "30000000000000000000", + "isEnabled": true, + "rate": "347220000000000" + }, + "out": { + "capacity": "5000000000000000000", + "isEnabled": true, + "rate": "57870000000000" + } + } + } + } + }, + "sei-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "1555000000000000000", + "isEnabled": true, + "rate": "71990280000000" + }, + "out": { + "capacity": "1660000000000000000", + "isEnabled": true, + "rate": "76851360000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "1312500000000000000", + "isEnabled": true, + "rate": "60763500000000" + }, + "out": { + "capacity": "1197500000000000000", + "isEnabled": true, + "rate": "55439460000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "1567500000000000000", + "isEnabled": true, + "rate": "72568980000000" + }, + "out": { + "capacity": "1120000000000000000", + "isEnabled": true, + "rate": "51851520000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1722500000000000000", + "isEnabled": true, + "rate": "79744860000000" + }, + "out": { + "capacity": "985000000000000000", + "isEnabled": true, + "rate": "45601560000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1597500000000000000", + "isEnabled": true, + "rate": "73957860000000" + }, + "out": { + "capacity": "1420000000000000000", + "isEnabled": true, + "rate": "65740320000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "153250000", + "isEnabled": true, + "rate": "7094" + }, + "out": { + "capacity": "155750000", + "isEnabled": true, + "rate": "7210" + } + }, + "standard": { + "in": { + "capacity": "250000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "250000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "152500000", + "isEnabled": true, + "rate": "7060" + }, + "out": { + "capacity": "169000000", + "isEnabled": true, + "rate": "7824" + } + }, + "standard": { + "in": { + "capacity": "250000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "250000000", + "isEnabled": true, + "rate": "11574" + } + } + } + } + }, + "soneium-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "bitcoin-mainnet-bob-1": { + "custom": { + "in": { + "capacity": "890000000000000000", + "isEnabled": true, + "rate": "41203440000000" + }, + "out": { + "capacity": "1617500000000000000", + "isEnabled": true, + "rate": "74883780000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "942500000000000000", + "isEnabled": true, + "rate": "43633980000000" + }, + "out": { + "capacity": "1677500000000000000", + "isEnabled": true, + "rate": "77661540000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "22980000000000000000", + "isEnabled": true, + "rate": "265970520000000" + }, + "out": { + "capacity": "1057500000000000000", + "isEnabled": true, + "rate": "48958020000000" + } + }, + "standard": { + "in": { + "capacity": "60000000000000000000", + "isEnabled": true, + "rate": "694440000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1702500000000000000", + "isEnabled": true, + "rate": "78818940000000" + }, + "out": { + "capacity": "1387500000000000000", + "isEnabled": true, + "rate": "64235700000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1150000000000000000", + "isEnabled": true, + "rate": "53240400000000" + }, + "out": { + "capacity": "1580000000000000000", + "isEnabled": true, + "rate": "73147680000000" + } + }, + "standard": { + "in": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + }, + "out": { + "capacity": "2500000000000000000", + "isEnabled": true, + "rate": "115740000000000" + } + } + } + } + } + }, + "XSWAP": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "12120000000000000000000000", + "isEnabled": true, + "rate": "280578000000000000000" + }, + "out": { + "capacity": "8600000000000000000000000", + "isEnabled": true, + "rate": "199090000000000000000" + } + }, + "standard": { + "in": { + "capacity": "20000000000000000000000000", + "isEnabled": true, + "rate": "463000000000000000000" + }, + "out": { + "capacity": "20000000000000000000000000", + "isEnabled": true, + "rate": "463000000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "13420000000000000000000000", + "isEnabled": true, + "rate": "310673000000000000000" + }, + "out": { + "capacity": "9240000000000000000000000", + "isEnabled": true, + "rate": "213906000000000000000" + } + }, + "standard": { + "in": { + "capacity": "20000000000000000000000000", + "isEnabled": true, + "rate": "463000000000000000000" + }, + "out": { + "capacity": "20000000000000000000000000", + "isEnabled": true, + "rate": "463000000000000000000" + } + } + } + } + } + }, + "XTFBRICK1": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "memento-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "memento-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "memento-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "XTFCLOBOND": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 5, + "remote": { + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "memento-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "matic-mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "memento-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "memento-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "matic-mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "YBTC.B": { + "avalanche-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bsc-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plume-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "bsc-mainnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-mainnet": { + "custom": null, + "standard": null + }, + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-mainnet-ink-1": { + "minBlockConfirmation": 5, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 9, + "remote": { + "avalanche-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-mainnet-ink-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "plasma-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "plume-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "bitcoin-mainnet-bitlayer-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "YGG": { + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ronin-mainnet": { + "custom": { + "in": { + "capacity": "1208000000000000000000000", + "isEnabled": true, + "rate": "13981452400000000000" + }, + "out": { + "capacity": "1116000000000000000000000", + "isEnabled": true, + "rate": "12916646000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148100000000000000" + }, + "out": { + "capacity": "1800000000000000000000000", + "isEnabled": true, + "rate": "20833300000000000000" + } + } + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 6, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1194000000000000000000000", + "isEnabled": true, + "rate": "13819415700000000000" + }, + "out": { + "capacity": "833400000000000000000000", + "isEnabled": true, + "rate": "9645817900000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23148100000000000000" + }, + "out": { + "capacity": "1800000000000000000000000", + "isEnabled": true, + "rate": "20833300000000000000" + } + } + } + } + } + }, + "YNE": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "solana-mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "zBTC": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "484000000", + "isEnabled": true, + "rate": "5601" + }, + "out": { + "capacity": "316000000", + "isEnabled": true, + "rate": "3657" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "480000000", + "isEnabled": true, + "rate": "5555" + }, + "out": { + "capacity": "353000000", + "isEnabled": true, + "rate": "4085" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "328000000", + "isEnabled": true, + "rate": "3796" + }, + "out": { + "capacity": "639000000", + "isEnabled": true, + "rate": "7395" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "479000000", + "isEnabled": true, + "rate": "5543" + }, + "out": { + "capacity": "691000000", + "isEnabled": true, + "rate": "7997" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "429000000", + "isEnabled": true, + "rate": "4965" + }, + "out": { + "capacity": "419000000", + "isEnabled": true, + "rate": "4849" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "676000000", + "isEnabled": true, + "rate": "7824" + }, + "out": { + "capacity": "495000000", + "isEnabled": true, + "rate": "5729" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + } + } + }, + "solana-mainnet": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "520000000", + "isEnabled": true, + "rate": "6018" + }, + "out": { + "capacity": "409000000", + "isEnabled": true, + "rate": "4733" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "495000000", + "isEnabled": true, + "rate": "5729" + }, + "out": { + "capacity": "616000000", + "isEnabled": true, + "rate": "7129" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "sonic-mainnet": { + "custom": { + "in": { + "capacity": "325000000", + "isEnabled": true, + "rate": "3761" + }, + "out": { + "capacity": "620000000", + "isEnabled": true, + "rate": "7175" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + } + } + }, + "sonic-mainnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-base-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "656000000", + "isEnabled": true, + "rate": "7592" + }, + "out": { + "capacity": "621000000", + "isEnabled": true, + "rate": "7187" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + }, + "solana-mainnet": { + "custom": { + "in": { + "capacity": "449000000", + "isEnabled": true, + "rate": "5196" + }, + "out": { + "capacity": "574000000", + "isEnabled": true, + "rate": "6643" + } + }, + "standard": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "11574" + } + } + } + } + } + }, + "ZENT": { + "mainnet": { + "minBlockConfirmation": null, + "remote": { + "ronin-mainnet": { + "custom": null, + "standard": null + } + } + }, + "ronin-mainnet": { + "minBlockConfirmation": 2, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "ZeUSD": { + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 10, + "remote": { + "mainnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "ZUN": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1138000000000000000000000", + "isEnabled": true, + "rate": "13166660000000000000" + }, + "out": { + "capacity": "1018000000000000000000000", + "isEnabled": true, + "rate": "11778260000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "686000000000000000000000", + "isEnabled": true, + "rate": "7937020000000000000" + }, + "out": { + "capacity": "792000000000000000000000", + "isEnabled": true, + "rate": "9163440000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "648000000000000000000000", + "isEnabled": true, + "rate": "7497360000000000000" + }, + "out": { + "capacity": "1292000000000000000000000", + "isEnabled": true, + "rate": "14948440000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "988000000000000000000000", + "isEnabled": true, + "rate": "11431160000000000000" + }, + "out": { + "capacity": "1100000000000000000000000", + "isEnabled": true, + "rate": "12727000000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": null, + "standard": null + }, + "mainnet": { + "custom": { + "in": { + "capacity": "1106000000000000000000000", + "isEnabled": true, + "rate": "12796420000000000000" + }, + "out": { + "capacity": "934000000000000000000000", + "isEnabled": true, + "rate": "10806380000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "1384000000000000000000000", + "isEnabled": true, + "rate": "16012880000000000000" + }, + "out": { + "capacity": "1010000000000000000000000", + "isEnabled": true, + "rate": "11685700000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1072000000000000000000000", + "isEnabled": true, + "rate": "12403040000000000000" + }, + "out": { + "capacity": "698000000000000000000000", + "isEnabled": true, + "rate": "8075860000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "996000000000000000000000", + "isEnabled": true, + "rate": "11523720000000000000" + }, + "out": { + "capacity": "626000000000000000000000", + "isEnabled": true, + "rate": "7242820000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "966000000000000000000000", + "isEnabled": true, + "rate": "11176620000000000000" + }, + "out": { + "capacity": "1170000000000000000000000", + "isEnabled": true, + "rate": "13536900000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "1078000000000000000000000", + "isEnabled": true, + "rate": "12472460000000000000" + }, + "out": { + "capacity": "970000000000000000000000", + "isEnabled": true, + "rate": "11222900000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "682000000000000000000000", + "isEnabled": true, + "rate": "7890740000000000000" + }, + "out": { + "capacity": "618000000000000000000000", + "isEnabled": true, + "rate": "7150260000000000000" + } + }, + "standard": { + "in": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + }, + "out": { + "capacity": "2000000000000000000000000", + "isEnabled": true, + "rate": "23140000000000000000" + } + } + } + } + } + }, + "zunETH": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "39096000000000000000", + "isEnabled": true, + "rate": "904638000000000" + }, + "out": { + "capacity": "25128000000000000000", + "isEnabled": true, + "rate": "581434000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "37080000000000000000", + "isEnabled": true, + "rate": "857990000000000" + }, + "out": { + "capacity": "22032000000000000000", + "isEnabled": true, + "rate": "509796000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "39456000000000000000", + "isEnabled": true, + "rate": "912968000000000" + }, + "out": { + "capacity": "48456000000000000000", + "isEnabled": true, + "rate": "1121218000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "49248000000000000000", + "isEnabled": true, + "rate": "1139544000000000" + }, + "out": { + "capacity": "45360000000000000000", + "isEnabled": true, + "rate": "1049580000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "25344000000000000000", + "isEnabled": true, + "rate": "586432000000000" + }, + "out": { + "capacity": "45504000000000000000", + "isEnabled": true, + "rate": "1052912000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "32256000000000000000", + "isEnabled": true, + "rate": "746368000000000" + }, + "out": { + "capacity": "36072000000000000000", + "isEnabled": true, + "rate": "834666000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "33696000000000000000", + "isEnabled": true, + "rate": "779688000000000" + }, + "out": { + "capacity": "41184000000000000000", + "isEnabled": true, + "rate": "952952000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "40752000000000000000", + "isEnabled": true, + "rate": "942956000000000" + }, + "out": { + "capacity": "39888000000000000000", + "isEnabled": true, + "rate": "922964000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "23472000000000000000", + "isEnabled": true, + "rate": "543116000000000" + }, + "out": { + "capacity": "38160000000000000000", + "isEnabled": true, + "rate": "882980000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "37008000000000000000", + "isEnabled": true, + "rate": "856324000000000" + }, + "out": { + "capacity": "36576000000000000000", + "isEnabled": true, + "rate": "846328000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "45072000000000000000", + "isEnabled": true, + "rate": "1042916000000000" + }, + "out": { + "capacity": "46152000000000000000", + "isEnabled": true, + "rate": "1067906000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "35712000000000000000", + "isEnabled": true, + "rate": "826336000000000" + }, + "out": { + "capacity": "33480000000000000000", + "isEnabled": true, + "rate": "774690000000000" + } + }, + "standard": { + "in": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + }, + "out": { + "capacity": "72000000000000000000", + "isEnabled": true, + "rate": "1666000000000000" + } + } + } + } + } + }, + "zunUSD": { + "ethereum-mainnet-arbitrum-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "125000000000000000000000", + "isEnabled": true, + "rate": "2893500000000000000" + }, + "out": { + "capacity": "129250000000000000000000", + "isEnabled": true, + "rate": "2991879000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "155750000000000000000000", + "isEnabled": true, + "rate": "3605301000000000000" + }, + "out": { + "capacity": "91250000000000000000000", + "isEnabled": true, + "rate": "2112255000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "113750000000000000000000", + "isEnabled": true, + "rate": "2633085000000000000" + }, + "out": { + "capacity": "147250000000000000000000", + "isEnabled": true, + "rate": "3408543000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + } + } + }, + "ethereum-mainnet-base-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "77500000000000000000000", + "isEnabled": true, + "rate": "1793970000000000000" + }, + "out": { + "capacity": "89000000000000000000000", + "isEnabled": true, + "rate": "2060172000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "171250000000000000000000", + "isEnabled": true, + "rate": "3964095000000000000" + }, + "out": { + "capacity": "117250000000000000000000", + "isEnabled": true, + "rate": "2714103000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "109250000000000000000000", + "isEnabled": true, + "rate": "2528919000000000000" + }, + "out": { + "capacity": "138000000000000000000000", + "isEnabled": true, + "rate": "3194424000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + } + } + }, + "ethereum-mainnet-optimism-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "123750000000000000000000", + "isEnabled": true, + "rate": "2864565000000000000" + }, + "out": { + "capacity": "116250000000000000000000", + "isEnabled": true, + "rate": "2690955000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "158000000000000000000000", + "isEnabled": true, + "rate": "3657384000000000000" + }, + "out": { + "capacity": "97250000000000000000000", + "isEnabled": true, + "rate": "2251143000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "mainnet": { + "custom": { + "in": { + "capacity": "86000000000000000000000", + "isEnabled": true, + "rate": "1990728000000000000" + }, + "out": { + "capacity": "126000000000000000000000", + "isEnabled": true, + "rate": "2916648000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + } + } + }, + "mainnet": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-mainnet-arbitrum-1": { + "custom": { + "in": { + "capacity": "92500000000000000000000", + "isEnabled": true, + "rate": "2141190000000000000" + }, + "out": { + "capacity": "131750000000000000000000", + "isEnabled": true, + "rate": "3049749000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "ethereum-mainnet-base-1": { + "custom": { + "in": { + "capacity": "172250000000000000000000", + "isEnabled": true, + "rate": "3987243000000000000" + }, + "out": { + "capacity": "86500000000000000000000", + "isEnabled": true, + "rate": "2002302000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + }, + "ethereum-mainnet-optimism-1": { + "custom": { + "in": { + "capacity": "101250000000000000000000", + "isEnabled": true, + "rate": "2343735000000000000" + }, + "out": { + "capacity": "124250000000000000000000", + "isEnabled": true, + "rate": "2876139000000000000" + } + }, + "standard": { + "in": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + }, + "out": { + "capacity": "250000000000000000000000", + "isEnabled": true, + "rate": "5787000000000000000" + } + } + } + } + } + } +} diff --git a/src/__mocks__/rate-limits-testnet.json b/src/__mocks__/rate-limits-testnet.json new file mode 100644 index 00000000000..0dfaf068b79 --- /dev/null +++ b/src/__mocks__/rate-limits-testnet.json @@ -0,0 +1,7465 @@ +{ + "CCIP-BnM": { + "abstract-testnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "45500000000000000000000", + "isEnabled": true, + "rate": "75985000000000000000" + }, + "out": { + "capacity": "60300000000000000000000", + "isEnabled": true, + "rate": "100701000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "apechain-testnet-curtis": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "53700000000000000000000", + "isEnabled": true, + "rate": "89679000000000000000" + }, + "out": { + "capacity": "45300000000000000000000", + "isEnabled": true, + "rate": "75651000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "aptos-testnet": { + "minBlockConfirmation": 6, + "remote": { + "bsc-testnet": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "sonic-testnet-blaze": { + "custom": { + "in": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + }, + "out": { + "capacity": "100000000000", + "isEnabled": true, + "rate": "100000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "avalanche-fuji-testnet": { + "minBlockConfirmation": 10, + "remote": { + "bsc-testnet": { + "custom": { + "in": { + "capacity": "44900000000000000000000", + "isEnabled": true, + "rate": "74983000000000000000" + }, + "out": { + "capacity": "48500000000000000000000", + "isEnabled": true, + "rate": "80995000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "45500000000000000000000", + "isEnabled": true, + "rate": "75985000000000000000" + }, + "out": { + "capacity": "47900000000000000000000", + "isEnabled": true, + "rate": "79993000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "33700000000000000000000", + "isEnabled": true, + "rate": "56279000000000000000" + }, + "out": { + "capacity": "56300000000000000000000", + "isEnabled": true, + "rate": "94021000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "66400000000000000000000", + "isEnabled": true, + "rate": "110888000000000000000" + }, + "out": { + "capacity": "42900000000000000000000", + "isEnabled": true, + "rate": "71643000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "60700000000000000000000", + "isEnabled": true, + "rate": "101369000000000000000" + }, + "out": { + "capacity": "44300000000000000000000", + "isEnabled": true, + "rate": "73981000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "41800000000000000000000", + "isEnabled": true, + "rate": "69806000000000000000" + }, + "out": { + "capacity": "44100000000000000000000", + "isEnabled": true, + "rate": "73647000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "shibarium-testnet-puppynet": { + "custom": { + "in": { + "capacity": "42300000000000000000000", + "isEnabled": true, + "rate": "70641000000000000000" + }, + "out": { + "capacity": "58500000000000000000000", + "isEnabled": true, + "rate": "97695000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "51800000000000000000000", + "isEnabled": true, + "rate": "86506000000000000000" + }, + "out": { + "capacity": "50400000000000000000000", + "isEnabled": true, + "rate": "84168000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "57900000000000000000000", + "isEnabled": true, + "rate": "96693000000000000000" + }, + "out": { + "capacity": "46000000000000000000000", + "isEnabled": true, + "rate": "76820000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "bitcoin-testnet-bsquared-1": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "68000000000000000000000", + "isEnabled": true, + "rate": "113560000000000000000" + }, + "out": { + "capacity": "58300000000000000000000", + "isEnabled": true, + "rate": "97361000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "bitcoin-testnet-rootstock": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "35000000000000000000000", + "isEnabled": true, + "rate": "58450000000000000000" + }, + "out": { + "capacity": "47800000000000000000000", + "isEnabled": true, + "rate": "79826000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "bitcoin-testnet-sepolia-bob-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "39000000000000000000000", + "isEnabled": true, + "rate": "65130000000000000000" + }, + "out": { + "capacity": "40400000000000000000000", + "isEnabled": true, + "rate": "67468000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "bsc-testnet": { + "minBlockConfirmation": 7, + "remote": { + "aptos-testnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "52400000000000000000000", + "isEnabled": true, + "rate": "87508000000000000000" + }, + "out": { + "capacity": "59100000000000000000000", + "isEnabled": true, + "rate": "98697000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "42400000000000000000000", + "isEnabled": true, + "rate": "70808000000000000000" + }, + "out": { + "capacity": "38400000000000000000000", + "isEnabled": true, + "rate": "64128000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "32900000000000000000000", + "isEnabled": true, + "rate": "54943000000000000000" + }, + "out": { + "capacity": "65800000000000000000000", + "isEnabled": true, + "rate": "109886000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "65900000000000000000000", + "isEnabled": true, + "rate": "110053000000000000000" + }, + "out": { + "capacity": "65600000000000000000000", + "isEnabled": true, + "rate": "109552000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "34100000000000000000000", + "isEnabled": true, + "rate": "56947000000000000000" + }, + "out": { + "capacity": "64300000000000000000000", + "isEnabled": true, + "rate": "107381000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "62600000000000000000000", + "isEnabled": true, + "rate": "104542000000000000000" + }, + "out": { + "capacity": "37500000000000000000000", + "isEnabled": true, + "rate": "62625000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "57400000000000000000000", + "isEnabled": true, + "rate": "95858000000000000000" + }, + "out": { + "capacity": "33900000000000000000000", + "isEnabled": true, + "rate": "56613000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "celo-testnet-alfajores": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "36700000000000000000000", + "isEnabled": true, + "rate": "61289000000000000000" + }, + "out": { + "capacity": "44400000000000000000000", + "isEnabled": true, + "rate": "74148000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "cronos-testnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "47900000000000000000000", + "isEnabled": true, + "rate": "79993000000000000000" + }, + "out": { + "capacity": "35600000000000000000000", + "isEnabled": true, + "rate": "59452000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-holesky": { + "minBlockConfirmation": 1, + "remote": { + "polygon-testnet-tatara": { + "custom": { + "in": { + "capacity": "58500000000000000000000", + "isEnabled": true, + "rate": "97695000000000000000" + }, + "out": { + "capacity": "68700000000000000000000", + "isEnabled": true, + "rate": "114729000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-holesky-fraxtal-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "49000000000000000000000", + "isEnabled": true, + "rate": "81830000000000000000" + }, + "out": { + "capacity": "53400000000000000000000", + "isEnabled": true, + "rate": "89178000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-holesky-taiko-1": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "51400000000000000000000", + "isEnabled": true, + "rate": "85838000000000000000" + }, + "out": { + "capacity": "42300000000000000000000", + "isEnabled": true, + "rate": "70641000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-hoodi-morph": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia": { + "minBlockConfirmation": 3, + "remote": { + "abstract-testnet": { + "custom": { + "in": { + "capacity": "66900000000000000000000", + "isEnabled": true, + "rate": "111723000000000000000" + }, + "out": { + "capacity": "35800000000000000000000", + "isEnabled": true, + "rate": "59786000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "apechain-testnet-curtis": { + "custom": { + "in": { + "capacity": "65500000000000000000000", + "isEnabled": true, + "rate": "109385000000000000000" + }, + "out": { + "capacity": "55500000000000000000000", + "isEnabled": true, + "rate": "92685000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "aptos-testnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "avalanche-fuji-testnet": { + "custom": null, + "standard": null + }, + "bitcoin-testnet-bsquared-1": { + "custom": { + "in": { + "capacity": "68800000000000000000000", + "isEnabled": true, + "rate": "114896000000000000000" + }, + "out": { + "capacity": "65900000000000000000000", + "isEnabled": true, + "rate": "110053000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bitcoin-testnet-rootstock": { + "custom": { + "in": { + "capacity": "60300000000000000000000", + "isEnabled": true, + "rate": "100701000000000000000" + }, + "out": { + "capacity": "64300000000000000000000", + "isEnabled": true, + "rate": "107381000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bitcoin-testnet-sepolia-bob-1": { + "custom": { + "in": { + "capacity": "54200000000000000000000", + "isEnabled": true, + "rate": "90514000000000000000" + }, + "out": { + "capacity": "57200000000000000000000", + "isEnabled": true, + "rate": "95524000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "48300000000000000000000", + "isEnabled": true, + "rate": "80661000000000000000" + }, + "out": { + "capacity": "42500000000000000000000", + "isEnabled": true, + "rate": "70975000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "celo-testnet-alfajores": { + "custom": { + "in": { + "capacity": "58700000000000000000000", + "isEnabled": true, + "rate": "98029000000000000000" + }, + "out": { + "capacity": "62800000000000000000000", + "isEnabled": true, + "rate": "104876000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "cronos-testnet": { + "custom": { + "in": { + "capacity": "44500000000000000000000", + "isEnabled": true, + "rate": "74315000000000000000" + }, + "out": { + "capacity": "67400000000000000000000", + "isEnabled": true, + "rate": "112558000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-holesky-fraxtal-1": { + "custom": { + "in": { + "capacity": "33000000000000000000000", + "isEnabled": true, + "rate": "55110000000000000000" + }, + "out": { + "capacity": "41800000000000000000000", + "isEnabled": true, + "rate": "69806000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-holesky-taiko-1": { + "custom": { + "in": { + "capacity": "45200000000000000000000", + "isEnabled": true, + "rate": "75484000000000000000" + }, + "out": { + "capacity": "57800000000000000000000", + "isEnabled": true, + "rate": "96526000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-hoodi-morph": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-andromeda-1": { + "custom": { + "in": { + "capacity": "40100000000000000000000", + "isEnabled": true, + "rate": "66967000000000000000" + }, + "out": { + "capacity": "65600000000000000000000", + "isEnabled": true, + "rate": "109552000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": null, + "standard": null + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "54700000000000000000000", + "isEnabled": true, + "rate": "91349000000000000000" + }, + "out": { + "capacity": "33900000000000000000000", + "isEnabled": true, + "rate": "56613000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-blast-1": { + "custom": { + "in": { + "capacity": "65000000000000000000000", + "isEnabled": true, + "rate": "108550000000000000000" + }, + "out": { + "capacity": "65400000000000000000000", + "isEnabled": true, + "rate": "109218000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-hashkey-1": { + "custom": { + "in": { + "capacity": "57700000000000000000000", + "isEnabled": true, + "rate": "96359000000000000000" + }, + "out": { + "capacity": "52000000000000000000000", + "isEnabled": true, + "rate": "86840000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-lisk-1": { + "custom": null, + "standard": null + }, + "ethereum-testnet-sepolia-mantle-1": { + "custom": { + "in": { + "capacity": "65200000000000000000000", + "isEnabled": true, + "rate": "108884000000000000000" + }, + "out": { + "capacity": "58600000000000000000000", + "isEnabled": true, + "rate": "97862000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-mode-1": { + "custom": { + "in": { + "capacity": "44100000000000000000000", + "isEnabled": true, + "rate": "73647000000000000000" + }, + "out": { + "capacity": "62900000000000000000000", + "isEnabled": true, + "rate": "105043000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "38200000000000000000000", + "isEnabled": true, + "rate": "63794000000000000000" + }, + "out": { + "capacity": "57100000000000000000000", + "isEnabled": true, + "rate": "95357000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-unichain-1": { + "custom": { + "in": { + "capacity": "37700000000000000000000", + "isEnabled": true, + "rate": "62959000000000000000" + }, + "out": { + "capacity": "31400000000000000000000", + "isEnabled": true, + "rate": "52438000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-worldchain-1": { + "custom": { + "in": { + "capacity": "63400000000000000000000", + "isEnabled": true, + "rate": "105878000000000000000" + }, + "out": { + "capacity": "35300000000000000000000", + "isEnabled": true, + "rate": "58951000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-zksync-1": { + "custom": { + "in": { + "capacity": "57400000000000000000000", + "isEnabled": true, + "rate": "95858000000000000000" + }, + "out": { + "capacity": "69300000000000000000000", + "isEnabled": true, + "rate": "115731000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "hedera-testnet": { + "custom": { + "in": { + "capacity": "57700000000000000000000", + "isEnabled": true, + "rate": "96359000000000000000" + }, + "out": { + "capacity": "60700000000000000000000", + "isEnabled": true, + "rate": "101369000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ink-testnet-sepolia": { + "custom": null, + "standard": null + }, + "jovay-testnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "memento-testnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "metal-testnet": { + "custom": { + "in": { + "capacity": "69400000000000000000000", + "isEnabled": true, + "rate": "115898000000000000000" + }, + "out": { + "capacity": "30100000000000000000000", + "isEnabled": true, + "rate": "50267000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "mint-testnet": { + "custom": { + "in": { + "capacity": "36700000000000000000000", + "isEnabled": true, + "rate": "61289000000000000000" + }, + "out": { + "capacity": "40700000000000000000000", + "isEnabled": true, + "rate": "67969000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "plume-testnet-sepolia": { + "custom": { + "in": { + "capacity": "58900000000000000000000", + "isEnabled": true, + "rate": "98363000000000000000" + }, + "out": { + "capacity": "49300000000000000000000", + "isEnabled": true, + "rate": "82331000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polkadot-testnet-astar-shibuya": { + "custom": { + "in": { + "capacity": "61300000000000000000000", + "isEnabled": true, + "rate": "102371000000000000000" + }, + "out": { + "capacity": "35700000000000000000000", + "isEnabled": true, + "rate": "59619000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "54500000000000000000000", + "isEnabled": true, + "rate": "91015000000000000000" + }, + "out": { + "capacity": "37700000000000000000000", + "isEnabled": true, + "rate": "62959000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ronin-testnet-saigon": { + "custom": { + "in": { + "capacity": "33300000000000000000000", + "isEnabled": true, + "rate": "55611000000000000000" + }, + "out": { + "capacity": "47800000000000000000000", + "isEnabled": true, + "rate": "79826000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "sei-testnet-atlantic": { + "custom": { + "in": { + "capacity": "30600000000000000000000", + "isEnabled": true, + "rate": "51102000000000000000" + }, + "out": { + "capacity": "57500000000000000000000", + "isEnabled": true, + "rate": "96025000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "shibarium-testnet-puppynet": { + "custom": { + "in": { + "capacity": "42000000000000000000000", + "isEnabled": true, + "rate": "70140000000000000000" + }, + "out": { + "capacity": "49700000000000000000000", + "isEnabled": true, + "rate": "82999000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "65200000000000000000000", + "isEnabled": true, + "rate": "108884000000000000000" + }, + "out": { + "capacity": "56100000000000000000000", + "isEnabled": true, + "rate": "93687000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "sonic-testnet-blaze": { + "custom": { + "in": { + "capacity": "40700000000000000000000", + "isEnabled": true, + "rate": "67969000000000000000" + }, + "out": { + "capacity": "54700000000000000000000", + "isEnabled": true, + "rate": "91349000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "tac-testnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "69900000000000000000000", + "isEnabled": true, + "rate": "116733000000000000000" + }, + "out": { + "capacity": "47600000000000000000000", + "isEnabled": true, + "rate": "79492000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "35100000000000000000000", + "isEnabled": true, + "rate": "58617000000000000000" + }, + "out": { + "capacity": "48200000000000000000000", + "isEnabled": true, + "rate": "80494000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdc-testnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia-andromeda-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "49000000000000000000000", + "isEnabled": true, + "rate": "81830000000000000000" + }, + "out": { + "capacity": "37600000000000000000000", + "isEnabled": true, + "rate": "62792000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "minBlockConfirmation": 3, + "remote": { + "aptos-testnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "37100000000000000000000", + "isEnabled": true, + "rate": "61957000000000000000" + }, + "out": { + "capacity": "30000000000000000000000", + "isEnabled": true, + "rate": "50100000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "45600000000000000000000", + "isEnabled": true, + "rate": "76152000000000000000" + }, + "out": { + "capacity": "34800000000000000000000", + "isEnabled": true, + "rate": "58116000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "59900000000000000000000", + "isEnabled": true, + "rate": "100033000000000000000" + }, + "out": { + "capacity": "38000000000000000000000", + "isEnabled": true, + "rate": "63460000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "34500000000000000000000", + "isEnabled": true, + "rate": "57615000000000000000" + }, + "out": { + "capacity": "51400000000000000000000", + "isEnabled": true, + "rate": "85838000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "shibarium-testnet-puppynet": { + "custom": { + "in": { + "capacity": "38900000000000000000000", + "isEnabled": true, + "rate": "64963000000000000000" + }, + "out": { + "capacity": "51300000000000000000000", + "isEnabled": true, + "rate": "85671000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "58100000000000000000000", + "isEnabled": true, + "rate": "97027000000000000000" + }, + "out": { + "capacity": "57500000000000000000000", + "isEnabled": true, + "rate": "96025000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "31100000000000000000000", + "isEnabled": true, + "rate": "51937000000000000000" + }, + "out": { + "capacity": "66900000000000000000000", + "isEnabled": true, + "rate": "111723000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "38500000000000000000000", + "isEnabled": true, + "rate": "64295000000000000000" + }, + "out": { + "capacity": "42500000000000000000000", + "isEnabled": true, + "rate": "70975000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "minBlockConfirmation": 5, + "remote": { + "aptos-testnet": { + "custom": null, + "standard": null + }, + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "31200000000000000000000", + "isEnabled": true, + "rate": "52104000000000000000" + }, + "out": { + "capacity": "62900000000000000000000", + "isEnabled": true, + "rate": "105043000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "68400000000000000000000", + "isEnabled": true, + "rate": "114228000000000000000" + }, + "out": { + "capacity": "43600000000000000000000", + "isEnabled": true, + "rate": "72812000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": null, + "standard": null + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "33700000000000000000000", + "isEnabled": true, + "rate": "56279000000000000000" + }, + "out": { + "capacity": "44300000000000000000000", + "isEnabled": true, + "rate": "73981000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-mode-1": { + "custom": { + "in": { + "capacity": "60000000000000000000000", + "isEnabled": true, + "rate": "100200000000000000000" + }, + "out": { + "capacity": "34500000000000000000000", + "isEnabled": true, + "rate": "57615000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "63600000000000000000000", + "isEnabled": true, + "rate": "106212000000000000000" + }, + "out": { + "capacity": "43000000000000000000000", + "isEnabled": true, + "rate": "71810000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "shibarium-testnet-puppynet": { + "custom": { + "in": { + "capacity": "54000000000000000000000", + "isEnabled": true, + "rate": "90180000000000000000" + }, + "out": { + "capacity": "46900000000000000000000", + "isEnabled": true, + "rate": "78323000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "48100000000000000000000", + "isEnabled": true, + "rate": "80327000000000000000" + }, + "out": { + "capacity": "34600000000000000000000", + "isEnabled": true, + "rate": "57782000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "51900000000000000000000", + "isEnabled": true, + "rate": "86673000000000000000" + }, + "out": { + "capacity": "42500000000000000000000", + "isEnabled": true, + "rate": "70975000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-blast-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "39000000000000000000000", + "isEnabled": true, + "rate": "65130000000000000000" + }, + "out": { + "capacity": "48200000000000000000000", + "isEnabled": true, + "rate": "80494000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-hashkey-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "43700000000000000000000", + "isEnabled": true, + "rate": "72979000000000000000" + }, + "out": { + "capacity": "33800000000000000000000", + "isEnabled": true, + "rate": "56446000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-lisk-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "35400000000000000000000", + "isEnabled": true, + "rate": "59118000000000000000" + }, + "out": { + "capacity": "46300000000000000000000", + "isEnabled": true, + "rate": "77321000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-mantle-1": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "34700000000000000000000", + "isEnabled": true, + "rate": "57949000000000000000" + }, + "out": { + "capacity": "51500000000000000000000", + "isEnabled": true, + "rate": "86005000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-mode-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "42500000000000000000000", + "isEnabled": true, + "rate": "70975000000000000000" + }, + "out": { + "capacity": "49200000000000000000000", + "isEnabled": true, + "rate": "82164000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "46900000000000000000000", + "isEnabled": true, + "rate": "78323000000000000000" + }, + "out": { + "capacity": "40200000000000000000000", + "isEnabled": true, + "rate": "67134000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "minBlockConfirmation": 1, + "remote": { + "aptos-testnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "61000000000000000000000", + "isEnabled": true, + "rate": "101870000000000000000" + }, + "out": { + "capacity": "48800000000000000000000", + "isEnabled": true, + "rate": "81496000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "47300000000000000000000", + "isEnabled": true, + "rate": "78991000000000000000" + }, + "out": { + "capacity": "38600000000000000000000", + "isEnabled": true, + "rate": "64462000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "54100000000000000000000", + "isEnabled": true, + "rate": "90347000000000000000" + }, + "out": { + "capacity": "54900000000000000000000", + "isEnabled": true, + "rate": "91683000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "53400000000000000000000", + "isEnabled": true, + "rate": "89178000000000000000" + }, + "out": { + "capacity": "52300000000000000000000", + "isEnabled": true, + "rate": "87341000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "51100000000000000000000", + "isEnabled": true, + "rate": "85337000000000000000" + }, + "out": { + "capacity": "40400000000000000000000", + "isEnabled": true, + "rate": "67468000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "shibarium-testnet-puppynet": { + "custom": { + "in": { + "capacity": "34700000000000000000000", + "isEnabled": true, + "rate": "57949000000000000000" + }, + "out": { + "capacity": "33500000000000000000000", + "isEnabled": true, + "rate": "55945000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "49600000000000000000000", + "isEnabled": true, + "rate": "82832000000000000000" + }, + "out": { + "capacity": "65900000000000000000000", + "isEnabled": true, + "rate": "110053000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "53500000000000000000000", + "isEnabled": true, + "rate": "89345000000000000000" + }, + "out": { + "capacity": "35800000000000000000000", + "isEnabled": true, + "rate": "59786000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "69700000000000000000000", + "isEnabled": true, + "rate": "116399000000000000000" + }, + "out": { + "capacity": "69400000000000000000000", + "isEnabled": true, + "rate": "115898000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-unichain-1": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "61100000000000000000000", + "isEnabled": true, + "rate": "102037000000000000000" + }, + "out": { + "capacity": "64200000000000000000000", + "isEnabled": true, + "rate": "107214000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-worldchain-1": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "32400000000000000000000", + "isEnabled": true, + "rate": "54108000000000000000" + }, + "out": { + "capacity": "47700000000000000000000", + "isEnabled": true, + "rate": "79659000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-zksync-1": { + "minBlockConfirmation": null, + "remote": { + "ethereum-testnet-sepolia": { + "custom": null, + "standard": null + } + } + }, + "hedera-testnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "68100000000000000000000", + "isEnabled": true, + "rate": "113727000000000000000" + }, + "out": { + "capacity": "64900000000000000000000", + "isEnabled": true, + "rate": "108383000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ink-testnet-sepolia": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "62400000000000000000000", + "isEnabled": true, + "rate": "104208000000000000000" + }, + "out": { + "capacity": "68900000000000000000000", + "isEnabled": true, + "rate": "115063000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "jovay-testnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "memento-testnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "metal-testnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "57500000000000000000000", + "isEnabled": true, + "rate": "96025000000000000000" + }, + "out": { + "capacity": "59900000000000000000000", + "isEnabled": true, + "rate": "100033000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "mint-testnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "44900000000000000000000", + "isEnabled": true, + "rate": "74983000000000000000" + }, + "out": { + "capacity": "57400000000000000000000", + "isEnabled": true, + "rate": "95858000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "plume-testnet-sepolia": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "45900000000000000000000", + "isEnabled": true, + "rate": "76653000000000000000" + }, + "out": { + "capacity": "32800000000000000000000", + "isEnabled": true, + "rate": "54776000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "polkadot-testnet-astar-shibuya": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "41800000000000000000000", + "isEnabled": true, + "rate": "69806000000000000000" + }, + "out": { + "capacity": "50300000000000000000000", + "isEnabled": true, + "rate": "84001000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "polygon-testnet-amoy": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "40000000000000000000000", + "isEnabled": true, + "rate": "66800000000000000000" + }, + "out": { + "capacity": "55200000000000000000000", + "isEnabled": true, + "rate": "92184000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "37800000000000000000000", + "isEnabled": true, + "rate": "63126000000000000000" + }, + "out": { + "capacity": "41600000000000000000000", + "isEnabled": true, + "rate": "69472000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": null, + "standard": null + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "62200000000000000000000", + "isEnabled": true, + "rate": "103874000000000000000" + }, + "out": { + "capacity": "65300000000000000000000", + "isEnabled": true, + "rate": "109051000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "59500000000000000000000", + "isEnabled": true, + "rate": "99365000000000000000" + }, + "out": { + "capacity": "64600000000000000000000", + "isEnabled": true, + "rate": "107882000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "53700000000000000000000", + "isEnabled": true, + "rate": "89679000000000000000" + }, + "out": { + "capacity": "61200000000000000000000", + "isEnabled": true, + "rate": "102204000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "polygon-testnet-tatara": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-holesky": { + "custom": { + "in": { + "capacity": "37500000000000000000000", + "isEnabled": true, + "rate": "62625000000000000000" + }, + "out": { + "capacity": "68700000000000000000000", + "isEnabled": true, + "rate": "114729000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ronin-testnet-saigon": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "53400000000000000000000", + "isEnabled": true, + "rate": "89178000000000000000" + }, + "out": { + "capacity": "39700000000000000000000", + "isEnabled": true, + "rate": "66299000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "sei-testnet-atlantic": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "62900000000000000000000", + "isEnabled": true, + "rate": "105043000000000000000" + }, + "out": { + "capacity": "34200000000000000000000", + "isEnabled": true, + "rate": "57114000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "shibarium-testnet-puppynet": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "46200000000000000000000", + "isEnabled": true, + "rate": "77154000000000000000" + }, + "out": { + "capacity": "65700000000000000000000", + "isEnabled": true, + "rate": "109719000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "48100000000000000000000", + "isEnabled": true, + "rate": "80327000000000000000" + }, + "out": { + "capacity": "58500000000000000000000", + "isEnabled": true, + "rate": "97695000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "34500000000000000000000", + "isEnabled": true, + "rate": "57615000000000000000" + }, + "out": { + "capacity": "69400000000000000000000", + "isEnabled": true, + "rate": "115898000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": null, + "standard": null + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "45100000000000000000000", + "isEnabled": true, + "rate": "75317000000000000000" + }, + "out": { + "capacity": "63200000000000000000000", + "isEnabled": true, + "rate": "105544000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "solana-devnet": { + "minBlockConfirmation": 9, + "remote": { + "bsc-testnet": { + "custom": { + "in": { + "capacity": "62200000000000", + "isEnabled": true, + "rate": "103874000000" + }, + "out": { + "capacity": "50400000000000", + "isEnabled": true, + "rate": "84168000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + }, + "out": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "54200000000000", + "isEnabled": true, + "rate": "90514000000" + }, + "out": { + "capacity": "55300000000000", + "isEnabled": true, + "rate": "92351000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + }, + "out": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "60900000000000", + "isEnabled": true, + "rate": "101703000000" + }, + "out": { + "capacity": "65000000000000", + "isEnabled": true, + "rate": "108550000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + }, + "out": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "40800000000000", + "isEnabled": true, + "rate": "68136000000" + }, + "out": { + "capacity": "68300000000000", + "isEnabled": true, + "rate": "114061000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + }, + "out": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "36800000000000", + "isEnabled": true, + "rate": "61456000000" + }, + "out": { + "capacity": "41500000000000", + "isEnabled": true, + "rate": "69305000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + }, + "out": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + } + } + }, + "sonic-testnet-blaze": { + "custom": { + "in": { + "capacity": "64300000000000", + "isEnabled": true, + "rate": "107381000000" + }, + "out": { + "capacity": "31800000000000", + "isEnabled": true, + "rate": "53106000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + }, + "out": { + "capacity": "100000000000000", + "isEnabled": true, + "rate": "167000000000" + } + } + } + } + }, + "sonic-testnet-blaze": { + "minBlockConfirmation": 9, + "remote": { + "aptos-testnet": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "68500000000000000000000", + "isEnabled": true, + "rate": "114395000000000000000" + }, + "out": { + "capacity": "49500000000000000000000", + "isEnabled": true, + "rate": "82665000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "33200000000000000000000", + "isEnabled": true, + "rate": "55444000000000000000" + }, + "out": { + "capacity": "43200000000000000000000", + "isEnabled": true, + "rate": "72144000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "tac-testnet": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "wemix-testnet": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "45600000000000000000000", + "isEnabled": true, + "rate": "76152000000000000000" + }, + "out": { + "capacity": "44700000000000000000000", + "isEnabled": true, + "rate": "74649000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "60500000000000000000000", + "isEnabled": true, + "rate": "101035000000000000000" + }, + "out": { + "capacity": "52500000000000000000000", + "isEnabled": true, + "rate": "87675000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "45100000000000000000000", + "isEnabled": true, + "rate": "75317000000000000000" + }, + "out": { + "capacity": "41800000000000000000000", + "isEnabled": true, + "rate": "69806000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "38300000000000000000000", + "isEnabled": true, + "rate": "63961000000000000000" + }, + "out": { + "capacity": "30700000000000000000000", + "isEnabled": true, + "rate": "51269000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "66000000000000000000000", + "isEnabled": true, + "rate": "110220000000000000000" + }, + "out": { + "capacity": "38700000000000000000000", + "isEnabled": true, + "rate": "64629000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "37700000000000000000000", + "isEnabled": true, + "rate": "62959000000000000000" + }, + "out": { + "capacity": "42700000000000000000000", + "isEnabled": true, + "rate": "71309000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "xdai-testnet-chiado": { + "minBlockConfirmation": 4, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "44700000000000000000000", + "isEnabled": true, + "rate": "74649000000000000000" + }, + "out": { + "capacity": "38100000000000000000000", + "isEnabled": true, + "rate": "63627000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "59100000000000000000000", + "isEnabled": true, + "rate": "98697000000000000000" + }, + "out": { + "capacity": "51300000000000000000000", + "isEnabled": true, + "rate": "85671000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "52500000000000000000000", + "isEnabled": true, + "rate": "87675000000000000000" + }, + "out": { + "capacity": "61300000000000000000000", + "isEnabled": true, + "rate": "102371000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "40300000000000000000000", + "isEnabled": true, + "rate": "67301000000000000000" + }, + "out": { + "capacity": "51500000000000000000000", + "isEnabled": true, + "rate": "86005000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "50000000000000000000000", + "isEnabled": true, + "rate": "83500000000000000000" + }, + "out": { + "capacity": "54500000000000000000000", + "isEnabled": true, + "rate": "91015000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "56900000000000000000000", + "isEnabled": true, + "rate": "95023000000000000000" + }, + "out": { + "capacity": "45900000000000000000000", + "isEnabled": true, + "rate": "76653000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "64700000000000000000000", + "isEnabled": true, + "rate": "108049000000000000000" + }, + "out": { + "capacity": "53500000000000000000000", + "isEnabled": true, + "rate": "89345000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "xdc-testnet": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + }, + "out": { + "capacity": "1000000000000000000000", + "isEnabled": true, + "rate": "1000000000000000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "CCIP-LnM": { + "avalanche-fuji-testnet": { + "minBlockConfirmation": 8, + "remote": { + "bsc-testnet": { + "custom": { + "in": { + "capacity": "31500000000000000000000", + "isEnabled": true, + "rate": "52605000000000000000" + }, + "out": { + "capacity": "49900000000000000000000", + "isEnabled": true, + "rate": "83333000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "58000000000000000000000", + "isEnabled": true, + "rate": "96860000000000000000" + }, + "out": { + "capacity": "47600000000000000000000", + "isEnabled": true, + "rate": "79492000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "43000000000000000000000", + "isEnabled": true, + "rate": "71810000000000000000" + }, + "out": { + "capacity": "57200000000000000000000", + "isEnabled": true, + "rate": "95524000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "32600000000000000000000", + "isEnabled": true, + "rate": "54442000000000000000" + }, + "out": { + "capacity": "49100000000000000000000", + "isEnabled": true, + "rate": "81997000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "37400000000000000000000", + "isEnabled": true, + "rate": "62458000000000000000" + }, + "out": { + "capacity": "37600000000000000000000", + "isEnabled": true, + "rate": "62792000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "56600000000000000000000", + "isEnabled": true, + "rate": "94522000000000000000" + }, + "out": { + "capacity": "64000000000000000000000", + "isEnabled": true, + "rate": "106880000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "38000000000000000000000", + "isEnabled": true, + "rate": "63460000000000000000" + }, + "out": { + "capacity": "34800000000000000000000", + "isEnabled": true, + "rate": "58116000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": null, + "standard": null + } + } + }, + "bsc-testnet": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "60000000000000000000000", + "isEnabled": true, + "rate": "100200000000000000000" + }, + "out": { + "capacity": "60200000000000000000000", + "isEnabled": true, + "rate": "100534000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "42400000000000000000000", + "isEnabled": true, + "rate": "70808000000000000000" + }, + "out": { + "capacity": "51700000000000000000000", + "isEnabled": true, + "rate": "86339000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "46000000000000000000000", + "isEnabled": true, + "rate": "76820000000000000000" + }, + "out": { + "capacity": "48100000000000000000000", + "isEnabled": true, + "rate": "80327000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "67200000000000000000000", + "isEnabled": true, + "rate": "112224000000000000000" + }, + "out": { + "capacity": "69300000000000000000000", + "isEnabled": true, + "rate": "115731000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "65300000000000000000000", + "isEnabled": true, + "rate": "109051000000000000000" + }, + "out": { + "capacity": "39300000000000000000000", + "isEnabled": true, + "rate": "65631000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "48700000000000000000000", + "isEnabled": true, + "rate": "81329000000000000000" + }, + "out": { + "capacity": "60000000000000000000000", + "isEnabled": true, + "rate": "100200000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "celo-testnet-alfajores": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "67700000000000000000000", + "isEnabled": true, + "rate": "113059000000000000000" + }, + "out": { + "capacity": "64100000000000000000000", + "isEnabled": true, + "rate": "107047000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "44500000000000000000000", + "isEnabled": true, + "rate": "74315000000000000000" + }, + "out": { + "capacity": "64400000000000000000000", + "isEnabled": true, + "rate": "107548000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "68800000000000000000000", + "isEnabled": true, + "rate": "114896000000000000000" + }, + "out": { + "capacity": "35200000000000000000000", + "isEnabled": true, + "rate": "58784000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "celo-testnet-alfajores": { + "custom": { + "in": { + "capacity": "41000000000000000000000", + "isEnabled": true, + "rate": "68470000000000000000" + }, + "out": { + "capacity": "60800000000000000000000", + "isEnabled": true, + "rate": "101536000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-andromeda-1": { + "custom": { + "in": { + "capacity": "68000000000000000000000", + "isEnabled": true, + "rate": "113560000000000000000" + }, + "out": { + "capacity": "45500000000000000000000", + "isEnabled": true, + "rate": "75985000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "52900000000000000000000", + "isEnabled": true, + "rate": "88343000000000000000" + }, + "out": { + "capacity": "36700000000000000000000", + "isEnabled": true, + "rate": "61289000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "35000000000000000000000", + "isEnabled": true, + "rate": "58450000000000000000" + }, + "out": { + "capacity": "47700000000000000000000", + "isEnabled": true, + "rate": "79659000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-blast-1": { + "custom": { + "in": { + "capacity": "50300000000000000000000", + "isEnabled": true, + "rate": "84001000000000000000" + }, + "out": { + "capacity": "47800000000000000000000", + "isEnabled": true, + "rate": "79826000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-linea-1": { + "custom": { + "in": { + "capacity": "51600000000000000000000", + "isEnabled": true, + "rate": "86172000000000000000" + }, + "out": { + "capacity": "43400000000000000000000", + "isEnabled": true, + "rate": "72478000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-mantle-1": { + "custom": { + "in": { + "capacity": "54400000000000000000000", + "isEnabled": true, + "rate": "90848000000000000000" + }, + "out": { + "capacity": "52000000000000000000000", + "isEnabled": true, + "rate": "86840000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-mode-1": { + "custom": { + "in": { + "capacity": "53800000000000000000000", + "isEnabled": true, + "rate": "89846000000000000000" + }, + "out": { + "capacity": "59400000000000000000000", + "isEnabled": true, + "rate": "99198000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "59300000000000000000000", + "isEnabled": true, + "rate": "99031000000000000000" + }, + "out": { + "capacity": "37700000000000000000000", + "isEnabled": true, + "rate": "62959000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-polygon-zkevm-1": { + "custom": { + "in": { + "capacity": "65400000000000000000000", + "isEnabled": true, + "rate": "109218000000000000000" + }, + "out": { + "capacity": "32400000000000000000000", + "isEnabled": true, + "rate": "54108000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-scroll-1": { + "custom": { + "in": { + "capacity": "67400000000000000000000", + "isEnabled": true, + "rate": "112558000000000000000" + }, + "out": { + "capacity": "53200000000000000000000", + "isEnabled": true, + "rate": "88844000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-xlayer-1": { + "custom": { + "in": { + "capacity": "68700000000000000000000", + "isEnabled": true, + "rate": "114729000000000000000" + }, + "out": { + "capacity": "55500000000000000000000", + "isEnabled": true, + "rate": "92685000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-zksync-1": { + "custom": { + "in": { + "capacity": "40800000000000000000000", + "isEnabled": true, + "rate": "68136000000000000000" + }, + "out": { + "capacity": "62400000000000000000000", + "isEnabled": true, + "rate": "104208000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polkadot-testnet-astar-shibuya": { + "custom": { + "in": { + "capacity": "114228000000000000000", + "isEnabled": true, + "rate": "68400000000000000000" + }, + "out": { + "capacity": "84001000000000000000", + "isEnabled": true, + "rate": "50300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "167000000000000000000", + "isEnabled": true, + "rate": "100000000000000000000" + }, + "out": { + "capacity": "167000000000000000000", + "isEnabled": true, + "rate": "100000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "36900000000000000000000", + "isEnabled": true, + "rate": "61623000000000000000" + }, + "out": { + "capacity": "44600000000000000000000", + "isEnabled": true, + "rate": "74482000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ronin-testnet-saigon": { + "custom": { + "in": { + "capacity": "59400000000000000000000", + "isEnabled": true, + "rate": "99198000000000000000" + }, + "out": { + "capacity": "38200000000000000000000", + "isEnabled": true, + "rate": "63794000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "69700000000000000000000", + "isEnabled": true, + "rate": "116399000000000000000" + }, + "out": { + "capacity": "101703000000000000000", + "isEnabled": true, + "rate": "60900000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "167000000000000000000", + "isEnabled": true, + "rate": "100000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "58500000000000000000000", + "isEnabled": true, + "rate": "97695000000000000000" + }, + "out": { + "capacity": "33200000000000000000000", + "isEnabled": true, + "rate": "55444000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-andromeda-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "61100000000000000000000", + "isEnabled": true, + "rate": "102037000000000000000" + }, + "out": { + "capacity": "48100000000000000000000", + "isEnabled": true, + "rate": "80327000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "minBlockConfirmation": 5, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "47300000000000000000000", + "isEnabled": true, + "rate": "78991000000000000000" + }, + "out": { + "capacity": "30900000000000000000000", + "isEnabled": true, + "rate": "51603000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "69900000000000000000000", + "isEnabled": true, + "rate": "116733000000000000000" + }, + "out": { + "capacity": "48500000000000000000000", + "isEnabled": true, + "rate": "80995000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "41300000000000000000000", + "isEnabled": true, + "rate": "68971000000000000000" + }, + "out": { + "capacity": "52700000000000000000000", + "isEnabled": true, + "rate": "88009000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "41900000000000000000000", + "isEnabled": true, + "rate": "69973000000000000000" + }, + "out": { + "capacity": "33200000000000000000000", + "isEnabled": true, + "rate": "55444000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "34500000000000000000000", + "isEnabled": true, + "rate": "57615000000000000000" + }, + "out": { + "capacity": "66400000000000000000000", + "isEnabled": true, + "rate": "110888000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "31400000000000000000000", + "isEnabled": true, + "rate": "52438000000000000000" + }, + "out": { + "capacity": "47300000000000000000000", + "isEnabled": true, + "rate": "78991000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "minBlockConfirmation": 1, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "44400000000000000000000", + "isEnabled": true, + "rate": "74148000000000000000" + }, + "out": { + "capacity": "61600000000000000000000", + "isEnabled": true, + "rate": "102872000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "46400000000000000000000", + "isEnabled": true, + "rate": "77488000000000000000" + }, + "out": { + "capacity": "55000000000000000000000", + "isEnabled": true, + "rate": "91850000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "50200000000000000000000", + "isEnabled": true, + "rate": "83834000000000000000" + }, + "out": { + "capacity": "32300000000000000000000", + "isEnabled": true, + "rate": "53941000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "61800000000000000000000", + "isEnabled": true, + "rate": "103206000000000000000" + }, + "out": { + "capacity": "39200000000000000000000", + "isEnabled": true, + "rate": "65464000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-mode-1": { + "custom": { + "in": { + "capacity": "47000000000000000000000", + "isEnabled": true, + "rate": "78490000000000000000" + }, + "out": { + "capacity": "57500000000000000000000", + "isEnabled": true, + "rate": "96025000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "32600000000000000000000", + "isEnabled": true, + "rate": "54442000000000000000" + }, + "out": { + "capacity": "37300000000000000000000", + "isEnabled": true, + "rate": "62291000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "35600000000000000000000", + "isEnabled": true, + "rate": "59452000000000000000" + }, + "out": { + "capacity": "44000000000000000000000", + "isEnabled": true, + "rate": "73480000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-blast-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "35900000000000000000000", + "isEnabled": true, + "rate": "59953000000000000000" + }, + "out": { + "capacity": "43900000000000000000000", + "isEnabled": true, + "rate": "73313000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-kroma-1": { + "minBlockConfirmation": 1, + "remote": { + "wemix-testnet": { + "custom": { + "in": { + "capacity": "48200000000000000000000", + "isEnabled": true, + "rate": "80494000000000000000" + }, + "out": { + "capacity": "53500000000000000000000", + "isEnabled": true, + "rate": "89345000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-linea-1": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "63800000000000000000000", + "isEnabled": true, + "rate": "106546000000000000000" + }, + "out": { + "capacity": "65400000000000000000000", + "isEnabled": true, + "rate": "109218000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-mantle-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "63200000000000000000000", + "isEnabled": true, + "rate": "105544000000000000000" + }, + "out": { + "capacity": "35500000000000000000000", + "isEnabled": true, + "rate": "59285000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-mode-1": { + "minBlockConfirmation": 4, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "50700000000000000000000", + "isEnabled": true, + "rate": "84669000000000000000" + }, + "out": { + "capacity": "49500000000000000000000", + "isEnabled": true, + "rate": "82665000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "40900000000000000000000", + "isEnabled": true, + "rate": "68303000000000000000" + }, + "out": { + "capacity": "45900000000000000000000", + "isEnabled": true, + "rate": "76653000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "68400000000000000000000", + "isEnabled": true, + "rate": "114228000000000000000" + }, + "out": { + "capacity": "41500000000000000000000", + "isEnabled": true, + "rate": "69305000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "52900000000000000000000", + "isEnabled": true, + "rate": "88343000000000000000" + }, + "out": { + "capacity": "59700000000000000000000", + "isEnabled": true, + "rate": "99699000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "50400000000000000000000", + "isEnabled": true, + "rate": "84168000000000000000" + }, + "out": { + "capacity": "54800000000000000000000", + "isEnabled": true, + "rate": "91516000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "61100000000000000000000", + "isEnabled": true, + "rate": "102037000000000000000" + }, + "out": { + "capacity": "57200000000000000000000", + "isEnabled": true, + "rate": "95524000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "54100000000000000000000", + "isEnabled": true, + "rate": "90347000000000000000" + }, + "out": { + "capacity": "48600000000000000000000", + "isEnabled": true, + "rate": "81162000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "33300000000000000000000", + "isEnabled": true, + "rate": "55611000000000000000" + }, + "out": { + "capacity": "38900000000000000000000", + "isEnabled": true, + "rate": "64963000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "52100000000000000000000", + "isEnabled": true, + "rate": "87007000000000000000" + }, + "out": { + "capacity": "61200000000000000000000", + "isEnabled": true, + "rate": "102204000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-polygon-zkevm-1": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "46000000000000000000000", + "isEnabled": true, + "rate": "76820000000000000000" + }, + "out": { + "capacity": "42000000000000000000000", + "isEnabled": true, + "rate": "70140000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-scroll-1": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "41500000000000000000000", + "isEnabled": true, + "rate": "69305000000000000000" + }, + "out": { + "capacity": "57000000000000000000000", + "isEnabled": true, + "rate": "95190000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-xlayer-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "55100000000000000000000", + "isEnabled": true, + "rate": "92017000000000000000" + }, + "out": { + "capacity": "52200000000000000000000", + "isEnabled": true, + "rate": "87174000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ethereum-testnet-sepolia-zksync-1": { + "minBlockConfirmation": 9, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "69000000000000000000000", + "isEnabled": true, + "rate": "115230000000000000000" + }, + "out": { + "capacity": "48400000000000000000000", + "isEnabled": true, + "rate": "80828000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "polkadot-testnet-astar-shibuya": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "78490000000000000000", + "isEnabled": true, + "rate": "47000000000000000000" + }, + "out": { + "capacity": "92351000000000000000", + "isEnabled": true, + "rate": "55300000000000000000" + } + }, + "standard": { + "in": { + "capacity": "167000000000000000000", + "isEnabled": true, + "rate": "100000000000000000000" + }, + "out": { + "capacity": "167000000000000000000", + "isEnabled": true, + "rate": "100000000000000000000" + } + } + } + } + }, + "polygon-testnet-amoy": { + "minBlockConfirmation": 6, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "63700000000000000000000", + "isEnabled": true, + "rate": "106379000000000000000" + }, + "out": { + "capacity": "41100000000000000000000", + "isEnabled": true, + "rate": "68637000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "64800000000000000000000", + "isEnabled": true, + "rate": "108216000000000000000" + }, + "out": { + "capacity": "58500000000000000000000", + "isEnabled": true, + "rate": "97695000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "58400000000000000000000", + "isEnabled": true, + "rate": "97528000000000000000" + }, + "out": { + "capacity": "37100000000000000000000", + "isEnabled": true, + "rate": "61957000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "36600000000000000000000", + "isEnabled": true, + "rate": "61122000000000000000" + }, + "out": { + "capacity": "56400000000000000000000", + "isEnabled": true, + "rate": "94188000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "wemix-testnet": { + "custom": { + "in": { + "capacity": "32300000000000000000000", + "isEnabled": true, + "rate": "53941000000000000000" + }, + "out": { + "capacity": "30900000000000000000000", + "isEnabled": true, + "rate": "51603000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "xdai-testnet-chiado": { + "custom": { + "in": { + "capacity": "34200000000000000000000", + "isEnabled": true, + "rate": "57114000000000000000" + }, + "out": { + "capacity": "68200000000000000000000", + "isEnabled": true, + "rate": "113894000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "ronin-testnet-saigon": { + "minBlockConfirmation": 7, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "56900000000000000000000", + "isEnabled": true, + "rate": "95023000000000000000" + }, + "out": { + "capacity": "53000000000000000000000", + "isEnabled": true, + "rate": "88510000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "wemix-testnet": { + "minBlockConfirmation": 2, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "54300000000000000000000", + "isEnabled": true, + "rate": "90681000000000000000" + }, + "out": { + "capacity": "46600000000000000000000", + "isEnabled": true, + "rate": "77822000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "68900000000000000000000", + "isEnabled": true, + "rate": "115063000000000000000" + }, + "out": { + "capacity": "66400000000000000000000", + "isEnabled": true, + "rate": "110888000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "43200000000000000000000", + "isEnabled": true, + "rate": "72144000000000000000" + }, + "out": { + "capacity": "43200000000000000000000", + "isEnabled": true, + "rate": "72144000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "33200000000000000000000", + "isEnabled": true, + "rate": "55444000000000000000" + }, + "out": { + "capacity": "64100000000000000000000", + "isEnabled": true, + "rate": "107047000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-kroma-1": { + "custom": { + "in": { + "capacity": "48600000000000000000000", + "isEnabled": true, + "rate": "81162000000000000000" + }, + "out": { + "capacity": "37500000000000000000000", + "isEnabled": true, + "rate": "62625000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "63600000000000000000000", + "isEnabled": true, + "rate": "106212000000000000000" + }, + "out": { + "capacity": "59500000000000000000000", + "isEnabled": true, + "rate": "99365000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "63200000000000000000000", + "isEnabled": true, + "rate": "105544000000000000000" + }, + "out": { + "capacity": "35200000000000000000000", + "isEnabled": true, + "rate": "58784000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + }, + "xdai-testnet-chiado": { + "minBlockConfirmation": 10, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "63600000000000000000000", + "isEnabled": true, + "rate": "106212000000000000000" + }, + "out": { + "capacity": "36900000000000000000000", + "isEnabled": true, + "rate": "61623000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "bsc-testnet": { + "custom": { + "in": { + "capacity": "68700000000000000000000", + "isEnabled": true, + "rate": "114729000000000000000" + }, + "out": { + "capacity": "67200000000000000000000", + "isEnabled": true, + "rate": "112224000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "64900000000000000000000", + "isEnabled": true, + "rate": "108383000000000000000" + }, + "out": { + "capacity": "37200000000000000000000", + "isEnabled": true, + "rate": "62124000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "59800000000000000000000", + "isEnabled": true, + "rate": "99866000000000000000" + }, + "out": { + "capacity": "60800000000000000000000", + "isEnabled": true, + "rate": "101536000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "60300000000000000000000", + "isEnabled": true, + "rate": "100701000000000000000" + }, + "out": { + "capacity": "60500000000000000000000", + "isEnabled": true, + "rate": "101035000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "30800000000000000000000", + "isEnabled": true, + "rate": "51436000000000000000" + }, + "out": { + "capacity": "32800000000000000000000", + "isEnabled": true, + "rate": "54776000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "33200000000000000000000", + "isEnabled": true, + "rate": "55444000000000000000" + }, + "out": { + "capacity": "46400000000000000000000", + "isEnabled": true, + "rate": "77488000000000000000" + } + }, + "standard": { + "in": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + }, + "out": { + "capacity": "100000000000000000000000", + "isEnabled": true, + "rate": "167000000000000000000" + } + } + } + } + } + }, + "syrupUSDC": { + "ethereum-testnet-sepolia": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "solana-devnet": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "syrupUSDT": { + "ethereum-testnet-sepolia": { + "minBlockConfirmation": 1, + "remote": { + "ethereum-testnet-sepolia-mantle-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "plasma-testnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia-mantle-1": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "plasma-testnet": { + "minBlockConfirmation": 5, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + }, + "USDC": { + "avalanche-fuji-testnet": { + "minBlockConfirmation": 10, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia": { + "minBlockConfirmation": 8, + "remote": { + "avalanche-fuji-testnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "minBlockConfirmation": 8, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia-base-1": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "minBlockConfirmation": 3, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "ethereum-testnet-sepolia-unichain-1": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-devnet": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + }, + "polygon-testnet-amoy": { + "minBlockConfirmation": 2, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "solana-devnet": { + "custom": null, + "standard": null + } + } + }, + "solana-devnet": { + "minBlockConfirmation": 6, + "remote": { + "ethereum-testnet-sepolia": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "ethereum-testnet-sepolia-unichain-1": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + }, + "polygon-testnet-amoy": { + "custom": { + "in": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + }, + "out": { + "capacity": "1000000000", + "isEnabled": true, + "rate": "1000000" + } + }, + "standard": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } + } + } + } +} diff --git a/src/assets/icons/remix-logo.svg b/src/assets/icons/remix-logo.svg new file mode 100644 index 00000000000..4580f3bf83b --- /dev/null +++ b/src/assets/icons/remix-logo.svg @@ -0,0 +1,13 @@ + +
+ + + + + + + + + + +
diff --git a/src/assets/icons/token-icon.svg b/src/assets/icons/token-icon.svg new file mode 100644 index 00000000000..2b8c333d430 --- /dev/null +++ b/src/assets/icons/token-icon.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/product-logos/automated-compliance-engine.svg b/src/assets/product-logos/automated-compliance-engine.svg new file mode 100644 index 00000000000..e786648eddd --- /dev/null +++ b/src/assets/product-logos/automated-compliance-engine.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/product-logos/chainlink-local-2-logo.svg b/src/assets/product-logos/chainlink-local-2-logo.svg new file mode 100644 index 00000000000..f3a6360b201 --- /dev/null +++ b/src/assets/product-logos/chainlink-local-2-logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/product-logos/data-link-vault.svg b/src/assets/product-logos/data-link-vault.svg new file mode 100644 index 00000000000..292b03b63a5 --- /dev/null +++ b/src/assets/product-logos/data-link-vault.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/product-logos/general-globe-logo.svg b/src/assets/product-logos/general-globe-logo.svg new file mode 100644 index 00000000000..11804ee8b1e --- /dev/null +++ b/src/assets/product-logos/general-globe-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/product-logos/nodes-logo.svg b/src/assets/product-logos/nodes-logo.svg new file mode 100644 index 00000000000..016dae52333 --- /dev/null +++ b/src/assets/product-logos/nodes-logo.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/Address.tsx b/src/components/Address.tsx index 5544b5e225b..1acc8b3c07d 100644 --- a/src/components/Address.tsx +++ b/src/components/Address.tsx @@ -55,6 +55,7 @@ const AddressComponent = ({ padding: 1px 5px; border-radius: var(--border-radius-10); word-break: break-word; + color: var(--blue-600); } .addressContainer { diff --git a/src/components/AddressReact.tsx b/src/components/AddressReact.tsx index 84648e9f3e4..46d3e69bace 100644 --- a/src/components/AddressReact.tsx +++ b/src/components/AddressReact.tsx @@ -40,6 +40,7 @@ const AddressComponent = ({ contractUrl, address, endLength, urlClass, urlId }: padding: 1px 0px; border-radius: var(--border-radius-10); word-break: break-word; + color: var(--blue-600); } .addressContainer { diff --git a/src/components/CCIP/AddButton/AddButton.astro b/src/components/CCIP/AddButton/AddButton.astro new file mode 100644 index 00000000000..bd52b43b126 --- /dev/null +++ b/src/components/CCIP/AddButton/AddButton.astro @@ -0,0 +1,47 @@ +--- +export interface Props { + href: string + text: string + urlClass?: string +} + +const { href, text, urlClass } = Astro.props +--- + + + Add + {text} + + + diff --git a/src/components/CCIP/Cards/Card.css b/src/components/CCIP/Cards/Card.css new file mode 100644 index 00000000000..bb77dae5555 --- /dev/null +++ b/src/components/CCIP/Cards/Card.css @@ -0,0 +1,40 @@ +.card__container { + display: flex; + padding: var(--space-6x); + gap: var(--space-3x); + width: 100%; + background: var(--white); + border: 1px solid var(--gray-200); + border-radius: var(--space-1x); + /* Optimize rendering performance */ + contain: layout style paint; + will-change: background-color; +} + +.card__container:hover { + background-color: var(--gray-50); +} + +.card__container img, +.card__container object, +.card__container object img { + width: var(--space-10x); + height: var(--space-10x); + margin-top: auto; + margin-bottom: auto; +} + +.card__container h3 { + font-size: var(--space-4x); + font-weight: var(--font-weight-medium); + line-height: var(--space-6x); + color: var(--gray-950); + margin-bottom: var(--space-1x); +} + +.card__container p { + margin-bottom: 0; + font-size: var(--space-3x); + line-height: var(--space-5x); + color: var(--gray-500); +} diff --git a/src/components/CCIP/Cards/Card.tsx b/src/components/CCIP/Cards/Card.tsx new file mode 100644 index 00000000000..669bd9155ff --- /dev/null +++ b/src/components/CCIP/Cards/Card.tsx @@ -0,0 +1,43 @@ +import { memo, type ReactNode } from "react" +import "./Card.css" + +interface CardProps { + logo: ReactNode + title: string + subtitle?: string + link?: string + onClick?: () => void + ariaLabel?: string +} + +const Card = memo(function Card({ logo, title, subtitle, link, onClick, ariaLabel }: CardProps) { + const content = ( + <> + {logo} +
+

{title}

+ {subtitle &&

{subtitle}

} +
+ + ) + + if (link) { + return ( + +
{content}
+
+ ) + } + + if (onClick) { + return ( + + ) + } + + return
{content}
+}) + +export default Card diff --git a/src/components/CCIP/Cards/NetworkCard.tsx b/src/components/CCIP/Cards/NetworkCard.tsx index 839f4389d4d..5d5ee0f4e99 100644 --- a/src/components/CCIP/Cards/NetworkCard.tsx +++ b/src/components/CCIP/Cards/NetworkCard.tsx @@ -1,5 +1,5 @@ import { memo } from "react" -import "./NetworkCard.css" +import Card from "./Card.tsx" interface NetworkCardProps { name: string @@ -9,17 +9,9 @@ interface NetworkCardProps { } const NetworkCard = memo(function NetworkCard({ name, totalLanes, totalTokens, logo }: NetworkCardProps) { - return ( -
- -
-

{name}

-

- {totalLanes} {totalLanes > 1 ? "lanes" : "lane"} | {totalTokens} {totalTokens > 1 ? "tokens" : "token"} -

-
-
- ) + const subtitle = `${totalLanes} ${totalLanes === 1 ? "lane" : "lanes"} | ${totalTokens} ${totalTokens === 1 ? "token" : "tokens"}` + + return } title={name} subtitle={subtitle} /> }) export default NetworkCard diff --git a/src/components/CCIP/Cards/TokenCard.css b/src/components/CCIP/Cards/TokenCard.css index c2d092aa132..ae035e97a19 100644 --- a/src/components/CCIP/Cards/TokenCard.css +++ b/src/components/CCIP/Cards/TokenCard.css @@ -1,19 +1,11 @@ .token-card__container { display: flex; - width: 100%; - height: 110px; - min-width: 110px; - margin: 0 auto; - flex-direction: column; - align-items: center; - text-align: center; - padding: var(--space-4x); + padding: var(--space-6x); gap: var(--space-3x); - background: #ffffff; + width: 100%; + background: var(--white); border: 1px solid var(--gray-200); border-radius: var(--space-1x); - justify-content: center; - cursor: pointer; /* Optimize rendering performance */ contain: layout style paint; will-change: background-color; @@ -27,14 +19,24 @@ .token-card__container object img { width: var(--space-10x); height: var(--space-10x); + margin-top: auto; + margin-bottom: auto; border-radius: 50%; } .token-card__container h3 { font-size: var(--space-4x); - font-weight: 500; + font-weight: var(--font-weight-medium); + line-height: var(--space-6x); color: var(--gray-950); + margin-bottom: var(--space-1x); +} + +.token-card__container p { margin-bottom: 0; + font-size: var(--space-3x); + line-height: var(--space-5x); + color: var(--gray-500); } .truncate { @@ -49,3 +51,58 @@ height: 124px; } } + +/* Square variant styles */ +.token-card__square-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: var(--space-6x); + width: 100%; + background: var(--white); + border: 1px solid var(--gray-200); + border-radius: var(--space-1x); + text-align: center; +} + +.token-card__square-container:hover { + background-color: var(--gray-50); +} + +.token-card__square-logo { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: var(--space-4x); +} + +.token-card__square-logo object, +.token-card__square-logo object img { + width: var(--space-16x); + height: var(--space-16x); + border-radius: 50%; +} + +.token-card__square-content { + display: flex; + flex-direction: column; + align-items: center; +} + +.token-card__square-content h3 { + font-size: var(--space-4x); + font-weight: var(--font-weight-medium); + line-height: var(--space-6x); + color: var(--gray-950); + margin-bottom: var(--space-1x); + text-align: center; +} + +.token-card__square-content p { + margin-bottom: 0; + font-size: var(--space-3x); + line-height: var(--space-5x); + color: var(--gray-500); + text-align: center; +} diff --git a/src/components/CCIP/Cards/TokenCard.tsx b/src/components/CCIP/Cards/TokenCard.tsx index 653908ec260..51372209112 100644 --- a/src/components/CCIP/Cards/TokenCard.tsx +++ b/src/components/CCIP/Cards/TokenCard.tsx @@ -1,5 +1,6 @@ import { memo } from "react" import { fallbackTokenIconUrl } from "~/features/utils/index.ts" +import Card from "./Card.tsx" import "./TokenCard.css" interface TokenCardProps { @@ -7,42 +8,71 @@ interface TokenCardProps { logo?: string link?: string onClick?: () => void + totalNetworks?: number + variant?: "default" | "square" } -const TokenCard = memo(function TokenCard({ id, logo, link, onClick }: TokenCardProps) { - if (link) { - return ( - -
- {/* We cannot use the normal Image/onError syntax as a fallback as the element is server rendered - and the onerror does not seem to work correctly. Using Picture will also not work. */} - - {`${id} - +const TokenCard = memo(function TokenCard({ + id, + logo, + link, + onClick, + totalNetworks, + variant = "default", +}: TokenCardProps) { + const logoElement = ( + + {`${id} + + ) + + const subtitle = + totalNetworks !== undefined ? `${totalNetworks} ${totalNetworks === 1 ? "network" : "networks"}` : undefined + + if (variant === "square") { + const content = ( + <> +
{logoElement}
+

{id}

+ {subtitle &&

{subtitle}

}
-
+ ) - } - if (onClick) { - return ( - - ) + if (link) { + return ( + +
{content}
+
+ ) + } + + if (onClick) { + return ( + + ) + } + + return
{content}
} return ( -
- - - -

{id}

-
+ ) }) diff --git a/src/components/CCIP/Chain/Chain.astro b/src/components/CCIP/Chain/Chain.astro index fd726a209a2..1dc9bf70e46 100644 --- a/src/components/CCIP/Chain/Chain.astro +++ b/src/components/CCIP/Chain/Chain.astro @@ -6,6 +6,7 @@ import { Network, getAllNetworkLanes, getAllNetworks, + getAllUniqueVerifiers, getSearchLanes, getTokensOfChain, Version, @@ -17,6 +18,7 @@ import ChainTokenGrid from "./ChainTokenGrid" import { generateChainStructuredData } from "~/utils/ccipStructuredData" import StructuredData from "~/components/StructuredData.astro" import { DOCS_BASE_URL } from "~/utils/structuredData" +import AddButton from "~/components/CCIP/AddButton/AddButton.astro" interface Props { environment: Environment @@ -48,6 +50,11 @@ const lanes = await getAllNetworkLanes({ const searchLanes = getSearchLanes({ environment }) +const allVerifiers = getAllUniqueVerifiers({ + environment, + version: Version.V1_2_0, +}) + // Generate dynamic metadata for this specific chain const environmentText = environment === Environment.Mainnet ? "Mainnet" : "Testnet" const logoPath = network.logo || "" @@ -106,6 +113,7 @@ const chainStructuredData = generateChainStructuredData( network={network} environment={environment} lanes={searchLanes} + verifiers={allVerifiers} client:load />
@@ -128,14 +136,11 @@ const chainStructuredData = generateChainStructuredData(

Tokens ({allTokens.length})

{ network.chainType !== "solana" && network.chainType !== "aptos" && ( - - Add - Add my token - + ) }
@@ -180,6 +185,14 @@ const chainStructuredData = generateChainStructuredData( grid-template-columns: 1fr; gap: var(--space-2x); } + :global(.chain-add-button) { + border-color: var(--blue-600) !important; + color: var(--blue-600) !important; + } + + :global(.chain-add-button:hover) { + background-color: var(--blue-100) !important; + } @media (min-width: 50em) { .layout { @@ -193,8 +206,12 @@ const chainStructuredData = generateChainStructuredData( display: grid; --doc-padding: var(--space-10x); padding: var(--doc-padding) var(--space-8x); - grid-template-columns: 1fr 1fr; - gap: var(--space-24x); + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: var(--space-8x); + } + + .layout > div { + min-width: 0; } .networks__grid { diff --git a/src/components/CCIP/Chain/ChainTokenGrid.css b/src/components/CCIP/Chain/ChainTokenGrid.css index 9f61a1e8472..aa0bcdbcc86 100644 --- a/src/components/CCIP/Chain/ChainTokenGrid.css +++ b/src/components/CCIP/Chain/ChainTokenGrid.css @@ -6,7 +6,6 @@ @media (min-width: 992px) { .tokens__grid { - min-height: 420px; grid-template-columns: 1fr 1fr 1fr 1fr; gap: var(--space-4x); } diff --git a/src/components/CCIP/Chain/ChainTokenGrid.tsx b/src/components/CCIP/Chain/ChainTokenGrid.tsx index ad2502efcff..c74a8fa0211 100644 --- a/src/components/CCIP/Chain/ChainTokenGrid.tsx +++ b/src/components/CCIP/Chain/ChainTokenGrid.tsx @@ -1,7 +1,7 @@ -import { Environment, Version, Network } from "~/config/data/ccip/types.ts" +import { Environment, Version, Network, PoolType } from "~/config/data/ccip/types.ts" import { getAllTokenLanes, getTokenData } from "~/config/data/ccip/data.ts" import TokenCard from "../Cards/TokenCard.tsx" -import { drawerContentStore } from "../Drawer/drawerStore.ts" +import { drawerContentStore, DrawerWidth, drawerWidthStore } from "../Drawer/drawerStore.ts" import TokenDrawer from "../Drawer/TokenDrawer.tsx" import { directoryToSupportedChain, getChainIcon, getChainTypeAndFamily, getTitle } from "~/features/utils/index.ts" import { useState } from "react" @@ -36,6 +36,7 @@ function ChainTokenGrid({ tokens, network, environment }: ChainTokenGridProps) { id={token.id} logo={token.logo} key={token.id} + variant="square" onClick={() => { const selectedNetwork = Object.keys(data) .map((key) => { @@ -53,8 +54,9 @@ function ChainTokenGrid({ tokens, network, environment }: ChainTokenGridProps) { tokenSymbol: data[key].symbol, tokenDecimals: data[key].decimals, tokenAddress: data[key].tokenAddress, - tokenPoolType: data[key].poolType, - tokenPoolAddress: data[key].poolAddress || "", + tokenPoolType: (data[key].pool?.type || data[key].poolType) as PoolType, + tokenPoolAddress: data[key].pool?.address || data[key].poolAddress || "", + tokenPoolVersion: data[key].pool?.version || "", explorer: network.explorer, chainType, } @@ -67,6 +69,7 @@ function ChainTokenGrid({ tokens, network, environment }: ChainTokenGridProps) { version: Version.V1_2_0, token: token.id, })[selectedNetwork.key] + drawerWidthStore.set(DrawerWidth.Wide) drawerContentStore.set(() => ( } -function ChainHero({ chains, tokens, network, token, environment, lanes }: ChainHeroProps) { +function ChainHero({ + chains, + tokens, + network, + token, + environment, + lanes, + verifiers = [], + breadcrumbItems, +}: ChainHeroProps) { // Get chain-specific tooltip configuration const chainTooltipConfig = network?.chain ? getChainTooltip(network.chain) : null @@ -99,55 +119,58 @@ function ChainHero({ chains, tokens, network, token, environment, lanes }: Chain
- +
-
- { - currentTarget.onerror = null // prevents looping - currentTarget.src = fallbackTokenIconUrl - }} - /> -

- {network?.name || token?.id} - {token?.name} + {(network || token) && ( +
+ { + currentTarget.onerror = null // prevents looping + currentTarget.src = fallbackTokenIconUrl + }} + /> +

+ {network?.name || token?.name} + {token?.id} - {chainTooltipConfig && ( - - )} -

-
+ {chainTooltipConfig && ( + + )} +

+
+ )} {network && (
diff --git a/src/components/CCIP/ChainHero/LaneDetailsHero.css b/src/components/CCIP/ChainHero/LaneDetailsHero.css index 706ee384876..2046fc35f59 100644 --- a/src/components/CCIP/ChainHero/LaneDetailsHero.css +++ b/src/components/CCIP/ChainHero/LaneDetailsHero.css @@ -1,5 +1,5 @@ .lane-details-hero { - background-color: var(--gray-100); + background: var(--Page-Background-Alt); padding: var(--space-6x); border-bottom: 1px solid var(--gray-200); } @@ -42,9 +42,16 @@ } .lane-details-hero__details { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--space-6x); + display: flex; + flex-direction: column; + gap: var(--space-10x); +} + +.lane-details-hero__details__item { + display: flex; + flex-direction: column; + gap: var(--space-4x); + min-width: var(--space-45x); } .lane-details-hero__details__label { @@ -58,11 +65,12 @@ @media screen and (min-width: 768px) { .lane-details-hero { - padding: var(--space-6x) var(--space-10x) var(--space-10x); + padding: var(--space-6x) var(--space-8x) var(--space-10x); } - .lane-details-hero__details { - grid-template-columns: 1fr 2fr; + /* Drawer-specific styles to match drawer heading width */ + .lane-details-hero--drawer { + padding: var(--space-6x) var(--space-10x) var(--space-10x); } .lane-details-hero__networks { @@ -74,4 +82,9 @@ transform: rotate(0deg); margin-left: 0; } + + .lane-details-hero__details { + flex-direction: row; + flex-wrap: wrap; + } } diff --git a/src/components/CCIP/ChainHero/LaneDetailsHero.tsx b/src/components/CCIP/ChainHero/LaneDetailsHero.tsx index 8c96ef2fde5..f13e96dd296 100644 --- a/src/components/CCIP/ChainHero/LaneDetailsHero.tsx +++ b/src/components/CCIP/ChainHero/LaneDetailsHero.tsx @@ -19,10 +19,11 @@ interface LaneDetailsHeroProps { } onRamp: string offRamp: string + sourceAddress: string destinationAddress: string - enforceOutOfOrder?: boolean explorer: ExplorerInfo inOutbound: LaneFilter + inDrawer?: boolean } // Arrow component to avoid duplication @@ -69,13 +70,13 @@ const DetailItem = ({ clipboardType?: string tooltip?: React.ReactNode }) => ( - <> +
{label} {tooltip}
{children}
- +
) function LaneDetailsHero({ @@ -83,20 +84,14 @@ function LaneDetailsHero({ destinationNetwork, onRamp, offRamp, + sourceAddress, destinationAddress, - enforceOutOfOrder, explorer, inOutbound, + inDrawer = false, }: LaneDetailsHeroProps) { - // Map boolean values to display strings - const getOutOfOrderText = (value?: boolean) => { - if (value === true) return "Required" - if (value === false) return "Optional" - return "N/A" - } - return ( -
+
{/* Display networks with direction based on lane type */}
{inOutbound === LaneFilter.Inbound ? ( @@ -115,16 +110,7 @@ function LaneDetailsHero({
- {/* Display address information based on lane type */} - {inOutbound === LaneFilter.Inbound ? ( - - - - ) : ( + {onRamp && ( )} - - {destinationAddress ? : "n/a"}{" "} - + {offRamp && ( + + + + )} + + {sourceAddress && ( + } + > + + + )} - {inOutbound === LaneFilter.Outbound && ( + {destinationAddress && ( - } + label="Destination chain selector" + clipboardType="destination-chain-selector" + tooltip={} > - {getOutOfOrderText(enforceOutOfOrder)} + )}
diff --git a/src/components/CCIP/ChainHero/TokenDetailsHero.tsx b/src/components/CCIP/ChainHero/TokenDetailsHero.tsx index 94ce250d01f..382b2f849bb 100644 --- a/src/components/CCIP/ChainHero/TokenDetailsHero.tsx +++ b/src/components/CCIP/ChainHero/TokenDetailsHero.tsx @@ -4,6 +4,7 @@ import { PoolType } from "~/config/data/ccip/types.ts" import { tokenPoolDisplay } from "~/config/data/ccip/utils.ts" import "./ChainHero.css" import { ExplorerInfo, ChainType } from "~/config/types.ts" +import { getNetworkIconUrl } from "~/config/data/ccip/data.ts" interface TokenDetailsHeroProps { network: { @@ -22,15 +23,16 @@ interface TokenDetailsHeroProps { poolType: PoolType poolAddress: string } + inDrawer?: boolean } -function TokenDetailsHero({ network, token }: TokenDetailsHeroProps) { +function TokenDetailsHero({ network, token, inDrawer = false }: TokenDetailsHeroProps) { return ( -
+
- + (null) const drawerContentRef = useRef(null) const $drawerContent = useStore(drawerContentStore) as (() => ReactNode) | ReactNode | null + const $drawerWidth = useStore(drawerWidthStore) const [isOpened, setIsOpened] = useState(false) // exit when press esc @@ -47,6 +48,7 @@ function Drawer() { // Use transitionend event instead of setTimeout for better performance const handleTransitionEnd = () => { drawerContentStore.set(null) + drawerWidthStore.set(DrawerWidth.Default) drawerRef.current?.removeEventListener("transitionend", handleTransitionEnd) } @@ -62,7 +64,12 @@ function Drawer() { ref={drawerRef} onClick={handleClickOutside} > -
+
@@ -285,6 +298,36 @@ function Search({ chains, tokens, small, environment, lanes }: SearchProps) { )} + + {verifiersResults.length > 0 && ( + <> + Verifiers + + + )}
)}
diff --git a/src/components/CCIP/SeeMore/SeeMore.css b/src/components/CCIP/SeeMore/SeeMore.css index 8c4c9209c51..102d96cf4b1 100644 --- a/src/components/CCIP/SeeMore/SeeMore.css +++ b/src/components/CCIP/SeeMore/SeeMore.css @@ -7,6 +7,6 @@ } .seeMore__container { display: flex; - justify-content: center; + justify-content: flex-start; align-items: center; } diff --git a/src/components/CCIP/SeeMore/SeeMore.tsx b/src/components/CCIP/SeeMore/SeeMore.tsx index 3e0b7c17278..cab963897c7 100644 --- a/src/components/CCIP/SeeMore/SeeMore.tsx +++ b/src/components/CCIP/SeeMore/SeeMore.tsx @@ -1,14 +1,22 @@ import "./SeeMore.css" interface SeeMoreProps { onClick?: () => void + label?: string + href?: string } -function SeeMore({ onClick }: SeeMoreProps) { +function SeeMore({ onClick, label = "See more", href }: SeeMoreProps) { return (
- + {href ? ( + + {label} + + ) : ( + + )}
) } diff --git a/src/components/CCIP/Tables/ChainTable.tsx b/src/components/CCIP/Tables/ChainTable.tsx index d487faf20ee..7ab6c7c559e 100644 --- a/src/components/CCIP/Tables/ChainTable.tsx +++ b/src/components/CCIP/Tables/ChainTable.tsx @@ -4,7 +4,7 @@ import Tabs from "./Tabs.tsx" import TableSearchInput from "./TableSearchInput.tsx" import { useEffect, useState } from "react" import { getExplorerAddressUrl } from "~/features/utils/index.ts" -import { drawerContentStore } from "../Drawer/drawerStore.ts" +import { drawerContentStore, drawerWidthStore, DrawerWidth } from "../Drawer/drawerStore.ts" import LaneDrawer from "../Drawer/LaneDrawer.tsx" import { Environment, Version, LaneFilter } from "~/config/data/ccip/types.ts" import { getLane } from "~/config/data/ccip/data.ts" @@ -68,9 +68,6 @@ function ChainTable({ lanes, explorer, sourceNetwork, environment }: TableProps) onChange={(key) => setInOutbound(key as LaneFilter)} />
-
- -
View lane status +
+ +
@@ -130,6 +130,7 @@ function ChainTable({ lanes, explorer, sourceNetwork, environment }: TableProps) version: Version.V1_2_0, }) + drawerWidthStore.set(DrawerWidth.Wide) drawerContentStore.set(() => ( .ccip-table { + font-size: 11px; + } + + .ccip-table__wrapper > .ccip-table thead th { + padding: var(--space-2x) var(--space-1x); + font-size: 10px; + line-height: 1.2; + white-space: nowrap; + } + + .ccip-table__wrapper > .ccip-table tbody td { + padding: var(--space-2x) var(--space-1x); + font-size: 10px; + vertical-align: middle; + } + + .ccip-table__wrapper > .ccip-table tbody td > div { + display: flex; + align-items: center; + gap: var(--space-1x); + } + + .ccip-table__wrapper > .ccip-table .ccip-table__logo { + width: 16px !important; + height: 16px !important; + margin-right: 0 !important; + flex-shrink: 0; + } + + /* Make verifier name column slightly wider */ + .ccip-table__wrapper > .ccip-table thead th:nth-child(1) { + min-width: 90px; + } + + /* Compress address column */ + .ccip-table__wrapper > .ccip-table thead th:nth-child(2) { + min-width: 70px; + } + + /* Make type and threshold columns narrower */ + .ccip-table__wrapper > .ccip-table thead th:nth-child(3), + .ccip-table__wrapper > .ccip-table thead th:nth-child(4) { + min-width: 60px; + } +} diff --git a/src/components/CCIP/Tables/TokenChainsTable.tsx b/src/components/CCIP/Tables/TokenChainsTable.tsx index ca40a294da8..7ddfe2e0a38 100644 --- a/src/components/CCIP/Tables/TokenChainsTable.tsx +++ b/src/components/CCIP/Tables/TokenChainsTable.tsx @@ -1,6 +1,6 @@ import Address from "~/components/AddressReact.tsx" import "./Table.css" -import { drawerContentStore } from "../Drawer/drawerStore.ts" +import { drawerContentStore, DrawerWidth, drawerWidthStore } from "../Drawer/drawerStore.ts" import { Environment, SupportedTokenConfig, tokenPoolDisplay, PoolType } from "~/config/data/ccip/index.ts" import { areAllLanesPaused } from "~/config/data/ccip/utils.ts" import { ChainType, ExplorerInfo } from "~/config/types.ts" @@ -8,6 +8,8 @@ import TableSearchInput from "./TableSearchInput.tsx" import { useState } from "react" import { getExplorerAddressUrl, fallbackTokenIconUrl } from "~/features/utils/index.ts" import TokenDrawer from "../Drawer/TokenDrawer.tsx" +import { Tooltip } from "~/features/common/Tooltip/Tooltip.tsx" +import { useTokenFinality } from "~/hooks/useTokenFinality.ts" interface TableProps { networks: { @@ -23,6 +25,7 @@ interface TableProps { tokenAddress: string tokenPoolType: PoolType tokenPoolAddress: string + tokenPoolVersion: string explorer: ExplorerInfo }[] token: { @@ -41,6 +44,10 @@ interface TableProps { function TokenChainsTable({ networks, token, lanes, environment }: TableProps) { const [search, setSearch] = useState("") + + // Fetch finality data using custom hook + const { finalityData, isLoading: loading } = useTokenFinality(token.id, environment, "internal_id") + return ( <>
@@ -60,6 +67,9 @@ function TokenChainsTable({ networks, token, lanes, environment }: TableProps) { Token address Token pool type Token pool address + Pool version + Custom finality + Min Blocks required @@ -76,6 +86,7 @@ function TokenChainsTable({ networks, token, lanes, environment }: TableProps) { type="button" className={`ccip-table__network-name ${allLanesPaused ? "ccip-table__network-name--paused" : ""}`} onClick={() => { + drawerWidthStore.set(DrawerWidth.Wide) drawerContentStore.set(() => ( {tokenPoolDisplay(network.tokenPoolType)} @@ -136,9 +147,44 @@ function TokenChainsTable({ networks, token, lanes, environment }: TableProps) { network.chainType )(network.tokenPoolAddress)} address={network.tokenPoolAddress} - endLength={6} + endLength={4} /> + {network.tokenPoolVersion} + + {loading ? ( + "-" + ) : finalityData[network.key] ? ( + finalityData[network.key].hasCustomFinality === null ? ( + + ) : finalityData[network.key].hasCustomFinality ? ( + "Yes" + ) : ( + "No" + ) + ) : ( + + )} + + + {loading + ? "-" + : finalityData[network.key] + ? finalityData[network.key].minBlockConfirmation === null + ? "-" + : finalityData[network.key].minBlockConfirmation + : "-"} + ) })} diff --git a/src/components/CCIP/Tables/VerifiersTable.tsx b/src/components/CCIP/Tables/VerifiersTable.tsx new file mode 100644 index 00000000000..dc79bf8753e --- /dev/null +++ b/src/components/CCIP/Tables/VerifiersTable.tsx @@ -0,0 +1,124 @@ +import Address from "~/components/AddressReact.tsx" +import "./Table.css" +import { Environment, Verifier, getVerifierTypeDisplay } from "~/config/data/ccip/index.ts" +import TableSearchInput from "./TableSearchInput.tsx" +import { useState } from "react" +import { + getExplorerAddressUrl, + fallbackVerifierIconUrl, + getChainIcon, + getTitle, + directoryToSupportedChain, + getExplorer, + getChainTypeAndFamily, +} from "~/features/utils/index.ts" + +interface VerifiersTableProps { + verifiers: Verifier[] +} + +function VerifiersTable({ verifiers }: VerifiersTableProps) { + const [search, setSearch] = useState("") + + // Transform verifiers data to include network information + const verifiersWithNetworkInfo = verifiers.map((verifier) => { + const supportedChain = directoryToSupportedChain(verifier.network) + const networkName = getTitle(supportedChain) || verifier.network + const networkLogo = getChainIcon(supportedChain) || "" + const explorer = getExplorer(supportedChain) + const { chainType } = getChainTypeAndFamily(supportedChain) + + return { + ...verifier, + networkName, + networkLogo, + supportedChain, + explorer, + chainType, + } + }) + + const filteredVerifiers = verifiersWithNetworkInfo.filter( + (verifier) => + verifier.name.toLowerCase().includes(search.toLowerCase()) || + verifier.networkName.toLowerCase().includes(search.toLowerCase()) || + verifier.address.toLowerCase().includes(search.toLowerCase()) || + getVerifierTypeDisplay(verifier.type).toLowerCase().includes(search.toLowerCase()) + ) + + return ( + <> +
+
+ Verifiers ({verifiers.length}) +
+ +
+
+ + + + + + + + + + + {filteredVerifiers.map((verifier, index) => ( + + + + + + + ))} + +
VerifierNetworkVerifier addressVerifier type
+
+ + {`${verifier.name} { + currentTarget.onerror = null // prevents looping + currentTarget.src = fallbackVerifierIconUrl + }} + /> + + {verifier.name} +
+
+
+ + {`${verifier.networkName} { + currentTarget.onerror = null // prevents looping + currentTarget.src = fallbackVerifierIconUrl + }} + /> + + {verifier.networkName} +
+
+
+
{getVerifierTypeDisplay(verifier.type)}
+
{filteredVerifiers.length === 0 && <>No verifiers found}
+
+ + ) +} + +export default VerifiersTable diff --git a/src/components/CCIP/Token/Token.astro b/src/components/CCIP/Token/Token.astro index 58071e03c39..8718769da7f 100644 --- a/src/components/CCIP/Token/Token.astro +++ b/src/components/CCIP/Token/Token.astro @@ -5,6 +5,7 @@ import { getAllNetworks, getAllSupportedTokens, getAllTokenLanes, + getAllUniqueVerifiers, getChainsOfToken, getSearchLanes, getTokenData, @@ -76,6 +77,11 @@ const tokenLanes = getAllTokenLanes({ const searchLanes = getSearchLanes({ environment }) +const allVerifiers = getAllUniqueVerifiers({ + environment, + version: Version.V1_2_0, +}) + // Generate dynamic metadata for this specific token const environmentText = environment === Environment.Mainnet ? "Mainnet" : "Testnet" const tokenMetadata = { @@ -117,6 +123,7 @@ const tokenStructuredData = generateTokenStructuredData(token, environment, chai tokens={allTokens} client:load lanes={searchLanes} + verifiers={allVerifiers} token={{ id: token, name: data[firstSupportedChain]?.name || "", @@ -150,8 +157,9 @@ const tokenStructuredData = generateTokenStructuredData(token, environment, chai tokenSymbol: data[key]?.symbol ?? "", tokenDecimals: data[key]?.decimals ?? 0, tokenAddress: data[key]?.tokenAddress ?? "", - tokenPoolType: data[key]?.poolType, - tokenPoolAddress: data[key]?.poolAddress ?? "", + tokenPoolType: data[key]?.pool?.type, + tokenPoolAddress: data[key]?.pool?.address ?? "", + tokenPoolVersion: data[key]?.pool?.version ?? "", explorer: explorer, chainType: chainType, } @@ -171,9 +179,8 @@ const tokenStructuredData = generateTokenStructuredData(token, environment, chai diff --git a/src/components/CCIP/TokenGrid/TokenGrid.tsx b/src/components/CCIP/TokenGrid/TokenGrid.tsx index 9c303e264a5..7938ef0406a 100644 --- a/src/components/CCIP/TokenGrid/TokenGrid.tsx +++ b/src/components/CCIP/TokenGrid/TokenGrid.tsx @@ -1,35 +1,47 @@ -import { useState } from "react" -import SeeMore from "../SeeMore/SeeMore.tsx" -import "./TokenGrid.css" -import TokenCard from "../Cards/TokenCard.tsx" +import { fallbackTokenIconUrl } from "~/features/utils/index.ts" +import Card from "../Cards/Card.tsx" +import Grid from "../Landing/Grid.tsx" interface TokenGridProps { tokens: { id: string logo: string + totalNetworks?: number }[] environment: string } -const BEFORE_SEE_MORE = 6 * 4 // Number of networks to show before the "See more" button, 6 rows x 4 items +const BEFORE_SEE_MORE = 2 * 4 // Number of tokens to show before the "See more" button, 2 rows x 4 items -function NetworkGrid({ tokens, environment }: TokenGridProps) { - const [seeMore, setSeeMore] = useState(tokens.length <= BEFORE_SEE_MORE) +function TokenGrid({ tokens, environment }: TokenGridProps) { return ( - <> -
- {tokens.slice(0, seeMore ? tokens.length : BEFORE_SEE_MORE).map((token) => ( - { + const subtitle = + token.totalNetworks !== undefined + ? `${token.totalNetworks} ${token.totalNetworks === 1 ? "network" : "networks"}` + : undefined + const logoElement = ( + + {`${token.id} + + ) + return ( + - ))} -
- {!seeMore && setSeeMore(!seeMore)} />} - + ) + }} + /> ) } -export default NetworkGrid +export default TokenGrid diff --git a/src/components/CCIP/Tooltip/RateTooltip.tsx b/src/components/CCIP/Tooltip/RateTooltip.tsx index 836644ab53d..78b6c948d9c 100644 --- a/src/components/CCIP/Tooltip/RateTooltip.tsx +++ b/src/components/CCIP/Tooltip/RateTooltip.tsx @@ -7,14 +7,33 @@ function RateTooltip({ symbol, decimals, position, + showUnavailableText = false, }: { destinationLane: SupportedTokenConfig inOutbound: LaneFilter symbol: string decimals: number position?: "top" | "bottom" | "left" | "right" + showUnavailableText?: boolean }) { if (!destinationLane.rateLimiterConfig?.[inOutbound === LaneFilter.Inbound ? "in" : "out"]?.isEnabled) { + if (showUnavailableText) { + return ( + + ) + } return N/A } const { rateSecond, maxThroughput } = displayRate( diff --git a/src/components/CCIP/VerifierGrid/LazyVerifierGrid.tsx b/src/components/CCIP/VerifierGrid/LazyVerifierGrid.tsx new file mode 100644 index 00000000000..7dd31d36e19 --- /dev/null +++ b/src/components/CCIP/VerifierGrid/LazyVerifierGrid.tsx @@ -0,0 +1,46 @@ +import { lazy, Suspense } from "react" +import type { Environment } from "~/config/data/ccip/types.ts" + +const VerifierGrid = lazy(() => import("./VerifierGrid.tsx")) + +interface LazyVerifierGridProps { + verifiers: Array<{ + id: string + name: string + logo: string + totalNetworks: number + }> + environment: Environment +} + +export default function LazyVerifierGrid({ verifiers, environment }: LazyVerifierGridProps) { + return ( + + {Array.from({ length: 8 }, (_, i) => ( +
+ ))} +
+ } + > + +
+ ) +} diff --git a/src/components/CCIP/VerifierGrid/VerifierGrid.tsx b/src/components/CCIP/VerifierGrid/VerifierGrid.tsx new file mode 100644 index 00000000000..133dbb95a97 --- /dev/null +++ b/src/components/CCIP/VerifierGrid/VerifierGrid.tsx @@ -0,0 +1,46 @@ +import { fallbackVerifierIconUrl } from "~/features/utils/index.ts" +import Card from "../Cards/Card.tsx" +import Grid from "../Landing/Grid.tsx" + +interface VerifierGridProps { + verifiers: { + id: string + name: string + logo: string + totalNetworks: number + }[] + environment: string +} + +const BEFORE_SEE_MORE = 2 * 4 // Number of verifiers to show before the "See more" button, 2 rows x 4 items + +function VerifierGrid({ verifiers, environment }: VerifierGridProps) { + return ( + { + const subtitle = `${verifier.totalNetworks} ${verifier.totalNetworks === 1 ? "network" : "networks"}` + const logoElement = ( + + {`${verifier.name} + + ) + return ( + + ) + }} + /> + ) +} + +export default VerifierGrid diff --git a/src/components/CCIP/Verifiers/Verifiers.astro b/src/components/CCIP/Verifiers/Verifiers.astro new file mode 100644 index 00000000000..dd3dc730de4 --- /dev/null +++ b/src/components/CCIP/Verifiers/Verifiers.astro @@ -0,0 +1,118 @@ +--- +import CcipDirectoryLayout from "~/layouts/CcipDirectoryLayout.astro" +import { getEntry, render } from "astro:content" +import { + getAllNetworks, + getAllVerifiers, + getSearchLanes, + Version, + Environment, + getAllSupportedTokens, + getChainsOfToken, +} from "~/config/data/ccip" +import Table from "~/components/CCIP/Tables/VerifiersTable" +import { getAllUniqueVerifiers } from "~/config/data/ccip/data.ts" +import { DOCS_BASE_URL } from "~/utils/structuredData" +import ChainHero from "~/components/CCIP/ChainHero/ChainHero" +import { getTokenIconUrl } from "~/features/utils" +import "./Verifiers.css" + +interface Props { + environment: Environment +} + +const { environment } = Astro.props as Props + +const entry = await getEntry("ccip", "index") +if (!entry) { + throw new Error('Could not find "ccip/index" doc. Check src/content/ccip/index.mdx!') +} + +const { headings } = await render(entry) + +const networks = getAllNetworks({ filter: environment }) + +const allVerifiers = getAllVerifiers({ + environment, + version: Version.V1_2_0, +}) + +const uniqueVerifiers = getAllUniqueVerifiers({ + environment, + version: Version.V1_2_0, +}) + +const searchLanes = getSearchLanes({ environment }) + +const supportedTokens = getAllSupportedTokens({ + environment, + version: Version.V1_2_0, +}) +const tokens = Object.keys(supportedTokens).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" })) +const allTokens = tokens.map((token) => { + const logo = getTokenIconUrl(token) || "" + return { + id: token, + logo, + totalNetworks: getChainsOfToken({ token, filter: environment }).length, + } +}) + +// Generate dynamic metadata for verifiers page +const environmentText = environment === Environment.Mainnet ? "Mainnet" : "Testnet" +const verifiersMetadata = { + title: `CCIP Verifiers - ${environmentText} Networks`, + description: `View all CCIP verifiers across ${environmentText} networks. Explore ${allVerifiers.length} verifiers, their addresses, types, and supported networks for cross-chain verification.`, + image: "/assets/product-logos/ccip-logo.svg", + excerpt: `CCIP verifiers ${environmentText.toLowerCase()} networks addresses types committee api cross-chain verification blockchain interoperability`, +} + +// Generate structured data for verifiers page +const currentPath = new URL(Astro.request.url).pathname +const canonicalForJsonLd = `${DOCS_BASE_URL}${currentPath}` +--- + + + + +
+
+ + + + diff --git a/src/components/CCIP/Verifiers/Verifiers.css b/src/components/CCIP/Verifiers/Verifiers.css new file mode 100644 index 00000000000..eda464e886c --- /dev/null +++ b/src/components/CCIP/Verifiers/Verifiers.css @@ -0,0 +1,43 @@ +.layout { + margin: 0 auto; + padding: var(--space-6x); +} + +.layout h2 { + color: var(--gray-900); + font-size: 22px; + line-height: var(--space-10x); + padding-bottom: var(--space-4x); + border-bottom: 1px solid var(--gray-200); + margin-bottom: var(--space-6x); +} + +.layout h2 span { + color: var(--gray-400); + font-weight: 600; + letter-spacing: 0.5px; +} + +.networks__grid { + display: grid; + grid-template-columns: 1fr; + gap: var(--space-8x); +} + +.tokens__grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-8x); +} + +@media (min-width: 50em) { + .layout { + max-width: 1500px; + } +} + +@media (min-width: 992px) { + .layout { + padding: var(--space-10x) var(--space-8x); + } +} diff --git a/src/components/Cards/Card.astro b/src/components/Cards/Card.astro new file mode 100644 index 00000000000..c1331668d75 --- /dev/null +++ b/src/components/Cards/Card.astro @@ -0,0 +1,17 @@ +--- +import CardLink from "./CardLink.astro" +import styles from "./cards.module.css" +import { ICard } from "./types" + +type Props = ICard + +const { title, description, links } = Astro.props +--- + +
+

{title}

+

{description}

+
+ {links && links.map((l) => )} +
+
diff --git a/src/components/Cards/CardLink.astro b/src/components/Cards/CardLink.astro new file mode 100644 index 00000000000..032a29adc02 --- /dev/null +++ b/src/components/Cards/CardLink.astro @@ -0,0 +1,27 @@ +--- +import styles from "./cards.module.css" +import { ILink } from "./types" + +import tokenIcon from "../../assets/icons/token-icon.svg" +import remixIcon from "../../assets/icons/remix-logo.svg" + +interface Props { + link: ILink +} + +const { link } = Astro.props + +const iconMap = { + token: tokenIcon, + remix: remixIcon, +} + +const iconSrc = iconMap[link.icon] +--- + + + + + {link.label} + arrow right + diff --git a/src/components/Cards/CardsWrapper.astro b/src/components/Cards/CardsWrapper.astro new file mode 100644 index 00000000000..cb91045a25d --- /dev/null +++ b/src/components/Cards/CardsWrapper.astro @@ -0,0 +1,15 @@ +--- +import Card from "./Card.astro" +import styles from "./cards.module.css" +import { ICard } from "./types.ts" + +interface Props { + links: ICard[] +} + +const { links } = Astro.props +--- + +
+ {links.map((link) => )} +
diff --git a/src/components/Cards/cards.module.css b/src/components/Cards/cards.module.css new file mode 100644 index 00000000000..db4e076ab55 --- /dev/null +++ b/src/components/Cards/cards.module.css @@ -0,0 +1,66 @@ +.cardsWrapper { + display: grid; + grid-template-columns: repeat(3, 1fr); + border-left: 1px solid var(--border); + border-top: 1px solid var(--border); +} + +.cardsWrapper h6 { + font-size: 18px; + margin-bottom: var(--space-4x); +} + +:where(.cardsWrapper p) { + font-size: 14px; + line-height: 24px; /* 171.429% */ +} + +.card { + padding: var(--space-5x) var(--space-6x); + background: #fff; + border-right: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} + +.card:hover { + background: var(--gray-100); +} + +.links { + display: flex; + flex-direction: column; + margin-top: var(--space-6x); + gap: var(--space-4x); +} + +.link { + color: var(--Color-Primary, #0e1119); + display: flex; + gap: var(--space-2x); + align-items: center; + cursor: default; +} + +.link:hover span { + opacity: 0.7; +} + +.cardTitle { + font-weight: 525; + margin-bottom: var(--space-4x); + font-size: 18px; + color: var(--foreground); +} + +@media screen and (max-width: 768px) { + .cardsWrapper { + grid-template-columns: repeat(2, 1fr) !important; + } +} + +@media screen and (max-width: 600px) { + .cardsWrapper { + grid-template-columns: repeat(1, 1fr) !important; + margin-top: 0; + } +} diff --git a/src/components/Cards/types.ts b/src/components/Cards/types.ts new file mode 100644 index 00000000000..20007518bc0 --- /dev/null +++ b/src/components/Cards/types.ts @@ -0,0 +1,12 @@ +export type IconType = "token" | "remix" + +export interface ILink { + icon: IconType + href: string + label: string +} +export interface ICard { + title: string + description: string + links?: ILink[] +} diff --git a/src/components/ChainSelector/ChainSelector.tsx b/src/components/ChainSelector/ChainSelector.tsx index 2af9c5d5337..44006774200 100644 --- a/src/components/ChainSelector/ChainSelector.tsx +++ b/src/components/ChainSelector/ChainSelector.tsx @@ -40,6 +40,7 @@ export function ChainSelector({ if (dataFeedType === "rates") return chain.tags?.includes("rates") ?? false if (dataFeedType === "usGovernmentMacroeconomicData") return chain.tags?.includes("usGovernmentMacroeconomicData") ?? false + if (dataFeedType === "tokenizedEquity") return chain.tags?.includes("tokenizedEquity") ?? false return chain.tags?.includes("default") ?? false })() diff --git a/src/components/ChainSelector/ChainTypeSelector.module.css b/src/components/ChainSelector/ChainTypeSelector.module.css deleted file mode 100644 index 41a417e6c67..00000000000 --- a/src/components/ChainSelector/ChainTypeSelector.module.css +++ /dev/null @@ -1,147 +0,0 @@ -.selector { - display: flex; - align-items: center; - padding: var(--space-3x) var(--space-3x); - border-bottom: 1px solid var(--border-color, #e5e7eb); - background: var(--color-background-primary, #ffffff); - position: sticky; - top: 0; - z-index: 10; -} - -.dropdown { - position: relative; - width: auto; - min-width: 160px; -} - -.dropdownButton { - display: flex; - align-items: center; - gap: var(--space-2x); - width: 100%; - padding: var(--space-2x) var(--space-3x); - border: 1.5px solid var(--border-color, #e5e7eb); - border-radius: 6px; - background: var(--color-background-primary, #ffffff); - color: var(--color-text-primary); - font-size: 14px; - font-weight: 500; - cursor: pointer; - transition: all 0.2s ease; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.dropdownButton:hover { - background: var(--color-background-secondary, #f9fafb); - border-color: var(--color-text-tertiary, #9ca3af); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); - transform: translateY(-1px); -} - -.dropdownButton:active { - transform: translateY(0); - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.dropdownButton:focus-visible { - outline: 2px solid var(--color-blue-600, #2563eb); - outline-offset: 2px; - border-color: var(--color-blue-600, #2563eb); -} - -.arrow { - margin-left: auto; - color: var(--color-text-secondary, #6b7280); - transition: transform 0.2s ease; -} - -.arrowOpen { - transform: rotate(180deg); -} - -.dropdownMenu { - position: absolute; - top: calc(100% + 4px); - left: 0; - right: 0; - margin: 0; - padding: var(--space-2x) 0; - list-style: none; - background: var(--color-background-primary, #ffffff); - border: 1.5px solid var(--border-color, #e5e7eb); - border-radius: 6px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - z-index: 100; - max-height: 300px; - overflow-y: auto; -} - -.dropdownMenu li { - margin: 0; - padding: 0; -} - -.dropdownItem { - display: flex; - align-items: center; - gap: var(--space-2x); - width: 100%; - padding: var(--space-2x) var(--space-3x); - border: none; - background: transparent; - color: var(--color-text-primary); - font-size: 14px; - font-weight: 500; - text-align: left; - cursor: pointer; - transition: all 0.15s ease; -} - -.dropdownItem:hover { - background: var(--color-background-secondary, #f9fafb); - padding-left: calc(var(--space-3x) + 2px); -} - -.dropdownItem:focus-visible { - outline: 2px solid var(--chain-color); - outline-offset: -2px; - background: var(--color-background-secondary, #f9fafb); -} - -.dropdownItemActive { - color: var(--color-blue-600, #2563eb); - font-weight: 600; - background: var(--color-blue-50, #eff6ff); -} - -.icon { - width: 20px; - height: 20px; - flex-shrink: 0; - object-fit: contain; -} - -.name { - white-space: nowrap; - flex: 1; -} - -.checkmark { - margin-left: auto; - color: var(--color-blue-600, #2563eb); - flex-shrink: 0; -} - -@media (max-width: 640px) { - .dropdown { - width: 100%; - min-width: 0; - } -} - -@media (max-width: 480px) { - .dropdownMenu { - max-height: 240px; - } -} diff --git a/src/components/ChainSelector/ChainTypeSelector.tsx b/src/components/ChainSelector/ChainTypeSelector.tsx index 2ebf21e6cdd..e85b99e0996 100644 --- a/src/components/ChainSelector/ChainTypeSelector.tsx +++ b/src/components/ChainSelector/ChainTypeSelector.tsx @@ -1,12 +1,11 @@ /** @jsxImportSource react */ import { useStore } from "@nanostores/react" -import { useState, useRef, useEffect } from "react" import { selectedChainType, setChainType } from "~/stores/chainType.js" import { CHAIN_TYPE_CONFIGS, CCIP_SUPPORTED_CHAINS } from "~/config/chainTypes.js" import { CCIP_SIDEBAR_CONTENT } from "~/config/sidebar/ccip-dynamic.js" import { findEquivalentPageUrlWithFallback } from "~/utils/chainNavigation.js" import type { ChainType } from "~/config/types.js" -import styles from "./ChainTypeSelector.module.css" +import { SidebarDropdown, type DropdownItem } from "../SidebarDropdown/index.js" /** * Chain Type Dropdown Selector Component @@ -30,13 +29,9 @@ import styles from "./ChainTypeSelector.module.css" */ export function ChainTypeSelector() { const activeChain = useStore(selectedChainType) - const [isOpen, setIsOpen] = useState(false) - const dropdownRef = useRef(null) - const activeConfig = CHAIN_TYPE_CONFIGS[activeChain] - - const handleSelect = (chainType: ChainType) => { - setIsOpen(false) + const handleSelect = (chainId: string) => { + const chainType = chainId as ChainType setChainType(chainType) // Find target URL with intelligent fallback: exact match → parent → section root @@ -45,110 +40,25 @@ export function ChainTypeSelector() { window.location.href = `/${targetUrl}` } - const handleToggle = () => { - setIsOpen(!isOpen) - } - - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { - setIsOpen(false) - } + // Convert chain configs to dropdown items format + const chainItems: DropdownItem[] = CCIP_SUPPORTED_CHAINS.map((chainId) => { + const config = CHAIN_TYPE_CONFIGS[chainId] + return { + id: chainId, + label: config.displayName, + icon: config.icon, + description: config.description, } - - const handleEscape = (event: KeyboardEvent) => { - if (event.key === "Escape") { - setIsOpen(false) - } - } - - if (isOpen) { - document.addEventListener("mousedown", handleClickOutside) - document.addEventListener("keydown", handleEscape) - } - - return () => { - document.removeEventListener("mousedown", handleClickOutside) - document.removeEventListener("keydown", handleEscape) - } - }, [isOpen]) + }) return ( -
-
- - - {isOpen && ( -
    - {CCIP_SUPPORTED_CHAINS.map((chainId) => { - const config = CHAIN_TYPE_CONFIGS[chainId] - const isActive = activeChain === chainId - - return ( -
  • - -
  • - ) - })} -
- )} -
-
+ ) } diff --git a/src/components/ChangelogFilters/ChangelogFilters.tsx b/src/components/ChangelogFilters/ChangelogFilters.tsx new file mode 100644 index 00000000000..2e0647230ba --- /dev/null +++ b/src/components/ChangelogFilters/ChangelogFilters.tsx @@ -0,0 +1,35 @@ +import styles from "./styles.module.css" +import type { ChangelogItem } from "~/components/ChangelogSnippet/types.ts" +import { DesktopFilters } from "./DesktopFilters.tsx" +import { MobileFilters } from "./MobileFilters.tsx" +import { useState } from "react" +import { clsx } from "~/lib/clsx/clsx.ts" + +export interface ChangelogFiltersProps { + products: string[] + networks: string[] + types: string[] + items: ChangelogItem[] +} + +export const ChangelogFilters = ({ products, networks, types, items }: ChangelogFiltersProps) => { + const [searchExpanded, setSearchExpanded] = useState(false) + + return ( +
+
+ +
+
+ +
+
+ ) +} diff --git a/src/components/ChangelogFilters/DesktopFilters.tsx b/src/components/ChangelogFilters/DesktopFilters.tsx new file mode 100644 index 00000000000..c54ce85b814 --- /dev/null +++ b/src/components/ChangelogFilters/DesktopFilters.tsx @@ -0,0 +1,245 @@ +import { SvgSearch, SvgTaillessArrowDownSmall, SvgX } from "@chainlink/blocks" +import styles from "./styles.module.css" +import { useState, useEffect, useRef } from "react" +import { clsx } from "~/lib/clsx/clsx.ts" +import type { ChangelogItem } from "~/components/ChangelogSnippet/types.ts" +import { useChangelogFilters } from "./useChangelogFilters.ts" + +type FilterType = "product" | "network" | "type" | null + +interface SearchInputProps { + isExpanded: boolean + onClick: (value: boolean) => void + value: string + onChange: (value: string) => void +} + +const SearchInput = ({ isExpanded, onClick, value, onChange }: SearchInputProps) => { + return ( +
onClick(true)}> + + onChange(e.target.value)} + /> + {isExpanded && ( + { + e.stopPropagation() + onClick(false) + onChange("") + }} + style={{ + marginRight: "var(--space-4x)", + }} + /> + )} +
+ ) +} + +interface TriggerProps { + label: string + count: number + isActive: boolean + onClick: () => void + onClose: () => void + onClearAll: () => void +} + +const Trigger = ({ label, count, isActive, onClick, onClose, onClearAll }: TriggerProps) => { + return ( + + ) +} + +interface FilterPillProps { + label: string + isSelected: boolean + onClick: () => void +} + +const FilterPill = ({ label, isSelected, onClick }: FilterPillProps) => { + return ( + + ) +} + +interface DesktopFiltersProps { + products: string[] + networks: string[] + types: string[] + items: ChangelogItem[] +} + +export const DesktopFilters = ({ products, networks, types, items }: DesktopFiltersProps) => { + const [activeFilter, setActiveFilter] = useState(null) + const wrapperRef = useRef(null) + + const { + searchExpanded, + searchTerm, + selectedProducts, + selectedNetworks, + selectedTypes, + handleSearchChange, + handleSearchToggle, + toggleSelection, + clearProductFilters, + clearNetworkFilters, + clearTypeFilters, + } = useChangelogFilters({ items }) + + const toggleFilter = (filterType: FilterType) => { + setActiveFilter(filterType) + } + + const closeFilter = () => { + setActiveFilter(null) + } + + // Close filter when clicking outside + useEffect(() => { + if (!activeFilter) return + + const handleClickOutside = (event: MouseEvent) => { + if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) { + closeFilter() + } + } + + document.addEventListener("mousedown", handleClickOutside) + return () => { + document.removeEventListener("mousedown", handleClickOutside) + } + }, [activeFilter]) + + const getFilterOptions = () => { + switch (activeFilter) { + case "product": + return products + case "network": + return networks + case "type": + return types + default: + return [] + } + } + + const getSelectedValues = () => { + switch (activeFilter) { + case "product": + return selectedProducts + case "network": + return selectedNetworks + case "type": + return selectedTypes + default: + return [] + } + } + + return ( +
+ {activeFilter && ( +
+ {getFilterOptions().map((option) => ( + { + const type = activeFilter as "product" | "network" | "type" + toggleSelection(type, option) + }} + /> + ))} +
+ )} +
+ {!searchExpanded && ( + <> + toggleFilter("product")} + onClose={closeFilter} + onClearAll={clearProductFilters} + /> + toggleFilter("network")} + onClose={closeFilter} + onClearAll={clearNetworkFilters} + /> + toggleFilter("type")} + onClose={closeFilter} + onClearAll={clearTypeFilters} + /> + + )} + +
+
+ ) +} diff --git a/src/components/ChangelogFilters/MobileFilters.tsx b/src/components/ChangelogFilters/MobileFilters.tsx new file mode 100644 index 00000000000..9240d6b7fe8 --- /dev/null +++ b/src/components/ChangelogFilters/MobileFilters.tsx @@ -0,0 +1,337 @@ +import { SvgSearch, SvgTaillessArrowDownSmall, SvgX } from "@chainlink/blocks" +import styles from "./styles.module.css" +import { useState, useEffect } from "react" +import { createPortal } from "react-dom" +import { clsx } from "~/lib/clsx/clsx.ts" +import type { ChangelogItem } from "~/components/ChangelogSnippet/types.ts" +import { useChangelogFilters } from "./useChangelogFilters.ts" + +type FilterType = "product" | "network" | "type" | null + +interface SearchInputProps { + isExpanded: boolean + onClick: (value: boolean) => void + value: string + onChange: (value: string) => void +} + +const SearchInput = ({ isExpanded, onClick, value, onChange }: SearchInputProps) => { + return ( +
onClick(true)}> + + onChange(e.target.value)} + /> + {isExpanded && ( + { + e.stopPropagation() + onClick(false) + onChange("") + }} + style={{ + marginRight: "var(--space-4x)", + }} + /> + )} +
+ ) +} + +interface FilterPillProps { + label: string + isSelected: boolean + onClick: () => void +} + +const FilterPill = ({ label, isSelected, onClick }: FilterPillProps) => { + return ( + + ) +} + +interface MobileFiltersButtonProps { + totalCount: number + onClick: () => void +} + +const MobileFiltersButton = ({ totalCount, onClick }: MobileFiltersButtonProps) => { + return ( + + ) +} + +interface FilterSectionProps { + title: string + count: number + isExpanded: boolean + options: string[] + selectedValues: string[] + onToggle: () => void + onSelect: (value: string) => void + onClearAll: () => void +} + +const FilterSection = ({ + title, + count, + isExpanded, + options, + selectedValues, + onToggle, + onSelect, + onClearAll, +}: FilterSectionProps) => { + return ( +
+ + {isExpanded && ( +
+ {options.map((option) => ( + onSelect(option)} + /> + ))} +
+ )} +
+ ) +} + +interface MobileFiltersModalProps { + isOpen: boolean + onClose: () => void + products: string[] + networks: string[] + types: string[] + selectedProducts: string[] + selectedNetworks: string[] + selectedTypes: string[] + onSelectProduct: (value: string) => void + onSelectNetwork: (value: string) => void + onSelectType: (value: string) => void + onClearAll: () => void + expandedSection: FilterType + onToggleSection: (section: FilterType) => void + onClearProducts: () => void + onClearNetworks: () => void + onClearTypes: () => void +} + +const MobileFiltersModal = ({ + isOpen, + onClose, + products, + networks, + types, + selectedProducts, + selectedNetworks, + selectedTypes, + onSelectProduct, + onSelectNetwork, + onSelectType, + onClearAll, + expandedSection, + onToggleSection, + onClearProducts, + onClearNetworks, + onClearTypes, +}: MobileFiltersModalProps) => { + if (!isOpen) return null + + return ( + <> +
+
+
+

Filters

+ +
+
+ onToggleSection(expandedSection === "product" ? null : "product")} + onSelect={onSelectProduct} + onClearAll={onClearProducts} + /> + onToggleSection(expandedSection === "network" ? null : "network")} + onSelect={onSelectNetwork} + onClearAll={onClearNetworks} + /> + onToggleSection(expandedSection === "type" ? null : "type")} + onSelect={onSelectType} + onClearAll={onClearTypes} + /> +
+
+ + +
+
+ + ) +} + +interface MobileFiltersProps { + products: string[] + networks: string[] + types: string[] + items: ChangelogItem[] + searchExpanded: boolean + onSearchExpandedChange: (expanded: boolean) => void +} + +export const MobileFilters = ({ + products, + networks, + types, + items, + searchExpanded, + onSearchExpandedChange, +}: MobileFiltersProps) => { + const [isMobileFiltersOpen, setIsMobileFiltersOpen] = useState(false) + const [expandedSection, setExpandedSection] = useState(null) + + const { + searchTerm, + selectedProducts, + selectedNetworks, + selectedTypes, + handleSearchChange, + toggleSelection, + clearProductFilters, + clearNetworkFilters, + clearTypeFilters, + clearAllFilters, + } = useChangelogFilters({ items }) + + const totalFilterCount = selectedProducts.length + selectedNetworks.length + selectedTypes.length + + // Disable body scroll when mobile modal is open + useEffect(() => { + if (typeof window === "undefined") return + + if (isMobileFiltersOpen) { + document.body.style.overflow = "hidden" + } else { + document.body.style.overflow = "" + } + + return () => { + document.body.style.overflow = "" + } + }, [isMobileFiltersOpen]) + + const modalContent = ( + setIsMobileFiltersOpen(false)} + products={products} + networks={networks} + types={types} + selectedProducts={selectedProducts} + selectedNetworks={selectedNetworks} + selectedTypes={selectedTypes} + onSelectProduct={(value) => toggleSelection("product", value)} + onSelectNetwork={(value) => toggleSelection("network", value)} + onSelectType={(value) => toggleSelection("type", value)} + onClearAll={clearAllFilters} + expandedSection={expandedSection} + onToggleSection={setExpandedSection} + onClearProducts={clearProductFilters} + onClearNetworks={clearNetworkFilters} + onClearTypes={clearTypeFilters} + /> + ) + + return ( + <> +
+ setIsMobileFiltersOpen(true)} /> + +
+ + {typeof document !== "undefined" && createPortal(modalContent, document.body)} + + ) +} diff --git a/src/components/ChangelogFilters/styles.module.css b/src/components/ChangelogFilters/styles.module.css new file mode 100644 index 00000000000..83f34ade5f6 --- /dev/null +++ b/src/components/ChangelogFilters/styles.module.css @@ -0,0 +1,418 @@ +.wrapper { + background: #252e42e6; + border-radius: var(--space-8x); + max-width: 700px; + min-width: 492px; + + margin: 0 auto; + position: fixed; + bottom: var(--space-4x); + height: fit-content; + min-height: 56px; + z-index: 11; + left: 50%; + transform: translateX(-50%); + + padding: var(--space-2x); + backdrop-filter: blur(2px); + -webkit-backdrop-filter: blur(2px); +} + +.content { + display: grid; + grid-template-columns: repeat(4, 1fr); + align-items: center; + justify-content: space-evenly; +} + +.btn { + border-radius: var(--space-8x); + padding: 0 var(--space-4x); + color: var(--gray-300); + display: flex; + transition: all 0.1s ease; + align-items: center; + justify-content: center; + height: 100%; + &:hover { + background-color: #252e42; + } + + & div { + margin-right: var(--space-2x); + font-size: 16px; + display: flex; + align-items: center; + gap: var(--space-2x); + & span { + display: flex; + color: var(--white); + align-items: center; + gap: var(--space-2x); + background-color: var(--gray-500); + border-radius: var(--space-8x); + padding: var(--space-1x) var(--space-3x); + } + } +} + +.searchInputWrapper.expanded { + width: 100%; + grid-column-end: span 4; +} + +.searchIcon { + width: 22px; + height: 22px; +} + +.searchInputWrapper { + background-color: #252e42; + display: flex; + padding: var(--space-2x) var(--space-3x); + border-radius: var(--space-8x); + align-items: center; + gap: var(--space-2x); + transition: all 0.1s ease; + min-width: 108px; +} + +.searchInput { + background: transparent; + color: var(--gray-300); + font-size: 14px; + &::placeholder { + color: var(--gray-400); + font-style: normal; + } +} + +.expandedContent { + max-height: 312px; + overflow-y: auto; + overflow-x: hidden; + padding: var(--space-4x); + display: flex; + flex-direction: column; + gap: var(--space-1x); + margin-bottom: var(--space-2x); + border-bottom: 1px solid var(--gray-800); +} + +.expandedContent::-webkit-scrollbar { + width: 6px; +} + +.expandedContent::-webkit-scrollbar-track { + background: transparent; +} + +.expandedContent::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.2); + border-radius: 3px; +} + +.expandedContent::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.3); +} + +.pill { + background-color: transparent; + color: var(--white); + border-radius: var(--space-8x); + padding: var(--space-1x) var(--space-3x); + font-weight: 400; + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-2x); + transition: all 0.2s ease; + white-space: nowrap; + cursor: pointer; + border: none; + width: fit-content; + text-align: left; +} + +.pill:hover { + background-color: var(--gray-500); +} + +.pillSelected { + color: var(--white); + background-color: var(--gray-500); + + & span { + border-radius: var(--space-2x); + } +} + +.btnActive { + background-color: #1e2635; +} + +/* Mobile Styles */ +.mobileFiltersBtn { + background-color: #252e42; + border-radius: var(--space-8x); + padding: var(--space-2x) var(--space-3x); + display: flex; + align-items: center; + justify-content: center; + position: relative; + color: var(--gray-300); + transition: all 0.2s ease; + cursor: pointer; +} + +.mobileFiltersBtn:hover { + background-color: #1e2635; +} + +.mobileBadge { + position: absolute; + top: -4px; + right: -4px; + background-color: var(--blue-500); + color: var(--white); + border-radius: 50%; + width: 18px; + height: 18px; + display: flex; + align-items: center; + justify-content: center; + font-size: 10px; + font-weight: 600; +} + +/* Mobile Modal */ +.mobileModalBackdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + z-index: 100; + animation: fadeIn 0.2s ease; +} + +.mobileModal { + position: fixed; + bottom: 0; + left: 0; + right: 0; + max-height: 80vh; + background: #252e42; + border-radius: var(--space-6x) var(--space-6x) 0 0; + z-index: 101; + display: flex; + flex-direction: column; + animation: slideUp 0.3s ease; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes slideUp { + from { + transform: translateY(100%); + } + to { + transform: translateY(0); + } +} + +.mobileModalHeader { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-6x) var(--space-6x) var(--space-4x); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.mobileModalTitle { + font-size: 20px; + font-weight: 600; + color: var(--white); + margin: 0; +} + +.mobileModalClose { + background: transparent; + padding: var(--space-2x); + color: var(--gray-300); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; +} + +.mobileModalBody { + flex: 1; + overflow-y: auto; + padding: var(--space-4x) var(--space-6x); +} + +.mobileModalFooter { + display: flex; + gap: var(--space-3x); + padding: var(--space-4x) var(--space-6x); + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +.mobileModalClearAll { + flex: 1; + padding: var(--space-3x) var(--space-4x); + background: transparent; + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: var(--space-2x); + color: var(--gray-300); + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; +} + +.mobileModalClearAll:hover { + background-color: rgba(255, 255, 255, 0.05); +} + +.mobileModalApply { + flex: 1; + padding: var(--space-3x) var(--space-4x); + background: var(--blue-500); + border-radius: var(--space-2x); + color: var(--white); + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; +} + +.mobileModalApply:hover { + background: var(--blue-600); +} + +/* Filter Section */ +.filterSection { + margin-bottom: var(--space-4x); +} + +.filterSectionHeader { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-4x); + background: rgba(255, 255, 255, 0.05); + border-radius: var(--space-2x); + cursor: pointer; + transition: all 0.2s ease; +} + +.filterSectionHeader:hover { + background: rgba(255, 255, 255, 0.08); +} + +.filterSectionTitle { + display: flex; + align-items: center; + gap: var(--space-2x); + font-size: 16px; + font-weight: 500; + color: var(--white); +} + +.filterSectionCount { + display: flex; + align-items: center; + gap: var(--space-2x); + background-color: var(--gray-500); + border-radius: var(--space-8x); + padding: var(--space-1x) var(--space-3x); + font-size: 14px; + color: var(--white); +} + +.filterSectionChevron { + transition: transform 0.2s ease; + color: var(--gray-300); +} + +.filterSectionChevronOpen { + transform: rotate(180deg); +} + +.filterSectionContent { + padding: var(--space-4x); + display: flex; + flex-direction: column; + gap: var(--space-1x); + max-height: 300px; + overflow-y: auto; +} + +/* Desktop/Mobile Filter Visibility */ +.desktopFilters { + display: block; +} + +.mobileFilters { + display: none; +} + +/* Mobile Responsive */ +@media screen and (max-width: 576px) { + .desktopFilters { + display: none; + } + + .mobileFilters { + display: block; + width: 100%; + } + + .wrapper { + max-width: calc(100% - var(--space-4x)); + padding: var(--space-2x); + min-width: unset; + } + + .wrapper.searchExpanded { + width: 100%; + max-width: 100%; + } + + .content { + grid-template-columns: auto 1fr; + gap: var(--space-2x); + } + + /* When search is expanded on mobile, keep both elements inline */ + .content.searchExpanded { + grid-template-columns: auto 1fr; + gap: var(--space-3x); + width: 100%; + } + + /* Override desktop expanded behavior for mobile */ + .searchInputWrapper.expanded { + width: auto; + grid-column-end: auto; + } + + .searchInputWrapper { + padding: var(--space-2x); + } + + .searchInput { + font-size: 14px; + } +} diff --git a/src/components/ChangelogFilters/useChangelogFilters.ts b/src/components/ChangelogFilters/useChangelogFilters.ts new file mode 100644 index 00000000000..ef18c108cb3 --- /dev/null +++ b/src/components/ChangelogFilters/useChangelogFilters.ts @@ -0,0 +1,221 @@ +import { useState, useEffect, useRef } from "react" +import type { ChangelogItem } from "~/components/ChangelogSnippet/types.ts" +import { matchesFilters } from "~/utils/changelogFilters.ts" +import { parseURLParams, updateFilterURL, toggleItemInArray } from "~/utils/changelogFilterUtils.ts" + +export interface UseChangelogFiltersProps { + items: ChangelogItem[] +} + +interface FilterState { + selectedProducts: string[] + selectedNetworks: string[] + selectedTypes: string[] + searchTerm: string + searchExpanded: boolean +} + +export const useChangelogFilters = ({ items }: UseChangelogFiltersProps) => { + const [filters, setFilters] = useState({ + selectedProducts: [], + selectedNetworks: [], + selectedTypes: [], + searchTerm: "", + searchExpanded: false, + }) + const isInitialMount = useRef(true) + const hasLoadedFromURL = useRef(false) + + // Read URL parameters on mount + useEffect(() => { + const urlParams = parseURLParams() + + setFilters({ + selectedProducts: urlParams.products, + selectedNetworks: urlParams.networks, + selectedTypes: urlParams.types, + searchTerm: urlParams.searchTerm, + searchExpanded: urlParams.searchExpanded, + }) + + hasLoadedFromURL.current = true + }, []) + + // Update URL when filters change (but not on initial mount) + useEffect(() => { + // Skip the first render and the initial load from URL + if (isInitialMount.current) { + isInitialMount.current = false + return + } + + // Skip if we just loaded from URL + if (hasLoadedFromURL.current) { + hasLoadedFromURL.current = false + return + } + + updateFilterURL(filters.selectedProducts, filters.selectedNetworks, filters.selectedTypes, filters.searchTerm) + }, [filters]) + + // Filter items and update the display + useEffect(() => { + if (typeof window === "undefined") return + + const changelogItems = document.querySelectorAll(".changelog-item") + const loadMoreSection = document.querySelector(".load-more-section") as HTMLElement + const visibleCountSpan = document.getElementById("visible-count") + const emptyState = document.querySelector(".empty-state") as HTMLElement + const changelogList = document.querySelector(".changelog-list") as HTMLElement + + if (filters.searchTerm) { + // Search takes priority - filter by search term + const searchLower = filters.searchTerm.toLowerCase() + let visibleCount = 0 + + changelogItems.forEach((item) => { + const index = parseInt(item.getAttribute("data-index") || "0") + const changelogItem = items[index] + + const matchesSearch = + changelogItem?.name.toLowerCase().includes(searchLower) || + changelogItem?.["text-description"]?.toLowerCase().includes(searchLower) + + if (matchesSearch) { + ;(item as HTMLElement).style.display = "" + visibleCount++ + } else { + ;(item as HTMLElement).style.display = "none" + } + }) + + // Hide load more section when searching + if (loadMoreSection) { + loadMoreSection.style.display = "none" + } + + // Show/hide empty state + if (emptyState && changelogList) { + if (visibleCount === 0) { + emptyState.style.display = "flex" + changelogList.style.display = "none" + } else { + emptyState.style.display = "none" + changelogList.style.display = "flex" + } + } + } else { + // Apply filter logic + let visibleCount = 0 + const hasFilters = + filters.selectedProducts.length > 0 || filters.selectedNetworks.length > 0 || filters.selectedTypes.length > 0 + + changelogItems.forEach((item) => { + const index = parseInt(item.getAttribute("data-index") || "0") + const changelogItem = items[index] + + if (hasFilters && changelogItem) { + const matches = matchesFilters( + changelogItem, + filters.selectedProducts, + filters.selectedNetworks, + filters.selectedTypes + ) + if (matches) { + ;(item as HTMLElement).style.display = "" + visibleCount++ + } else { + ;(item as HTMLElement).style.display = "none" + } + } else { + // No filters - show first 25 items by default + if (visibleCount < 25) { + ;(item as HTMLElement).style.display = "" + visibleCount++ + } else { + ;(item as HTMLElement).style.display = "none" + } + } + }) + + // Show/hide load more section based on filters + if (loadMoreSection) { + if (hasFilters) { + loadMoreSection.style.display = "none" + } else { + loadMoreSection.style.display = visibleCount >= items.length ? "none" : "flex" + } + } + + // Update visible count + if (visibleCountSpan) { + visibleCountSpan.textContent = visibleCount.toString() + } + + // Show/hide empty state + if (emptyState && changelogList) { + if (hasFilters && visibleCount === 0) { + emptyState.style.display = "flex" + changelogList.style.display = "none" + } else { + emptyState.style.display = "none" + changelogList.style.display = "flex" + } + } + } + }, [filters, items]) + + const handleSearchChange = (value: string) => { + setFilters((prev) => ({ ...prev, searchTerm: value })) + } + + const handleSearchToggle = (expanded: boolean) => { + setFilters((prev) => ({ ...prev, searchExpanded: expanded })) + } + + const toggleSelection = (type: "product" | "network" | "type", value: string) => { + setFilters((prev) => { + switch (type) { + case "product": + return { ...prev, selectedProducts: toggleItemInArray(prev.selectedProducts, value) } + case "network": + return { ...prev, selectedNetworks: toggleItemInArray(prev.selectedNetworks, value) } + case "type": + return { ...prev, selectedTypes: toggleItemInArray(prev.selectedTypes, value) } + default: + return prev + } + }) + } + + const clearProductFilters = () => { + setFilters((prev) => ({ ...prev, selectedProducts: [] })) + } + + const clearNetworkFilters = () => { + setFilters((prev) => ({ ...prev, selectedNetworks: [] })) + } + + const clearTypeFilters = () => { + setFilters((prev) => ({ ...prev, selectedTypes: [] })) + } + + const clearAllFilters = () => { + setFilters((prev) => ({ ...prev, selectedProducts: [], selectedNetworks: [], selectedTypes: [] })) + } + + return { + searchExpanded: filters.searchExpanded, + searchTerm: filters.searchTerm, + selectedProducts: filters.selectedProducts, + selectedNetworks: filters.selectedNetworks, + selectedTypes: filters.selectedTypes, + handleSearchChange, + handleSearchToggle, + toggleSelection, + clearProductFilters, + clearNetworkFilters, + clearTypeFilters, + clearAllFilters, + } +} diff --git a/src/components/ChangelogSnippet/ChangelogCard.astro b/src/components/ChangelogSnippet/ChangelogCard.astro new file mode 100644 index 00000000000..3ac9a16021b --- /dev/null +++ b/src/components/ChangelogSnippet/ChangelogCard.astro @@ -0,0 +1,377 @@ +--- +import { SvgTaillessArrowDownSmall, Typography } from "@chainlink/blocks" +import styles from "./ChangelogCard.module.css" +import type { ChangelogItem } from "./types" +import { clsx } from "~/lib/clsx/clsx" +import CopyButton from "./CopyButton.tsx" + +interface Props { + item: ChangelogItem + showBorder?: boolean + autoExpand?: boolean + showCopyButton?: boolean + disableHover?: boolean + showNetworksAndTopic?: boolean +} + +const { + item, + showBorder = true, + autoExpand = false, + showCopyButton = true, + disableHover = false, + showNetworksAndTopic = false, +} = Astro.props + +// Format the date +const formatDate = (dateString: string) => { + const date = new Date(dateString) + return date.toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }) +} + +const formattedDate = formatDate(item["date-of-release"]) +--- + +
+
+
+
+ + {item.type} + + + {formattedDate} + +
+
+ +
+ { + showNetworksAndTopic && (item.networks || item.topic) && ( +
+ {item.networks &&
} + {item.topic && {item.topic}} +
+ ) + } + + + {item.name} + + +
+ {item["text-description"] &&
} +
+
+ + {showCopyButton && } +
+ +
+ +
+
+ + + + diff --git a/src/components/ChangelogSnippet/ChangelogCard.module.css b/src/components/ChangelogSnippet/ChangelogCard.module.css new file mode 100644 index 00000000000..cc929a288c2 --- /dev/null +++ b/src/components/ChangelogSnippet/ChangelogCard.module.css @@ -0,0 +1,265 @@ +/* Card Wrapper used in Changelog page */ +.cardWrapper { + max-height: 268px; + overflow: hidden; + transition: all 0.5s ease; + position: relative; + + &:hover { + background-color: var(--gray-50); + } + + &:hover .copyButton { + opacity: 1; + } + + & .card { + padding: var(--space-4x); + } + + & ul { + padding-left: var(--space-6x); + } + & li { + list-style-type: disc; + } +} + +/* Used on individual pages like CCIP/DataFeeds */ +.cardWrapper.withBorder { + border: 1px solid var(--border); + + &:hover { + background-color: var(--muted); + } +} + +/* Disable hover background when disableHover is true */ +.cardWrapper[data-disable-hover="true"]:hover { + background-color: transparent !important; +} + +.cardWrapper.withBorder[data-disable-hover="true"]:hover { + background-color: transparent !important; +} + +/* Remove padding when disableHover is true */ +.cardWrapper[data-disable-hover="true"] .card { + padding: 0 !important; +} + +/* Card Container */ +.card { + display: flex; + gap: 82px; +} + +.cardWrapper.withBorder.expanded .card { + -webkit-mask-image: none; + mask-image: none; +} + +.cardWrapper.withBorder:hover { + & .contentFooter { + background: linear-gradient(to top, var(--muted) 50%, transparent); + } +} + +/* Header Section */ +.header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: var(--space-4x); + margin-bottom: var(--space-3x); +} + +.metaSection { + display: flex; + flex-direction: column; + gap: var(--space-1x); + flex: 1; +} + +/* Description Section */ +.description { + display: flex; + flex-direction: column; + line-height: 1.6; + margin-top: var(--space-3x); +} + +.description p { + margin: 0; + color: var(--muted-foreground); +} + +.description a { + color: var(--link); + text-decoration: none; +} + +.description a:hover { + text-decoration: underline; +} + +.header { + display: flex; + width: 160px; +} + +.content { + display: flex; + flex-direction: column; + flex: 1; +} + +/* Description Content */ +.descriptionContent { + flex: 1; +} + +/* Networks and Topic Section */ +.networksAndTopicSection { + display: flex; + align-items: center; + gap: var(--space-3x); + margin-bottom: var(--space-4x); + flex-wrap: wrap; +} + +/* Content Footer */ +.contentFooter { + position: absolute; + bottom: 0; + left: 0; + right: 0; + z-index: 9; + height: calc(var(--space-6x) + 68px); + display: flex; + align-items: end; + background: linear-gradient(to top, white 50%, transparent); + opacity: 0; + pointer-events: none; + transition: opacity 0.2s ease-in-out; +} + +/* Expand Button */ +.expandButton { + display: flex; + align-items: center; + gap: 8px; + padding: 0; + background: none; + border: none; + color: var(--foreground); + font-size: 14px; + font-weight: 600; + transition: color 0.2s ease; + cursor: default; + margin-left: 256px; + margin-bottom: var(--space-6x); +} + +.expandButton svg { + transition: transform 0.3s ease; +} + +.copyButton { + display: flex; + height: fit-content; + gap: var(--space-2x); + border-radius: var(--space-1x); + border: 1px solid var(--border); + width: 118px; + justify-content: center; + align-items: center; + padding: var(--space-2x) 0; + transition: all 0.2s ease; + opacity: 0; + + & > svg { + color: var(--muted-foreground); + } + + &:hover { + border: 1px solid var(--foreground); + } +} + +.checkmark { + stroke: var(--success-foreground); +} +.copyIconMobile { + display: none; +} + +.copyIconDesktop { + display: block; +} + +@media screen and (max-width: 425px) { + .changelogType { + font-size: 14px; + } + + .metaSection { + gap: 0 !important; + } +} + +@media screen and (max-width: 768px) { + .cardWrapper { + max-height: 440px; + } + .card { + padding: var(--space-4x); + gap: var(--space-4x); + flex-direction: column; + } + + .header { + gap: var(--space-3x); + } + + .metaSection { + gap: var(--space-1x); + } + + .expandButton { + margin-left: 0; + } + + .cardWrapper.expanded .card { + -webkit-mask-image: none; + mask-image: none; + } + + .contentFooter { + padding-left: var(--space-4x); + } + + .copyIconDesktop { + display: none; + } + + .copyIconMobile { + display: block; + } + .copyText { + display: none; + } + + .copyButton { + width: 32px; + opacity: 1; + } +} + +@media screen and (max-width: 990px) { + .copyButton { + position: absolute; + right: var(--space-4x); + top: var(--space-4x); + } +} diff --git a/src/components/ChangelogSnippet/ChangelogSnippet.astro b/src/components/ChangelogSnippet/ChangelogSnippet.astro new file mode 100644 index 00000000000..7c251b503ac --- /dev/null +++ b/src/components/ChangelogSnippet/ChangelogSnippet.astro @@ -0,0 +1,65 @@ +--- +import { SvgArrowRight2, Typography } from "@chainlink/blocks" +import { SearchClient, searchClient } from "@algolia/client-search" +import ChangelogCard from "./ChangelogCard.astro" +import { AlgoliaQuery, type ChangelogItem } from "./types" +import styles from "./ChangelogSnippet.module.css" +import { getSecret } from "astro:env/server" + +interface Props { + query: AlgoliaQuery +} + +const { query } = Astro.props + +const appId = getSecret("ALGOLIA_APP_ID") +const apiKey = getSecret("PUBLIC_ALGOLIA_SEARCH_PUBLIC_API_KEY") + +let client: SearchClient +let latestLog: ChangelogItem | undefined = undefined + +// Initialize client if appId and apiKey are available to avoid needing to update +// the github actions with the new keys (satisfies linkcheck-internal) +if (appId && apiKey) { + client = searchClient(appId, apiKey) + + const req = await client.search({ + requests: [ + { + indexName: "Changelog", + restrictSearchableAttributes: ["topic"], + query, + hitsPerPage: 1, + }, + ], + }) + + const firstResult = req.results[0] + const results = "hits" in firstResult ? (firstResult.hits as ChangelogItem[]) : [] + + // logs are returned sorted by created_at DESC + latestLog = results[0] +} +--- + +{ + latestLog && ( +
+
+ + Changelog + + + + + +
+ +
+ ) +} diff --git a/src/components/ChangelogSnippet/ChangelogSnippet.module.css b/src/components/ChangelogSnippet/ChangelogSnippet.module.css new file mode 100644 index 00000000000..d852a20cba5 --- /dev/null +++ b/src/components/ChangelogSnippet/ChangelogSnippet.module.css @@ -0,0 +1,46 @@ +.container { + display: flex; + flex-direction: column; + gap: var(--space-6x); +} + +.grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--space-4x); +} + +.sectionHeader { + display: flex; + gap: var(--space-4x); + align-items: end; +} + +.arrow { + padding: 10px; + border: 1px solid var(--border); + height: fit-content; + cursor: default; + &:hover { + border: 1px solid var(--foreground); + } +} + +@media (max-width: 1024px) { + .grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 768px) { + .grid { + grid-template-columns: 1fr; + } +} + +@media screen and (max-width: 480px) { + .sectionHeader { + justify-content: space-between; + width: 100%; + } +} diff --git a/src/components/ChangelogSnippet/CopyButton.tsx b/src/components/ChangelogSnippet/CopyButton.tsx new file mode 100644 index 00000000000..d52f32aa96f --- /dev/null +++ b/src/components/ChangelogSnippet/CopyButton.tsx @@ -0,0 +1,68 @@ +import { SvgCopy, Typography } from "@chainlink/blocks" +import styles from "./ChangelogCard.module.css" +import { useState } from "react" + +export default function CopyButton({ url }: { url: string }) { + const [isCopied, setIsCopied] = useState(false) + + const copyToClipboard = () => { + const mode = import.meta.env.MODE === "development" ? "http://localhost:4321" : "https://dev.chain.link" + navigator.clipboard.writeText(`${mode}/changelog/${url}`) + setIsCopied(true) + setTimeout(() => setIsCopied(false), 2000) + } + + return ( + + ) +} diff --git a/src/components/ChangelogSnippet/README.md b/src/components/ChangelogSnippet/README.md new file mode 100644 index 00000000000..eab5afed7c6 --- /dev/null +++ b/src/components/ChangelogSnippet/README.md @@ -0,0 +1,100 @@ +# ChangelogSnippet Component + +## What This Component Does + +The ChangelogSnippet component displays the most recent changelog entry for a specific product or topic. It searches through changelog entries and shows the latest update in a card format with an expandable description. + +## Notes + +On pages like "CCIP" (individual product pages), the changelog card has a border and has slightly different styling than the component shown on the Changelog page. This component has no border and some different hover effects. This styling is controlled by the "showBorder" prop. The showBorder prop when set to true (true is the default value) is what you see on individual product pages. This will be the default styling when using the changelog components. On the Changelog page you can see the styling when showBorder is set to false. + +## How to Use It + +Import the component into your MDX file and provide a search query: + +```astro +import ChangelogSnippet from "@components/ChangelogSnippet/ChangelogSnippet.astro" + + +``` + +## Props + +| Prop | Type | Required | Description | +| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------- | +| `query` | string | Yes | The search term used to find relevant changelog entries (e.g., "ccip", "vrf", "automation") | +| `showBorder` | boolean | No | Whether to show a border around the card. Defaults to true. | + +## Complete Example + +Here's a full example of using the component in your documentation page: + +```astro +--- +import ChangelogSnippet from "@components/ChangelogSnippet/ChangelogSnippet.astro" +--- + +# CCIP Documentation Learn about Cross-Chain Interoperability Protocol. + + +``` + +This will display the latest CCIP-related changelog entry with a link to view the full changelog. + +--- + +# ChangelogCard Component + +## What This Component Does + +The ChangelogCard component displays a single changelog item in a card format. It shows the changelog entry's type, date, title, and description with optional expand/collapse functionality. + +## How to Use It + +Import the component and pass a changelog item: + +```astro +import ChangelogCard from "@components/ChangelogSnippet/ChangelogCard.astro" import type {ChangelogItem} from "@components/ChangelogSnippet/types" +const item: ChangelogItem = { + // ... changelog item data +} + + +``` + +## Props + +| Prop | Type | Required | Default | Description | +| ---------------------- | ------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------- | +| `item` | ChangelogItem | Yes | - | The changelog item to display | +| `showBorder` | boolean | No | `true` | Whether to show a border around the card | +| `autoExpand` | boolean | No | `false` | Whether to automatically expand the card to full height (skips height restrictions and hides expand/collapse button) | +| `showCopyButton` | boolean | No | `true` | Whether to show the "Copy URL" button | +| `disableHover` | boolean | No | `false` | Whether to disable hover effects (background color change and card padding) | +| `showNetworksAndTopic` | boolean | No | `false` | Whether to show the networks icons and topic chip above the title | + +## Usage Examples + +### Default Card (with border and interactions) + +```astro + +``` + +### Card without border (like on main changelog page) + +```astro + +``` + +### Fully expanded card without interactions (like on individual pages) + +```astro + +``` + +### Card with networks and topic displayed + +```astro + +``` diff --git a/src/components/ChangelogSnippet/types.ts b/src/components/ChangelogSnippet/types.ts new file mode 100644 index 00000000000..870c3afd23b --- /dev/null +++ b/src/components/ChangelogSnippet/types.ts @@ -0,0 +1,31 @@ +export type AlgoliaQuery = + | "ccip" + | "data-streams" + | "smart-data" + | "nodes" + | "data-feeds" + | "functions" + | "automation" + | "vrf" + | "general" + +export interface ChangelogItem { + createdOn: string + "date-of-release": string + hash: string + id: string + lastPublished: string + lastUpdated: string + name: string + networks: string + slug: string + "text-description": string + topic: string + type: string + objectID: string + _highlightResult?: { + "date-of-release": Record + name: Record + "text-description": Record + } +} diff --git a/src/components/CodeHighlightBlock/CodeHighlightBlock.astro b/src/components/CodeHighlightBlock/CodeHighlightBlock.astro index 03bacdf06c2..8eb7332ce8e 100644 --- a/src/components/CodeHighlightBlock/CodeHighlightBlock.astro +++ b/src/components/CodeHighlightBlock/CodeHighlightBlock.astro @@ -277,7 +277,7 @@ function getLanguageDisplayName(langCode: string): string { const languageDisplay = getLanguageDisplayName(lang) --- -
+
{ @@ -358,6 +358,13 @@ const languageDisplay = getLanguageDisplayName(lang) // Simple syntax highlighting function function highlightInIsolation(code, language) { + // First, HTML-escape the code to prevent code parts from being interpreted as tags + const escapeHtml = (text) => { + const div = document.createElement("div") + div.textContent = text + return div.innerHTML + } + const goKeywords = ["package", "import", "func", "type", "struct", "if", "else", "for", "return", "var", "const"] const goTypes = ["string", "int", "bool", "error", "interface{}"] @@ -382,7 +389,7 @@ const languageDisplay = getLanguageDisplayName(lang) ] const tsTypes = ["string", "number", "boolean", "void", "any", "unknown", "object", "Array"] - let highlighted = code + let highlighted = escapeHtml(code) if (language === "go") { // Highlight strings @@ -602,8 +609,8 @@ const languageDisplay = getLanguageDisplayName(lang) if (copyButton) { copyButton.addEventListener("click", async () => { try { - // Use the clean code stored specifically in THIS container's data attribute - const codeToCopy = container.dataset.cleanCode || "" + // Parse the JSON-encoded clean code from the data attribute + const codeToCopy = JSON.parse(container.dataset.cleanCode || '""') await navigator.clipboard.writeText(codeToCopy) copyButton.innerHTML = checkmarkIconSVG diff --git a/src/components/CodeHighlightBlockMulti/CodeHighlightBlockMulti.astro b/src/components/CodeHighlightBlockMulti/CodeHighlightBlockMulti.astro index 3d82e41e0cf..cbd3df0330f 100644 --- a/src/components/CodeHighlightBlockMulti/CodeHighlightBlockMulti.astro +++ b/src/components/CodeHighlightBlockMulti/CodeHighlightBlockMulti.astro @@ -789,6 +789,13 @@ const languageDisplay = getLanguageDisplayName(currentLang) // Simple syntax highlighting function function highlightInIsolation(code, language) { + // First, HTML-escape the code to prevent code parts from being interpreted as tags + const escapeHtml = (text) => { + const div = document.createElement("div") + div.textContent = text + return div.innerHTML + } + const goKeywords = ["package", "import", "func", "type", "struct", "if", "else", "for", "return", "var", "const"] const goTypes = ["string", "int", "bool", "error", "interface{}"] @@ -813,7 +820,7 @@ const languageDisplay = getLanguageDisplayName(currentLang) ] const tsTypes = ["string", "number", "boolean", "void", "any", "unknown", "object", "Array"] - let highlighted = code + let highlighted = escapeHtml(code) if (language === "go") { // Highlight strings diff --git a/src/components/CodeSample/CodeSample.astro b/src/components/CodeSample/CodeSample.astro index 73cef4f4cb2..a617179346e 100644 --- a/src/components/CodeSample/CodeSample.astro +++ b/src/components/CodeSample/CodeSample.astro @@ -1,20 +1,31 @@ --- -import { Prism } from "@astrojs/prism" +import { runHighlighterWithAstro } from "@astrojs/prism/dist/highlighter" import fs from "node:fs/promises" import path from "node:path" +import { getLanguageIconSrc, languageBadge } from "../../lib/codeSample/language.js" + export type Props = { src: string lang?: string + filename?: string showButtonOnly?: boolean optimize?: boolean runs?: number + showButtons?: boolean } -const { src, lang, showButtonOnly, optimize, runs } = Astro.props as Props +const { src, lang, filename, showButtonOnly, optimize, runs, showButtons = true } = Astro.props as Props const data = (await fs.readFile(path.join(process.cwd(), "public", src), "utf-8")).toString() +const prismLang = lang ?? "solidity" +const headerFilename = filename?.trim() || undefined +const { classLanguage, html } = runHighlighterWithAstro(prismLang, data) +const languageKey = prismLang.toLowerCase() +const languageIconSrc = getLanguageIconSrc(languageKey) +const preInnerHtml = `${html}` + const isSolidityFile = src.match(/\.sol/) const isSample = isSolidityFile && (src.indexOf("samples/") === 0 || src.indexOf("/samples/") === 0) @@ -29,7 +40,38 @@ const remixUrl = `https://remix.ethereum.org/#url=https://docs.chain.link/${clea }` --- -{!showButtonOnly && } +{ + !showButtonOnly && + (headerFilename ? ( +
+
+
+ + + {headerFilename} + +
+ +
+
+      
+ ) : ( +
+    ))
+}
+
 {
   isSample && (
     
diff --git a/src/components/CodeSample/CodeSampleReact.tsx b/src/components/CodeSample/CodeSampleReact.tsx index 4b17738649b..687e13ade30 100644 --- a/src/components/CodeSample/CodeSampleReact.tsx +++ b/src/components/CodeSample/CodeSampleReact.tsx @@ -13,7 +13,6 @@ export const CodeSampleReact: React.FC = ({ src, showButto const isSolidityFile = src.match(/\.sol/) const isSample = isSolidityFile && (src.indexOf("samples/") === 0 || src.indexOf("/samples/") === 0) - if (!isSample || !showButtonOnly || !remixUrl) return null return ( diff --git a/src/components/CommunityEvents/CommunityEvents.astro b/src/components/CommunityEvents/CommunityEvents.astro new file mode 100644 index 00000000000..2d31b6a0945 --- /dev/null +++ b/src/components/CommunityEvents/CommunityEvents.astro @@ -0,0 +1,110 @@ +--- +import { SvgArrowRight2, Typography } from "@chainlink/blocks" +import EventCard from "./EventCard.astro" +import ImageGallery from "./ImageGallery.astro" +import type { GalleryImage } from "./types" +import { fetchEventsFromRSS } from "./fetchEvents" +import styles from "./CommunityEvents.module.css" + +// Community event gallery images +const galleryImages: GalleryImage[] = [ + // Top row - scrolls left + { + id: "1", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd59_home-community-5.webp", + alt: "Chainlink community event", + }, + { + id: "2", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd55_home-community-2.webp", + alt: "Chainlink community event", + }, + { + id: "3", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd30_home-community-4.webp", + alt: "Chainlink community event", + }, + { + id: "4", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd46_home-community-11.webp", + alt: "Chainlink community event", + }, + { + id: "5", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd51_home-community-3.webp", + alt: "Chainlink community event", + }, + { + id: "6", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd42_home-community-10.webp", + alt: "Chainlink community event", + }, + // Bottom row - scrolls right + { + id: "7", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd24_community-photo-12.webp", + alt: "Chainlink community event", + }, + { + id: "8", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd2b_community-photo-10.webp", + alt: "Chainlink community event", + }, + { + id: "9", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd4c_community-photo-24.webp", + alt: "Chainlink community event", + }, + { + id: "10", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd3d_community-photo-22.webp", + alt: "Chainlink community event", + }, + { + id: "11", + imageUrl: + "https://cdn.prod.website-files.com/64cc2c23d8dbd707cdb556d8/677d1da974d919ae98a3bd36_community-photo-30.webp", + alt: "Chainlink community event", + }, +] + +const events = await fetchEventsFromRSS() +--- + +
+
+ + Community Events + + + + + +
+
+
+
+ {events.map((event) => )} +
+
+ +
+ +
+
+
diff --git a/src/components/CommunityEvents/CommunityEvents.module.css b/src/components/CommunityEvents/CommunityEvents.module.css new file mode 100644 index 00000000000..562ac07105c --- /dev/null +++ b/src/components/CommunityEvents/CommunityEvents.module.css @@ -0,0 +1,87 @@ +.wrapper { + margin: 86px 0; +} +.component { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: auto; + grid-auto-columns: 1fr; + align-items: center; + gap: 33px; + width: 100%; +} + +.contentLeft { + justify-self: end; + width: 100%; + max-width: calc(var(--fullwidth-max-width) / 2); + padding-left: var(--space-10x); +} + +.contentRight { + display: flex; + align-items: center; + overflow: hidden; +} + +.sectionHeader { + display: flex; + gap: var(--space-4x); + align-items: end; + max-width: var(--fullwidth-max-width); + margin-bottom: var(--space-8x); + margin-left: auto; + margin-right: auto; + padding: 0 var(--space-10x); +} + +.arrow { + padding: 10px; + border: 1px solid var(--border); + height: fit-content; + cursor: pointer; + transition: border-color 0.2s ease; +} + +.arrow:hover { + border: 1px solid var(--foreground); +} + +.eventList { + display: flex; + flex-direction: column; + gap: var(--space-6x); +} + +/* Tablet */ +@media (max-width: 1024px) { + .component { + display: flex; + flex-direction: column-reverse; + } + + .contentRight { + margin-left: 0; + width: 100%; + } + + .contentLeft { + max-width: 100%; + } +} + +/* Mobile */ +@media (max-width: 768px) { + .sectionHeader { + margin-bottom: var(--space-6x); + margin-left: unset; + margin-right: unset; + & > h2 { + font-size: 28px; + } + } + + .wrapper { + margin: 36px 0; + } +} diff --git a/src/components/CommunityEvents/EventCard.astro b/src/components/CommunityEvents/EventCard.astro new file mode 100644 index 00000000000..4bf52bef5a0 --- /dev/null +++ b/src/components/CommunityEvents/EventCard.astro @@ -0,0 +1,32 @@ +--- +import { SvgArrowRight2, Typography } from "@chainlink/blocks" +import type { CommunityEvent } from "./types" +import styles from "./EventCard.module.css" + +interface Props { + event: CommunityEvent +} + +const { event } = Astro.props +--- + + +
+ {event.month} + {event.day} +
+
+
+
+ {`${event.country} +
+ {event.location} +
+
+ + {event.title} + + arrow +
+
+
diff --git a/src/components/CommunityEvents/EventCard.module.css b/src/components/CommunityEvents/EventCard.module.css new file mode 100644 index 00000000000..4613acc0971 --- /dev/null +++ b/src/components/CommunityEvents/EventCard.module.css @@ -0,0 +1,80 @@ +.eventCardLink { + display: flex; + align-items: center; + gap: var(--space-4x); + border-radius: 0.5rem; + text-decoration: none; + transition: all 0.3s ease; + background-color: var(--background); +} + +.eventCardLink:hover .eventCardH { + color: var(--brand) !important; +} + +.eventCardLink:hover .linkArr { + opacity: 1 !important; +} + +.eventDate { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: var(--space-2x) var(--space-5x); + flex-shrink: 0; + border: 1px solid var(--border); + background-color: var(--muted); +} + +.eventCardDesc { + display: flex; + flex-direction: column; + gap: var(--space-2x); + flex: 1; + min-width: 0; +} + +.eventCardCountry { + display: flex; + align-items: center; + gap: var(--space-2x); +} + +.eventCardFlag { + width: 16px; + max-width: 16px; + height: 16px; + border-radius: 100%; + overflow: hidden; + flex-shrink: 0; + position: relative; +} + +.coverImg { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +.eventCardCountryName { + text-transform: uppercase; + color: var(--gray-600); +} + +.eventCardHWrap { + display: flex; + align-items: baseline; + gap: var(--space-3x); +} + +.linkArr { + opacity: 0; +} + +@media (max-width: 768px) { + .eventCardLink { + gap: var(--space-3x); + } +} diff --git a/src/components/CommunityEvents/ImageGallery.astro b/src/components/CommunityEvents/ImageGallery.astro new file mode 100644 index 00000000000..20c0f26e5ee --- /dev/null +++ b/src/components/CommunityEvents/ImageGallery.astro @@ -0,0 +1,42 @@ +--- +import type { GalleryImage } from "./types" +import styles from "./ImageGallery.module.css" + +interface Props { + images: GalleryImage[] +} + +const { images } = Astro.props + +// Split images into two rows for the gallery +const topRowImages = images.slice(0, Math.ceil(images.length / 2)) +const bottomRowImages = images.slice(Math.ceil(images.length / 2)) + +// Duplicate images for seamless infinite scroll +const topRowDuplicated = [...topRowImages, ...topRowImages] +const bottomRowDuplicated = [...bottomRowImages, ...bottomRowImages] +--- + +
+ +
+ { + topRowDuplicated.map((image) => ( +
+ {image.alt} +
+ )) + } +
+ + +
+ { + bottomRowDuplicated.map((image) => ( +
+ {image.alt} +
+ )) + } +
+
diff --git a/src/components/CommunityEvents/ImageGallery.module.css b/src/components/CommunityEvents/ImageGallery.module.css new file mode 100644 index 00000000000..edc1af53337 --- /dev/null +++ b/src/components/CommunityEvents/ImageGallery.module.css @@ -0,0 +1,70 @@ +.gallery { + width: 100%; + display: flex; + flex-direction: column; + gap: var(--space-5x); + overflow: hidden; +} + +.row { + display: flex; + gap: var(--space-5x); + animation: scrollLeft 30s linear infinite; + flex-shrink: 0; +} + +.rowReverse { + animation: scrollRight 30s linear infinite; +} + +.imageWrapper { + width: 16rem; + height: 12rem; + flex-shrink: 0; + border-radius: 0.5rem; + overflow: hidden; + position: relative; +} + +.image { + object-fit: cover; + border-radius: 0.5rem; + width: 100%; + height: 100%; + position: absolute; + inset: 0; +} + +@keyframes scrollLeft { + 0% { + transform: translate3d(0%, 0px, 0px); + } + 100% { + transform: translate3d(-50%, 0px, 0px); + } +} + +@keyframes scrollRight { + 0% { + transform: translate3d(-50%, 0px, 0px); + } + 100% { + transform: translate3d(0%, 0px, 0px); + } +} + +/* Pause animation on hover */ +.gallery:hover .row { + animation-play-state: paused; +} + +@media (max-width: 1024px) { + .imageWrapper { + width: 12rem; + height: 9rem; + } + + .gallery { + padding: 0 var(--space-10x); + } +} diff --git a/src/components/CommunityEvents/fetchEvents.ts b/src/components/CommunityEvents/fetchEvents.ts new file mode 100644 index 00000000000..09ee45fbbef --- /dev/null +++ b/src/components/CommunityEvents/fetchEvents.ts @@ -0,0 +1,53 @@ +import type { CommunityEvent } from "./types.ts" + +// Fetch events from Webflow RSS feed +export const fetchEventsFromRSS = async (): Promise => { + try { + const response = await fetch("https://chain.link/events-coll/rss.xml") + const xml = await response.text() + + // Parse RSS XML manually (lightweight approach without xml2js dependency) + const items = xml.match(/[\s\S]*?<\/item>/g) || [] + const now = new Date() + now.setHours(0, 0, 0, 0) // Set to start of today to include today's events + + const events = items + .map((item, index) => { + const title = item.match(/(.*?)<\/title>/)?.[1] || "" + const pubDate = item.match(/<pubDate>(.*?)<\/pubDate>/)?.[1] || "" + const description = item.match(/<description>(.*?)<\/description>/)?.[1] || "" + const mediaContent = item.match(/<media:content url="(.*?)"/)?.[1] || "" + + // Parse description: "Nov 12, 2025 - | Meetup | Bhopal | https://luma.com/cl_bhopal01" + const descParts = description.split("|").map((s) => s.trim()) + const location = descParts[2] || "Virtual" + const eventUrl = descParts[3] || "" + + // Parse date + const dateObj = new Date(pubDate) + const month = dateObj.toLocaleDateString("en-US", { month: "short" }) + const day = dateObj.getDate().toString() + + return { + id: index.toString(), + title: title.replace(/&/g, "&"), + date: dateObj.toISOString(), + month, + day, + location, + country: location, + flagUrl: mediaContent, + eventUrl, + backgroundColor: "rgb(12, 22, 44)", + } + }) + .filter((event) => new Date(event.date) >= now) // Filter out past events + .sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) // Sort ascending (closest first) + .slice(0, 3) // Only take the first 3 events + + return events + } catch (error) { + console.error("Error fetching events:", error) + return [] + } +} diff --git a/src/components/CommunityEvents/types.ts b/src/components/CommunityEvents/types.ts new file mode 100644 index 00000000000..ab6910a200d --- /dev/null +++ b/src/components/CommunityEvents/types.ts @@ -0,0 +1,18 @@ +export interface CommunityEvent { + id: string + title: string + date: string // ISO date string + month: string + day: string + location: string + country: string + flagUrl: string + eventUrl: string + backgroundColor?: string +} + +export interface GalleryImage { + id: string + imageUrl: string + alt: string +} diff --git a/src/components/Demos.astro b/src/components/Demos.astro new file mode 100644 index 00000000000..0cf482cfe2e --- /dev/null +++ b/src/components/Demos.astro @@ -0,0 +1,90 @@ +--- +import { Tag, Typography } from "@chainlink/blocks" +import styles from "./Demos.module.css" + +export interface Demo { + image: string + title: string + description: string + tags: string[] + href: string +} + +const demos: Demo[] = [ + { + image: "/images/demos/Demos thumbnails 1.png", + title: "Custom Data Feed", + description: + "See how you can bring your financial data onchain in a variety of different ways by creating a Net Asset Value feed, Proof of Reserve feed, or other custom data feed.", + tags: ["CRE", "DATA FEEDS"], + href: "/", + }, + { + image: "/images/demos/Demos thumbnails 2.png", + title: "Delivery vs. Payment (DvP)", + description: + "Learn how to sell a variety of assets via a Delivery vs. Payment transaction using the Chainlink Runtime Environment (CRE).", + tags: ["CRE"], + href: "/", + }, + { + image: "/images/demos/Demos thumbnails 3.png", + title: "Digital Transfer Agent (DTA)", + description: + "Learn how to invest in a variety of funds via a Digital Transfer Agent (DTA) transaction using the Chainlink Runtime Environment (CRE).", + tags: ["CRE"], + href: "/", + }, + { + image: "/images/demos/Demos thumbnails 4.png", + title: "Explore Chainlink", + description: "Explore how the Chainlink standard powers tokenization and onchain finance through", + tags: ["CRE", "CCIP", "DATA FEEDS"], + href: "/", + }, +] +--- + +<section class={styles.demosSection}> + <Typography variant="h2">Demos</Typography> + <div class={styles.grid}> + { + demos.map((demo) => ( + <a href={demo.href} class={styles.card}> + <div class={styles.imageContainer}> + <img src={demo.image} alt={demo.title} class={styles.image} /> + </div> + <div class={styles.content}> + <div class={styles.body}> + <Typography + variant="h6" + style={{ + fontWeight: "500", + marginBottom: "var(--space-4x)", + }} + > + {demo.title} + </Typography> + <Typography variant="body-s" color="muted"> + {demo.description} + </Typography> + </div> + <footer class={styles.footer}> + <div class={styles.tags}> + {demo.tags.map((tag) => ( + <Tag size="sm" className={styles.footerTag}> + {tag} + </Tag> + ))} + </div> + + <div class={styles.footerArrow}> + <img src="/assets/icons/upper-right-arrow.svg" alt="" /> + </div> + </footer> + </div> + </a> + )) + } + </div> +</section> diff --git a/src/components/Demos.module.css b/src/components/Demos.module.css new file mode 100644 index 00000000000..37371d59041 --- /dev/null +++ b/src/components/Demos.module.css @@ -0,0 +1,99 @@ +.demosSection { + width: 100%; + display: flex; + flex-direction: column; + gap: var(--space-6x); + + & > h2 { + font-size: 28px; + } +} + +.grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + border: 1px solid var(--border); +} + +.card { + display: flex; + flex-direction: column; + padding: var(--space-6x); + overflow: hidden; + transition: box-shadow 0.2s ease; + gap: var(--space-4x); + + &:hover { + background-color: var(--muted); + } + + &:hover .footerTag { + background-color: var(--background); + } + + &:hover .footerArrow { + opacity: 1; + } +} + +.card:not(:last-child) { + border-right: 1px solid var(--border); +} + +.imageContainer { + width: 100%; + aspect-ratio: 16 / 9; + overflow: hidden; +} + +.image { + width: 100%; + height: 100%; + object-fit: cover; +} + +.body { + margin-bottom: var(--space-4x); +} +.content { + display: flex; + flex-direction: column; + gap: var(--space-4x); + flex: 1; +} + +.tags { + display: flex; + flex-wrap: wrap; + gap: var(--space-1x); +} + +.footer { + display: flex; + justify-content: space-between; + + margin-top: auto; + padding-top: var(--space-4x); +} + +.footerArrow { + opacity: 0; + display: flex; + align-items: end; +} +@media screen and (max-width: 1024px) { + .grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media screen and (max-width: 570px) { + .grid { + grid-template-columns: repeat(1, 1fr); + } + + .card:not(:last-child) { + border-bottom: 1px solid var(--border); + border-right: none; + } +} diff --git a/src/components/DocsHeaderTitle/DocsHeaderTitle.astro b/src/components/DocsHeaderTitle/DocsHeaderTitle.astro new file mode 100644 index 00000000000..81ec51634ed --- /dev/null +++ b/src/components/DocsHeaderTitle/DocsHeaderTitle.astro @@ -0,0 +1,24 @@ +--- +import { getNavigationProps } from "../Header/getNavigationProps" +import { isMatchedPath } from "../Header/Nav/isMatchedPath" +import defaultLogo from "../../assets/product-logos/default-logo.svg" +import styles from "./docsHeaderTitle.module.css" +const { subProductsNav } = getNavigationProps() +import { Typography } from "@chainlink/blocks" + +interface Props { + pathname: string +} + +const { pathname } = Astro.props + +const subProductTrigger = subProductsNav?.find(({ href }) => isMatchedPath(pathname, href)) + +const label = subProductTrigger?.label || "Resources" +const icon = subProductTrigger?.label ? subProductTrigger.icon : defaultLogo.src +--- + +<div class={styles.docsHeaderTitleWrapper}> + <img src={icon} alt="" class={styles.logo} /> + <Typography color="foreground" variant="body-semi-l">{label}</Typography> +</div> diff --git a/src/components/DocsHeaderTitle/docsHeaderTitle.module.css b/src/components/DocsHeaderTitle/docsHeaderTitle.module.css new file mode 100644 index 00000000000..f0f9443a1f0 --- /dev/null +++ b/src/components/DocsHeaderTitle/docsHeaderTitle.module.css @@ -0,0 +1,11 @@ +.logo { + width: var(--space-6x); + height: var(--space-6x); +} + +.docsHeaderTitleWrapper { + display: flex; + align-items: center; + gap: var(--space-3x); + padding: var(--doc-padding) 0; +} diff --git a/src/components/DocsNavigation/DocsNavigationDesktop/DocsNavigationDesktop.tsx b/src/components/DocsNavigation/DocsNavigationDesktop/DocsNavigationDesktop.tsx index f1a88b5395f..bf09832475c 100644 --- a/src/components/DocsNavigation/DocsNavigationDesktop/DocsNavigationDesktop.tsx +++ b/src/components/DocsNavigation/DocsNavigationDesktop/DocsNavigationDesktop.tsx @@ -1,6 +1,5 @@ import { clsx } from "~/lib/clsx/clsx.ts" import { useNavBar } from "../../Header/useNavBar/useNavBar.ts" -import DocsPickerDesktop from "./DocsPickerDesktop.tsx" import styles from "./docsNavigationDesktop.module.css" import QuickLinksModal from "../../Header/Nav/QuickLinksModal.tsx" import { useState } from "react" @@ -29,10 +28,7 @@ function DocsNavigationDesktop({ })} > <div className={styles.container}> - <div className={styles.left}> - <DocsPickerDesktop pathname={pathname} /> - {children} - </div> + <div className={styles.left}>{children}</div> <div className={styles.links}> {isCcipPage ? ( /* Custom links for CCIP Directory pages */ diff --git a/src/components/DocsNavigation/DocsNavigationDesktop/DocsPickerDesktop.tsx b/src/components/DocsNavigation/DocsNavigationDesktop/DocsPickerDesktop.tsx deleted file mode 100644 index feb8d80bcfb..00000000000 --- a/src/components/DocsNavigation/DocsNavigationDesktop/DocsPickerDesktop.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { useState } from "react" -import { isMatchedPath } from "../../Header/Nav/isMatchedPath.ts" -import { getNavigationProps } from "../../Header/getNavigationProps.ts" -import styles from "./docsPickerDesktop.module.css" -import { clsx } from "../../Header/Nav/utils.ts" -import defaultLogo from "../../../assets/product-logos/default-logo.svg" - -function DocsPickerDesktop({ pathname }: { pathname: string }) { - const [productMenuOpen, setProductMenuOpen] = useState(false) - const { subProductsNav } = getNavigationProps() - - const subProductTrigger = subProductsNav?.find(({ href }) => isMatchedPath(pathname, href)) - - const label = subProductTrigger?.label || "Resources" - const icon = subProductTrigger?.label ? subProductTrigger.icon : defaultLogo.src - - return ( - <div - className={styles.docsPickerContainer} - onMouseEnter={() => setProductMenuOpen(true)} - onMouseLeave={() => setProductMenuOpen(false)} - > - <img src={icon} alt="" className={styles.logo} /> - <span>{label}</span> - <div className={styles.caret}> - <span></span> - </div> - {productMenuOpen && ( - <div className={styles.menu}> - <ul className={styles.column}> - {subProductsNav - .filter((item) => !item.hideFromDropdown && item.col === 1) - .map((item) => ( - <li className={clsx(styles.item)} key={item.label}> - <a - className={clsx(styles.link, { [styles.active]: isMatchedPath(pathname, item.href) })} - href={item.href} - > - <img className={clsx(styles.icon)} src={item.icon}></img> - {item.label} - </a> - </li> - ))} - </ul> - <ul className={styles.column}> - {subProductsNav - .filter((item) => !item.hideFromDropdown && item.col === 2) - .map((item) => ( - <li className={clsx(styles.item)} key={item.label}> - <a className={clsx(styles.link)} href={item.href}> - <img className={clsx(styles.icon)} src={item.icon}></img> - {item.label} - </a> - </li> - ))} - </ul> - </div> - )} - </div> - ) -} - -export default DocsPickerDesktop diff --git a/src/components/DownloadButton.tsx b/src/components/DownloadButton.tsx index 8b3101444fb..43c45239725 100644 --- a/src/components/DownloadButton.tsx +++ b/src/components/DownloadButton.tsx @@ -15,7 +15,7 @@ export const DownloadButton = () => { } const handleClick = () => { - window.open("https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.2", "_blank", "noopener,noreferrer") + window.open("https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.10", "_blank", "noopener,noreferrer") } const handleMouseOver = (e) => { diff --git a/src/components/Footer/Footer.astro b/src/components/Footer/Footer.astro index 7f8a2078d1a..11b0118ed71 100644 --- a/src/components/Footer/Footer.astro +++ b/src/components/Footer/Footer.astro @@ -59,9 +59,6 @@ <li class="footer-list-item"> <a href="https://chain.link/community" class="footer-list-item-link"> Community overview</a> </li> - <li class="footer-list-item"> - <a href="https://chain.link/community/grants" class="footer-list-item-link"> Grant program</a> - </li> <li class="footer-list-item"> <a href="https://chain.link/community/events" class="footer-list-item-link"> Events</a> </li> @@ -198,7 +195,7 @@ </a> <div class="paragraph small footer-chainlinkreg hidden-sm">Chainlink®</div> <div class="paragraph small footer-chainlinkreg hidden-sm"> - {" "}© 2025 Chainlink Foundation + {" "}© 2026 Chainlink Foundation </div> </div> <div class="col footer-privacyandterms"> @@ -302,6 +299,12 @@ display: flex; align-items: center; } + + .footer-col > h3 { + margin-bottom: var(--space-4x); + font-weight: 500; + } + .footer-logo-text-hide { position: absolute; left: 0; diff --git a/src/components/Footer/NewsletterCTA.css b/src/components/Footer/NewsletterCTA.css index bf25fd36df4..eac894074d1 100644 --- a/src/components/Footer/NewsletterCTA.css +++ b/src/components/Footer/NewsletterCTA.css @@ -19,6 +19,8 @@ .cta-subscribe-h1 { text-align: center; + font-size: 2rem; + font-weight: 600; } .newsletter-cta :is(h2) { @@ -56,6 +58,7 @@ } .newsletter-cta .cta-subscribe-input::placeholder { font-style: italic; + color: var(--muted-foreground); } #subscribe-button { @@ -100,3 +103,9 @@ margin-bottom: var(--space-0x); } } + +@media screen and (min-width: 768px) { + .cta-subscribe-h1 { + font-size: 2.5rem; + } +} diff --git a/src/components/HeadCommon.astro b/src/components/HeadCommon.astro index f2199bba192..9a25c23af49 100644 --- a/src/components/HeadCommon.astro +++ b/src/components/HeadCommon.astro @@ -1,9 +1,11 @@ --- import "../styles/theme.css" import "../styles/index.css" +import "../styles/code-blocks.css" import "../styles/migrated.css" import "../styles/prism-darcula.css" import "@chainlink/design-system/global-styles.css" +import "@chainlink/blocks/src/theme/globals.css" export interface Props { title: string @@ -81,6 +83,31 @@ const { title } = Astro.props })() </script> +<!-- Set CCIP Chain Family in dataLayer --> +<script is:inline type="text/javascript"> + ;(function () { + if (!window.location.pathname.startsWith("/ccip")) return + + try { + var savedChain = localStorage.getItem("chainlink-docs-chain-type") + // Default to "evm" if not set or invalid + var chainFamily = + savedChain === "solana" || savedChain === '"solana"' + ? "solana" + : savedChain === "aptos" || savedChain === '"aptos"' + ? "aptos" + : "evm" + + window.dataLayer = window.dataLayer || [] + window.dataLayer.push({ + ccip_chain_family: chainFamily, + }) + } catch (e) { + // localStorage unavailable, skip tracking + } + })() +</script> + <!-- Google Tag Manager (lazy init on first interaction or idle) --> <script type="text/javascript"> ;(function (w, d, s, l, i) { diff --git a/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenu.tsx b/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenu.tsx index b13f9e55827..a8a65f8f984 100644 --- a/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenu.tsx +++ b/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenu.tsx @@ -1,305 +1,244 @@ -import { evmProducts } from "~/features/landing/data/index.ts" import styles from "./megaMenu.module.css" -import resourcesLogo from "../../../../../assets/product-logos/data-resources-logo.svg" -import { Fragment } from "react/jsx-runtime" -import { useEffect } from "react" +import ccipLogo from "../../../../../assets/product-logos/ccip-logo.svg" +import dataFeedsLogo from "../../../../../assets/product-logos/data-feeds-logo.svg" +import dataStreamsLogo from "../../../../../assets/product-logos/data-streams-logo.svg" +import dataLinkLogo from "../../../../../assets/product-logos/datalink-logo.svg" +import functionsLogo from "../../../../../assets/product-logos/functions-logo.svg" +import automationLogo from "../../../../../assets/product-logos/automation-logo.svg" +import vrfLogo from "../../../../../assets/product-logos/vrf-logo.svg" +import dtaLogo from "../../../../../assets/product-logos/dta-logo.svg" +import generalGlobeLogo from "../../../../../assets/product-logos/general-globe-logo.svg" +import nodesLogo from "../../../../../assets/product-logos/nodes-logo.svg" +import chainlinkLocalLogo from "../../../../../assets/product-logos/chainlink-local-2-logo.svg" +import creLogo from "../../../../../assets/product-logos/cre-logo.svg" +import { Typography } from "@chainlink/blocks" +import { clsx } from "../../utils.ts" -interface MegaMenuProps { - cancel: () => void - id?: string -} - -interface BottomLink { - label: string - href: string -} - -interface Link { - label: string - href?: string +const BlueSquare = () => { + return ( + <div + style={{ + background: "var(--brand)", + height: "5px", + width: "5px", + display: "block", + }} + ></div> + ) } -interface MenuItem { - title?: string - image?: { src: string } - description?: string - learnMoreLink?: string - docsLandingLink?: string - links: Link[] +interface GroupItem { + title: string + description: string + icon: ImageMetadata + link: string } -interface SubSection { - title: string - items: MenuItem[] - bottomLinks?: BottomLink[] +const GroupItem = ({ data }: { data: GroupItem }) => { + return ( + <a href={data.link} className={styles.groupItem}> + <img src={data.icon.src} alt={data.title} className={styles.groupItemIcon} /> + <div> + <Typography variant="body-semi" className={styles.groupItemTitle}> + {data.title} + </Typography> + <Typography color="muted" variant="body-s" className={styles.groupItemDescription}> + {data.description} + </Typography> + </div> + </a> + ) } -interface MegaMenuSection { - title: string - isMultiSection?: boolean - sections?: SubSection[] - items?: MenuItem[] - bottomLinks?: BottomLink[] +const GroupTitle = ({ children }: { children: React.ReactNode }) => { + return ( + <Typography + variant="code-s" + color="muted" + style={{ textTransform: "uppercase", lineHeight: "12px", letterSpacing: "0.6px" }} + > + {children} + </Typography> + ) } -export const megaMenuSections: MegaMenuSection[] = [ - { - title: "Orchestration & Cross-Chain", - isMultiSection: true, - sections: [ - { - title: "Orchestration", - items: [ - { - ...(evmProducts.find((product) => product.title === "CRE") || {}), - links: [ - { - label: "Docs", - href: (evmProducts.find((product) => product.title === "CRE") || {})?.docsLandingLink, - }, - ], - }, - ], - }, +export const megaMenuSections = { + interoperability: { + title: "Interoperability", + items: [ { - title: "Cross-Chain", - items: [ - { - ...(evmProducts.find((product) => product.title === "CCIP") || {}), - links: [ - { - label: "Docs", - href: (evmProducts.find((product) => product.title === "CCIP") || {})?.docsLandingLink, - }, - { - label: "Learn", - href: (evmProducts.find((product) => product.title === "CCIP") || {})?.learnMoreLink, - }, - ], - }, - ], - bottomLinks: [ - { - label: "View all resources", - href: "https://dev.chain.link/resources", - }, - { - label: "Learn about Chainlink", - href: "https://dev.chain.link/products/general", - }, - ], + icon: ccipLogo, + title: "Cross-Chain Communication", + description: "Move data and value across any blockchain", + link: "/ccip", }, ], }, - { + data: { title: "Data", items: [ { - ...evmProducts.find((product) => product.title === "Data Feeds"), - title: "Data Feeds", - links: [ - { - label: "Docs", - href: (evmProducts.find((product) => product.title === "Data Feeds") || {})?.docsLandingLink, - }, - { - label: "Learn", - href: (evmProducts.find((product) => product.title === "Data Feeds") || {})?.learnMoreLink, - }, - ], + icon: dataStreamsLogo, + title: "Data Streams", + description: "Access high-frequency market data for next-gen DeFi", + link: "/data-streams", }, - { - ...evmProducts.find((product) => product.title === "Data Streams"), - title: "Data Streams", - links: [ - { - label: "Docs", - href: (evmProducts.find((product) => product.title === "Data Streams") || {})?.docsLandingLink, - }, - { - label: "Learn", - href: (evmProducts.find((product) => product.title === "Data Streams") || {})?.learnMoreLink, - }, - ], + icon: dataFeedsLogo, + title: "Market and Data Feeds", + description: "Utilize ultra-secure onchain data for smart contracts", + link: "/data-feeds", }, - { - title: "Data resources", - image: resourcesLogo, - description: "Global standard for building secure cross-chain applications.", - learnMoreLink: "data-feeds", - links: [ - { - label: "Learn", - href: "https://dev.chain.link/products/data", - }, - ], + icon: dataLinkLogo, + title: "DataLink", + description: "Publish and commercialize institutional data across...", + link: "/datalink", }, ], }, - { + assetManagement: { + title: "Asset Management", + items: [ + { + icon: dtaLogo, + title: "Digital Transfer Agent (DTA) Technical Standard", + description: "Unlock streamlined tokenized fund operations", + link: "/dta-technical-standard", + }, + ], + }, + compute: { title: "Compute", items: [ { - ...evmProducts.find((product) => product.title === "Automation"), - links: [ - { - label: "Docs", - href: (evmProducts.find((product) => product.title === "Automation") || {})?.docsLandingLink, - }, - { - label: "Learn", - href: (evmProducts.find((product) => product.title === "Automation") || {})?.learnMoreLink, - }, - ], + icon: functionsLogo, + title: "Functions", + description: "Connect smart contracts to any API", + link: "/chainlink-functions", }, { - ...evmProducts.find((product) => product.title === "Functions"), - links: [ - { - label: "Docs", - href: (evmProducts.find((product) => product.title === "Functions") || {})?.docsLandingLink, - }, - { - label: "Learn", - href: (evmProducts.find((product) => product.title === "Functions") || {})?.learnMoreLink, - }, - ], + icon: automationLogo, + title: "Automation", + description: "Automate smart contracts via decentralized triggers", + link: "/chainlink-automation", }, { - ...evmProducts.find((product) => product.title === "VRF"), - links: [ - { - label: "Docs", - href: (evmProducts.find((product) => product.title === "VRF") || {})?.docsLandingLink, - }, - { - label: "Learn", - href: (evmProducts.find((product) => product.title === "VRF") || {})?.learnMoreLink, - }, - ], + icon: vrfLogo, + title: "VRF", + description: "Ensure fair outcomes in games, NFTs, and more", + link: "/vrf", }, ], }, -] - -function MegaMenu({ cancel, id }: MegaMenuProps) { - useEffect(() => { - const onESC = (ev: KeyboardEvent) => { - if (ev.key === "Escape") { - cancel() - } - } - window.addEventListener("keyup", onESC, false) - return () => { - window.removeEventListener("keyup", onESC, false) - } - }, []) + orchestration: { + title: "Orchestration", + items: [ + { + icon: creLogo, + title: "Chainlink Runtime Environment (CRE)", + description: "The global orchestration layer", + link: "/cre", + }, + ], + }, + other: { + title: "More", + items: [ + { + icon: generalGlobeLogo, + title: "General", + description: "Foundational Chainlink knowledge", + link: "/getting-started/conceptual-overview", + }, + { + icon: nodesLogo, + title: "Nodes", + description: "Be part of the Chainlink Network", + link: "/", + }, + { + icon: chainlinkLocalLogo, + title: "Chainlink local", + description: "Run services locally before transitioning to a testnet", + link: "/chainlink-local", + }, + ], + }, +} +function MegaMenu({ cancel, isMobile }: { cancel?: () => void; isMobile?: boolean }) { return ( - <div className={styles.megaMenuContainer} id={id}> - <div className={styles.wrapper} onMouseLeave={cancel}> - <div className={styles.resourcesMenuContentMain}> - {megaMenuSections.map((section) => ( - <div className={styles.resourcesMenuContentRow} key={section.title}> - {section.isMultiSection && section.sections ? ( - <> - {section.sections.map((subSection) => ( - <Fragment key={subSection.title}> - <h2 className="label">{subSection.title}</h2> - {subSection.items.map((item, index) => ( - <Fragment key={index}> - <div className={styles.megaMenuLink}> - {item?.image?.src && <img src={item.image.src} alt={item.title} />} - <h3 className="heading-100">{item.title}</h3> - </div> - <div className={styles.links}> - <p className="paragraph-100">{item.description}</p> - {item.links.map((link, linkIndex) => ( - <Fragment key={linkIndex}> - <a href={link.href} className="text-100"> - {link.label} - </a> - {linkIndex < item.links.length - 1 && <span className={styles.verticalDivider}></span>} - </Fragment> - ))} - </div> - </Fragment> - ))} - {subSection.bottomLinks && ( - <div className={styles.bottomLinks}> - {subSection.bottomLinks.map((link, linkIndex) => ( - <div className="label" key={linkIndex}> - <a href={link.href} target="_blank" rel="noopener noreferrer"> - {link.label} - </a> - <img src="/images/tabler_arrow-up.svg" alt="" /> - </div> - ))} - </div> - )} - </Fragment> - ))} - </> - ) : ( - <> - <h2 className="label">{section.title}</h2> - {section.items?.map((item, index) => ( - <Fragment key={index}> - <div className={styles.megaMenuLink}> - {item?.image?.src && <img src={item.image.src} alt={item.title} />} - <h3 className="heading-100">{item.title}</h3> - </div> - <div className={styles.links}> - <p className="paragraph-100">{item.description}</p> - {item.links.map((link, linkIndex) => ( - <Fragment key={linkIndex}> - <a href={link.href} className="text-100"> - {link.label} - </a> - {linkIndex < item.links.length - 1 && <span className={styles.verticalDivider}></span>} - </Fragment> - ))} - </div> - </Fragment> - ))} - {"bottomLinks" in section && section.bottomLinks && ( - <div className={styles.bottomLinks}> - {section.bottomLinks.map((link, linkIndex) => ( - <div className="label" key={linkIndex}> - <a href={link.href} target="_blank" rel="noopener noreferrer"> - {link.label} - </a> - <img src="/images/tabler_arrow-up.svg" alt="" /> - </div> - ))} - </div> - )} - </> - )} - </div> - ))} + <div className={clsx(styles.wrapper, isMobile && styles.mobile)} onMouseLeave={cancel}> + <div className={styles.row}> + <div className={styles.section}> + <header> + <BlueSquare /> + <GroupTitle>{megaMenuSections.orchestration.title}</GroupTitle> + </header> + <li className={styles.itemList}> + {megaMenuSections.orchestration.items.map((link) => ( + <GroupItem key={link.title} data={link} /> + ))} + </li> </div> - <div className={styles.resourcesMenuContentFeatured}> - <h2 className="label">Featured</h2> - <a href="/chainlink-local"> - <img src="/images/megamenu-featured.jpg" alt="" className={styles.featuredImage} /> - </a> - <div className={styles.divider}></div> + <div className={styles.section}> + <header> + <BlueSquare /> + <GroupTitle>{megaMenuSections.interoperability.title}</GroupTitle> + </header> + <li className={styles.itemList}> + {megaMenuSections.interoperability.items.map((link) => ( + <GroupItem key={link.title} data={link} /> + ))} + </li> + </div> + <div className={styles.section}> + <header> + <BlueSquare /> + <GroupTitle>{megaMenuSections.assetManagement.title}</GroupTitle> + </header> + <li className={styles.itemList}> + {megaMenuSections.assetManagement.items.map((link) => ( + <GroupItem key={link.title} data={link} /> + ))} + </li> + </div> + </div> - <h3 className="heading-100">Hardhat CLI for Data Streams</h3> - <div className={styles.links}> - <a href="/data-streams/getting-started-hardhat" className="text-100"> - Docs - </a> - </div> - <h3 className="heading-100">Try out Chainlink Automation</h3> - <div className={styles.links}> - <a href="/chainlink-automation/overview/getting-started" className="text-100"> - Docs - </a> - </div> + <div className={styles.row}> + <div className={styles.section}> + <header> + <BlueSquare /> + <GroupTitle>{megaMenuSections.data.title}</GroupTitle> + </header> + <li className={styles.itemList}> + {megaMenuSections.data.items.map((link) => ( + <GroupItem key={link.title} data={link} /> + ))} + </li> + </div> + <div className={styles.section}> + <header> + <BlueSquare /> + <GroupTitle>{megaMenuSections.compute.title}</GroupTitle> + </header> + <li className={styles.itemList}> + {megaMenuSections.compute.items.map((link) => ( + <GroupItem key={link.title} data={link} /> + ))} + </li> + </div> + <div className={styles.section}> + <header> + <BlueSquare /> + <GroupTitle>{megaMenuSections.other.title}</GroupTitle> + </header> + <li className={styles.itemList}> + {megaMenuSections.other.items.map((link) => ( + <GroupItem key={link.title} data={link} /> + ))} + </li> </div> </div> </div> diff --git a/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenuContainer.tsx b/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenuContainer.tsx new file mode 100644 index 00000000000..17a6a2a25ce --- /dev/null +++ b/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenuContainer.tsx @@ -0,0 +1,27 @@ +import { useEffect } from "react" +import styles from "./megaMenu.module.css" + +interface MegaMenuProps { + cancel: () => void + id?: string + children?: React.ReactNode +} + +export default function MegaMenuContainer({ cancel, id, children }: MegaMenuProps) { + useEffect(() => { + const onESC = (ev: KeyboardEvent) => { + if (ev.key === "Escape") { + cancel() + } + } + window.addEventListener("keyup", onESC, false) + return () => { + window.removeEventListener("keyup", onESC, false) + } + }, []) + return ( + <div className={styles.megaMenuContainer} id={id}> + {children} + </div> + ) +} diff --git a/src/components/Header/Nav/ProductNavigation/Desktop/ProductNavigation.tsx b/src/components/Header/Nav/ProductNavigation/Desktop/ProductNavigation.tsx index c6e0768cb9f..ffc10e66500 100644 --- a/src/components/Header/Nav/ProductNavigation/Desktop/ProductNavigation.tsx +++ b/src/components/Header/Nav/ProductNavigation/Desktop/ProductNavigation.tsx @@ -6,6 +6,7 @@ import { extendRadixComponent } from "../extendRadixComponent.ts" import styles from "./productNavigation.module.css" import { CaretIcon } from "../CaretIcon.tsx" import MegaMenu from "./MegaMenu.tsx" +import MegaMenuContainer from "./MegaMenuContainer.tsx" type Props = { setNavMenuOpen: (navMenuOpen: boolean) => void @@ -42,27 +43,20 @@ export const ProductNavigation = ({ setNavMenuOpen, showMegaMenu, isMegamenuOpen <> <Root className={clsx(styles.root, styles.alignLeft)}> <List className={styles.list}> - <Item> + <Item onMouseEnter={exitMegamenu}> <a - className={clsx(styles.navLink, { - [styles.megaMenu]: isMegamenuOpen, - })} + className={clsx(styles.navLink)} onMouseEnter={showMegaMenu} role="button" aria-expanded={isMegamenuOpen} aria-controls="mega-menu" - aria-label="Resources menu" + aria-label="Docs menu" tabIndex={0} onKeyDown={handleKeyDown} > - Resources <CaretIcon aria-hidden /> + Docs <CaretIcon aria-hidden /> </a> </Item> - <Item onMouseEnter={exitMegamenu}> - <NavigationMenu.Link className={clsx(styles.navLink, styles.active)} href="/"> - Docs - </NavigationMenu.Link> - </Item> <Item> <NavigationMenu.Link className={styles.navLink} href="https://dev.chain.link/demos"> Demos @@ -74,17 +68,21 @@ export const ProductNavigation = ({ setNavMenuOpen, showMegaMenu, isMegamenuOpen </NavigationMenu.Link> </Item> <Item> - <NavigationMenu.Link className={styles.navLink} href="https://dev.chain.link/changelog"> + <NavigationMenu.Link className={styles.navLink} href="/changelog"> Changelog </NavigationMenu.Link> </Item> <Item> - <NavigationMenu.Link className={styles.navLink} href="https://dev.chain.link/certification"> + <NavigationMenu.Link className={styles.navLink} href="/certification"> Get Certified </NavigationMenu.Link> </Item> </List> - {isMegamenuOpen && <MegaMenu id="mega-menu" cancel={exitMegamenu} />} + {isMegamenuOpen && ( + <MegaMenuContainer id="mega-menu" cancel={exitMegamenu}> + <MegaMenu cancel={exitMegamenu} /> + </MegaMenuContainer> + )} </Root> </> ) diff --git a/src/components/Header/Nav/ProductNavigation/Desktop/megaMenu.module.css b/src/components/Header/Nav/ProductNavigation/Desktop/megaMenu.module.css index 83ba42a3509..f586d708886 100644 --- a/src/components/Header/Nav/ProductNavigation/Desktop/megaMenu.module.css +++ b/src/components/Header/Nav/ProductNavigation/Desktop/megaMenu.module.css @@ -9,15 +9,8 @@ justify-content: center; } -.wrapper { - max-width: 1360px; - width: 100%; - background-color: white; - height: fit-content; - border-radius: 0.5rem; - display: grid; - grid-template-columns: 3fr 1fr; - overflow: hidden; +/* applies shadow to dropdown version of mega-menu */ +.megaMenuContainer > .wrapper { box-shadow: 4.6px 9.3px 54px 1px rgba(152, 160, 185, 0.04), 2.1px 4.3px 32px -0.7px rgba(152, 160, 185, 0.31), @@ -25,108 +18,105 @@ 0.3px 0.5px 0.8px 0px rgba(152, 160, 185, 0.12); } -.wrapper h2 { - padding-bottom: var(--space-4x); - color: var(--gray-500); - text-transform: uppercase; - border-bottom: 1px solid var(--gray-200); - margin-bottom: var(--space-8x); -} +.wrapper { + max-width: 1500px; + width: 100%; + background-color: white; + height: fit-content; + overflow: hidden; + display: flex; + flex-direction: column; -.wrapper h3 { - font-family: var(--font-family-text); - color: var(--gray-900); + border: 1px solid var(--border); } -.wrapper p { - color: var(--gray-500); - margin-top: var(--space-2x); - margin-bottom: var(--space-3x); - line-height: var(--space-6x); +.row { + display: grid; + grid-template-columns: repeat(3, 1fr); } -.resourcesMenuContentMain { - padding-top: var(--space-16x); - padding-left: var(--space-16x); - padding-bottom: var(--space-16x); - padding-right: var(--space-8x); - display: grid; - grid-template-columns: 1fr 1fr 1fr; - gap: var(--space-16x); +.row:last-child { + border-bottom: none; } -.resourcesMenuContentRow { +.wrapper header { display: flex; - flex-direction: column; + align-items: center; + gap: var(--space-3x); + padding: var(--space-4x) var(--space-6x); } -.verticalDivider { - border-left: 1px solid var(--gray-300); - margin: 0 var(--space-3x); +.wrapper p { + margin-bottom: 0; } -.links { - margin-bottom: var(--space-10x); +.section { + display: flex; + flex-direction: column; + border-right: 1px solid var(--border); } -.links a { - font-weight: var(--font-weight-medium); - color: var(--color-text-link); +.section:last-child { + border-right: none; } -.resourcesMenuContentFeatured { - padding-top: var(--space-16x); - padding-left: var(--space-8x); - padding-bottom: var(--space-16x); - padding-right: var(--space-16x); - background-color: var(--gray-100); +.section header { + border-bottom: 1px solid var(--border); } -.megaMenuLink { +.groupItem { display: flex; align-items: center; - gap: var(--space-2x); -} - -.megaMenuLink h3 { - margin-bottom: 0; + padding: var(--space-4x) var(--space-6x); + gap: var(--space-4x); + text-decoration: none; + transition: background-color 0.2s; } -.megaMenuLink img { - width: var(--space-5x); - height: var(--space-5x); +.groupItem:hover { + background-color: var(--muted); } -.featuredImage { - width: 100%; +.groupItemIcon { + width: 24px; + height: 24px; + flex-shrink: 0; } -.divider { - border-bottom: 1px solid var(--gray-200); - margin: var(--space-8x) auto; -} - -.bottomLinks { - margin-top: auto; +.itemList { display: flex; flex-direction: column; - gap: var(--space-3x); + padding: var(--space-2x); } -.bottomLinks div { - display: flex; - align-items: center; - gap: var(--space-2x); - line-height: var(--space-6x); +.groupItemTitle { + font-size: 18px; + font-weight: 500; } -.bottomLinks a { - color: var(--gray-900); -} +.wrapper.mobile { + border: none; + overflow: unset; + + & .row { + grid-template-columns: 1fr; + border-bottom: none; + } -/* TODO: change with a var when available in the chainlink repo */ -.bottomLink a:hover { - color: #0847f7; + & .section header { + border-bottom: 1px solid var(--border); + border-top: 1px solid var(--border); + } + + & .section { + border-right: none; + } + + & .itemList { + padding-top: var(--space-0); + padding-left: var(--space-0); + padding-right: var(--space-0); + } } @media screen and (min-width: 768px) { diff --git a/src/components/Header/Nav/ProductNavigation/Desktop/productNavigation.module.css b/src/components/Header/Nav/ProductNavigation/Desktop/productNavigation.module.css index 4057b7ac853..048809c260c 100644 --- a/src/components/Header/Nav/ProductNavigation/Desktop/productNavigation.module.css +++ b/src/components/Header/Nav/ProductNavigation/Desktop/productNavigation.module.css @@ -57,19 +57,6 @@ opacity: 1; } -.megaMenu::after { - content: ""; - position: absolute; - bottom: -35px; - right: 35%; - transform: translateX(-50%) rotate(45deg); - width: 20px; - height: 20px; - z-index: 100; - background-color: white; - padding: var(--space-2x); -} - @media screen and (min-width: 992px) { .root { display: flex; diff --git a/src/components/Header/Nav/ProductNavigation/Mobile/ProductNavigation.tsx b/src/components/Header/Nav/ProductNavigation/Mobile/ProductNavigation.tsx index dc0f0371d88..d1e89e453e6 100644 --- a/src/components/Header/Nav/ProductNavigation/Mobile/ProductNavigation.tsx +++ b/src/components/Header/Nav/ProductNavigation/Mobile/ProductNavigation.tsx @@ -6,7 +6,7 @@ import styles from "./productNavigation.module.css" import { MenuIcon } from "./MenuIcon.tsx" import { BackArrowIcon } from "./BackArrowIcon.tsx" import { CaretRightIcon } from "./CaretRightIcon.tsx" -import MegaMenu from "./MegaMenu.tsx" +import MegaMenu from "../Desktop/MegaMenu.tsx" const Trigger = extendRadixComponent(Dialog.Trigger) const Close = extendRadixComponent(Dialog.Close) @@ -71,24 +71,22 @@ export function ProductNavigation() { className={styles.productContentLink} onClick={() => setProductsSlidePosition("submenu")} data-testid="sub-product-navigation-trigger-mobile" - aria-label="Open Resources submenu" + aria-label="Open Docs submenu" > - Resources + Docs <CaretRightIcon /> </button> - <a href="/" className={styles.productContentLink}> - Docs - </a> + <a href="https://dev.chain.link/demos" className={styles.productContentLink}> Demos </a> <a href="https://dev.chain.link/tools" className={styles.productContentLink}> Tools </a> - <a href="https://dev.chain.link/changelog" className={styles.productContentLink}> + <a href="/changelog" className={styles.productContentLink}> Changelog </a> - <a href="https://dev.chain.link/certification" className={styles.productContentLink}> + <a href="/certification" className={styles.productContentLink}> Get Certified </a> </ul> @@ -103,11 +101,11 @@ export function ProductNavigation() { > <BackArrowIcon /> </button> - <span className={styles.subProductContentTitle}>Resources</span> + <span className={styles.subProductContentTitle}>Docs</span> <span></span> {/* Spacer */} </div> <div className={styles.subProductContent}> - <MegaMenu /> + <MegaMenu isMobile /> </div> </div> </div> diff --git a/src/components/Header/Nav/ProductNavigation/Mobile/productNavigation.module.css b/src/components/Header/Nav/ProductNavigation/Mobile/productNavigation.module.css index 5994b36a9e4..b3bb2b4c22c 100644 --- a/src/components/Header/Nav/ProductNavigation/Mobile/productNavigation.module.css +++ b/src/components/Header/Nav/ProductNavigation/Mobile/productNavigation.module.css @@ -34,6 +34,7 @@ width: 200vw; display: flex; transition: transform 0.3s; + height: 100%; } .main { @@ -71,11 +72,11 @@ overflow: scroll; list-style: none; width: 100vw; - padding-bottom: 56px; } .subProductContent { display: flex; flex-direction: column; + height: 100%; } .subProductContentTitle { diff --git a/src/components/Header/Nav/navBar.module.css b/src/components/Header/Nav/navBar.module.css index 7b8a629ffad..643ac110ed9 100644 --- a/src/components/Header/Nav/navBar.module.css +++ b/src/components/Header/Nav/navBar.module.css @@ -1,11 +1,11 @@ -/* +/* * Navigation bar styles - * + * * The navigation uses a fixed header with blur effect and contains: * 1. Logo section (left) * 2. Menu section (center) * 3. Right section with actions - * + * * Responsive breakpoints: * - Mobile: < 992px * - Desktop: >= 992px @@ -96,7 +96,6 @@ display: flex; justify-content: center; align-items: center; - z-index: 10; } .modalContentWrapper { diff --git a/src/components/Header/NavBar.tsx b/src/components/Header/NavBar.tsx index 404af835727..108ab4c6cd7 100644 --- a/src/components/Header/NavBar.tsx +++ b/src/components/Header/NavBar.tsx @@ -35,13 +35,9 @@ export const NavBar = ({ / - if the page has been scrolled down and the header is hidden / - if the page is a inner doc page or part of the "pathWithoutDocNav" or not */ - const innerDocNavHeight = 56 - let height = (navRef.current as HTMLElement).clientHeight - let baseHeightNoNav = 0 - if (doubleNavbar()) { - height += innerDocNavHeight - baseHeightNoNav += innerDocNavHeight - } + const height = (navRef.current as HTMLElement).clientHeight + const baseHeightNoNav = 0 + const elements = document.body.querySelectorAll("[data-sticky]") elements.forEach((e: HTMLElement) => { if (!e.classList.contains(styles.animateTop)) { diff --git a/src/components/JourneyCards/JourneyCards.astro b/src/components/JourneyCards/JourneyCards.astro new file mode 100644 index 00000000000..0d16686ecad --- /dev/null +++ b/src/components/JourneyCards/JourneyCards.astro @@ -0,0 +1,134 @@ +--- +import { JourneyCardsDesktop } from "./JourneyCardsDesktop.tsx" +import { JourneyTabGrid } from "./JourneyTabGrid.tsx" + +const columns = [ + { + title: "Learn & Explore", + items: [ + { + title: "Explore Cross-Chain Interoperability with CCIP", + description: "Learn cross-chain concepts, workflows, and real-world use cases.", + badge: "ccip", + href: "/", + }, + { + title: "Understand How Data Feeds Power dApps", + description: "See how oracle data feeds deliver price feeds and reference data.", + badge: "data feeds", + href: "/", + }, + { + title: "Learn How Data Streams Deliver Real-Time Data", + description: "Understand how low-latency streams support time-sensitive applications.", + badge: "data streams", + href: "/", + }, + { + title: "Discover Off-Chain Compute with Functions", + description: "Learn how Functions connect smart contracts to APIs and custom logic.", + badge: "functions", + href: "/", + }, + ], + }, + { + title: "Build & Integrate", + items: [ + { + title: "Build Cross-Chain Apps with CCIP Tutorials", + description: "Follow step-by-step guides with language switching (EVM, Rust, Move, etc.).", + badge: "ccip", + href: "/", + }, + { + title: "Integrate Data Feeds into Smart Contracts", + description: "Plug feeds into your apps with examples and addresses.", + badge: "data feeds", + href: "/", + }, + { + title: "Implement Real-Time Use Cases with Data Streams", + description: "Use low-latency data in trading, gaming, and other live applications.", + badge: "data streams", + href: "/", + }, + { + title: "Connect Contracts to APIs with Functions", + description: "Add external data and custom logic to your dApps.", + badge: "functions", + href: "/", + }, + ], + }, + { + title: "Operate & Scale", + items: [ + { + title: "Monitor CCIP Transactions in Real Time", + description: "Track the progress and status of cross-chain transactions.", + badge: "ccip", + href: "/", + }, + { + title: "Stay Up to Date with Data Feeds", + description: "Rely on changelogs and schema updates for accuracy.", + badge: "data feeds", + href: "/", + }, + { + title: "Deliver Reliable Low-Latency Data with Streams", + description: "Operate Data Streams at scale for critical, time-sensitive use cases.", + badge: "data streams", + href: "/", + }, + { + title: "Scale and Optimize Functions", + description: "Debug, manage workloads, and grow your applications.", + badge: "functions", + href: "/", + }, + ], + }, +] + +// Transform columns to tabs format for JourneyTabGrid +const tabs = columns.map((column) => ({ + name: column.title, + items: column.items.map((item) => ({ + title: item.title, + description: item.description, + link: item.href, + badge: item.badge, + })), +})) +--- + +<section> + <section class="desktop"> + <JourneyCardsDesktop columns={columns} client:load /> + </section> + <section class="mobile"> + <JourneyTabGrid header="Start your Chainlink journey" tabs={tabs} client:only="react" /> + </section> +</section> + +<style> + .desktop { + display: none; + } + + .mobile { + display: block; + } + + @media (min-width: 769px) { + .desktop { + display: block; + } + + .mobile { + display: none; + } + } +</style> diff --git a/src/components/JourneyCards/JourneyCardsDesktop.module.css b/src/components/JourneyCards/JourneyCardsDesktop.module.css new file mode 100644 index 00000000000..1270644aae2 --- /dev/null +++ b/src/components/JourneyCards/JourneyCardsDesktop.module.css @@ -0,0 +1,159 @@ +.container { + width: 100%; +} + +.header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--space-10x); + gap: var(--space-4x); + flex-wrap: wrap; +} + +.sectionTitle { + font-size: 28px; + margin: 0; +} + +.filterWrapper { + display: flex; + align-items: center; + gap: var(--space-2x); +} + +.journeyRows { + display: flex; + flex-direction: column; +} + +.journeyRow { + display: grid; + grid-template-columns: repeat(3, 1fr); +} + +.journeyCard { + gap: var(--space-6x); + padding: var(--space-6x); + display: block; + text-decoration: none; + color: inherit; + transition: background-color 0.2s ease; + border-left: 1px solid var(--border); +} + +.journeyCard:hover { + background-color: var(--muted); +} + +.journeyCard:hover .footerTag { + background-color: var(--background) !important; +} + +.journeyCard:hover .footerIcon { + opacity: 1; +} + +.cardContent { + display: flex; + flex-direction: column; + gap: var(--space-2x); + margin-bottom: var(--space-8x); +} + +.journeyFooter { + display: flex; + align-items: center; + justify-content: space-between; +} + +.footerTag { + text-transform: uppercase; +} + +.footerIcon { + height: 12px; + width: 12px; + opacity: 0; + transition: opacity 0.2s ease; +} + +.columnHeader { + padding: var(--space-2x) var(--space-6x); + border-left: 3px solid var(--brand); +} + +.columnTitle { + font-size: 22px; + line-height: 26px; + margin: 0; +} + +.noResults { + padding: var(--space-10x); + text-align: center; +} + +.paginationControls { + display: flex; + align-items: center; + justify-content: flex-end; + margin-top: var(--space-2x); +} + +.paginationButton { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + min-width: 40px; + max-width: 40px; + min-height: 40px; + max-height: 40px; + padding: var(--space-4x, 14px); + border: 1px solid var(--border); + background-color: var(--background); + color: var(--foreground); + border-radius: 4px; + cursor: pointer; + font-size: 12px; + transition: all 0.2s ease; +} + +.paginationButton svg { + display: block; + flex-shrink: 0; +} + +.paginationButton:hover:not(:disabled) { + background-color: var(--muted); + border-color: var(--brand); + color: var(--brand); +} + +.paginationButton:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +@media screen and (min-width: 62em) { + .sectionTitle { + font-size: 32px; + } +} + +@media (max-width: 768px) { + .header { + flex-direction: column; + align-items: flex-start; + } + + .filterWrapper { + width: 100%; + } + + .journeyRow { + grid-template-columns: 1fr; + } +} diff --git a/src/components/JourneyCards/JourneyCardsDesktop.tsx b/src/components/JourneyCards/JourneyCardsDesktop.tsx new file mode 100644 index 00000000000..6178e4177af --- /dev/null +++ b/src/components/JourneyCards/JourneyCardsDesktop.tsx @@ -0,0 +1,197 @@ +import { useState, useMemo, useEffect } from "react" +import { Typography, Tag } from "@chainlink/blocks" +import styles from "./JourneyCardsDesktop.module.css" +import { ProductFilterDropdown } from "./ProductFilterDropdown.tsx" +import { PaginationControls } from "./PaginationControls.tsx" + +export interface JourneyItem { + title: string + description: string + badge: string + href: string +} + +export interface JourneyColumn { + title: string + items: JourneyItem[] +} + +interface JourneyCardsDesktopProps { + columns: JourneyColumn[] +} + +// Product filter options +const PRODUCT_FILTERS = [ + { label: "All Products", value: "all" }, + { label: "Automation", value: "automation" }, + { label: "CCIP", value: "ccip" }, + { label: "CRE", value: "cre" }, + { label: "DataLink", value: "datalink" }, + { label: "Data Feeds", value: "data feeds" }, + { label: "Data Streams", value: "data streams" }, + { label: "DTA", value: "dta" }, + { label: "Functions", value: "functions" }, + { label: "VRF", value: "vrf" }, +] + +type ProductFilterValue = (typeof PRODUCT_FILTERS)[number]["value"] + +// Validate badge values against expected product types +const VALID_BADGE_VALUES = new Set([ + "automation", + "ccip", + "cre", + "datalink", + "data feeds", + "data streams", + "dta", + "functions", + "vrf", +]) + +function validateBadge(badge: string): boolean { + return VALID_BADGE_VALUES.has(badge) +} + +const ITEMS_PER_PAGE = 4 + +export const JourneyCardsDesktop = ({ columns }: JourneyCardsDesktopProps) => { + const [selectedFilters, setSelectedFilters] = useState<ProductFilterValue[]>(["all"]) + const [currentPage, setCurrentPage] = useState(0) + + // Filter columns based on selected products + const filteredColumns = useMemo(() => { + // If "all" is selected or no filters selected, show all items + if (selectedFilters.includes("all") || selectedFilters.length === 0) { + return columns + } + + return columns + .map((column) => ({ + ...column, + items: column.items.filter((item) => { + // Validate badge value + if (!validateBadge(item.badge)) { + console.warn(`Invalid badge value: ${item.badge}`) + return false + } + // Show item if it matches ANY of the selected filters (OR logic) + return selectedFilters.some((filter) => item.badge.toLowerCase() === filter.toLowerCase()) + }), + })) + .filter((column) => column.items.length > 0) // Hide columns with no matching cards + }, [columns, selectedFilters]) + + // Transform columns to rows (row-based layout) with pagination + const rows = useMemo(() => { + if (filteredColumns.length === 0) return [] + + const maxItems = Math.max(...filteredColumns.map((col) => col.items.length)) + const maxPage = Math.max(0, Math.ceil(maxItems / ITEMS_PER_PAGE) - 1) + + // Clamp currentPage to valid bounds to prevent flash of empty content + const validPage = Math.min(currentPage, maxPage) + + const startIndex = validPage * ITEMS_PER_PAGE + const endIndex = startIndex + ITEMS_PER_PAGE + + // Slice items from each column based on current page + const paginatedColumns = filteredColumns.map((col) => ({ + ...col, + items: col.items.slice(startIndex, endIndex), + })) + + const maxPaginatedItems = Math.max(...paginatedColumns.map((col) => col.items.length)) + return Array.from({ length: maxPaginatedItems }, (_, rowIndex) => ({ + id: `row-${rowIndex}`, + items: paginatedColumns.map((col) => col.items[rowIndex]).filter(Boolean), + })) + }, [filteredColumns, currentPage]) + + // Calculate total pages based on max items across all columns + const totalPages = useMemo(() => { + if (filteredColumns.length === 0) return 0 + const maxItems = Math.max(...filteredColumns.map((col) => col.items.length)) + return Math.ceil(maxItems / ITEMS_PER_PAGE) + }, [filteredColumns]) + + // Reset pagination when filters change + useEffect(() => { + setCurrentPage(0) + }, [filteredColumns]) + + const handlePreviousPage = () => { + setCurrentPage((prev) => Math.max(0, prev - 1)) + } + + const handleNextPage = () => { + setCurrentPage((prev) => Math.min(totalPages - 1, prev + 1)) + } + + return ( + <div className={styles.container}> + <div className={styles.header}> + <Typography variant="h4" className={styles.sectionTitle}> + Start your Chainlink journey + </Typography> + <div className={styles.filterWrapper}> + <ProductFilterDropdown + selectedFilters={selectedFilters} + onFiltersChange={setSelectedFilters} + options={PRODUCT_FILTERS} + /> + </div> + </div> + + {filteredColumns.length > 0 ? ( + <div className={styles.journeyRows}> + <div className={styles.journeyRow}> + {filteredColumns.map((column) => ( + <header key={column.title} className={styles.columnHeader}> + <Typography variant="h5" className={styles.columnTitle}> + {column.title} + </Typography> + </header> + ))} + </div> + {rows.map((row) => ( + <div key={row.id} className={styles.journeyRow}> + {row.items.map((item) => ( + <a key={item.href} href={item.href} className={styles.journeyCard}> + <div className={styles.cardContent}> + <Typography variant="body-semi">{item.title}</Typography> + <Typography variant="body-s" color="muted"> + {item.description} + </Typography> + </div> + + <footer className={styles.journeyFooter}> + <Tag size="sm" className={styles.footerTag}> + <Typography variant="code-s">{item.badge}</Typography> + </Tag> + <img src="/assets/icons/upper-right-arrow.svg" className={styles.footerIcon} alt="" /> + </footer> + </a> + ))} + </div> + ))} + + <PaginationControls + currentPage={currentPage} + totalPages={totalPages} + onPrevious={handlePreviousPage} + onNext={handleNextPage} + containerClassName={styles.paginationControls} + buttonClassName={styles.paginationButton} + /> + </div> + ) : ( + <div className={styles.noResults}> + <Typography variant="body" color="muted"> + No journey cards match the selected filter. + </Typography> + </div> + )} + </div> + ) +} diff --git a/src/components/JourneyCards/JourneyTabGrid.module.css b/src/components/JourneyCards/JourneyTabGrid.module.css new file mode 100644 index 00000000000..39bc9c5012e --- /dev/null +++ b/src/components/JourneyCards/JourneyTabGrid.module.css @@ -0,0 +1,124 @@ +/* Tab styling - copied from TabGrid */ +.gridHeader { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--space-8x); + flex-wrap: wrap; + gap: var(--space-8x); +} + +.tabsTrigger { + height: 32px; + padding: var(--space-1x) var(--space-2x); + justify-content: center; + align-items: center; + border-radius: var(--space-2x); + background-color: var(--pill); + border: 1px solid var(--pill-border); +} + +.tabsTrigger:hover { + background-color: var(--pill-hover); +} + +.tabsTrigger[data-state="active"] { + background-color: var(--pill-active); + border-color: var(--pill-active); + border-bottom: 1px solid var(--pill-active); + + & h3 { + color: var(--pill-active-foreground); + } +} + +.tabTitle { + color: var(--pill-foreground); + font-weight: 400; +} + +.tabsList { + display: flex; + gap: var(--space-2x); + border-bottom: 0; + flex-wrap: wrap; + justify-content: start !important; +} + +.journeyGrid { + display: grid; + grid-template-columns: 1fr; + border-left: 1px solid var(--border); + border-top: 1px solid var(--border); +} + +.journeyCard { + display: flex; + flex-direction: column; + gap: var(--space-6x); + padding: var(--space-6x); + border-right: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} + +.journeyCard:hover { + background-color: var(--muted); + + .footerTag { + background-color: var(--background); + } + + .footerIcon { + opacity: 1; + } +} + +.cardContent { + display: flex; + flex-direction: column; + gap: var(--space-2x); +} + +.journeyFooter { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: auto; + flex: 1; + width: 100%; +} + +.footerIcon { + height: 12px; + width: 12px; + opacity: 0; +} + +.footerTag { + text-transform: uppercase; +} + +@media (max-width: 768px) { + .journeyGrid { + grid-template-columns: repeat(2, 1fr); + } + .gridHeader > h2 { + font-size: 28px; + } +} + +@media screen and (max-width: 425px) { + .journeyGrid { + grid-template-columns: 1fr; + } + .gridHeader { + margin-bottom: var(--space-6x); + } +} + +@media screen and (max-width: 390px) { + .gridHeader { + flex-direction: column; + align-items: start; + } +} diff --git a/src/components/JourneyCards/JourneyTabGrid.tsx b/src/components/JourneyCards/JourneyTabGrid.tsx new file mode 100644 index 00000000000..610380c3d8e --- /dev/null +++ b/src/components/JourneyCards/JourneyTabGrid.tsx @@ -0,0 +1,153 @@ +import { useState, useMemo, useEffect } from "react" +import styles from "./JourneyTabGrid.module.css" +import { Tabs, TabsContent, TabsList, TabsTrigger, Typography, Tag } from "@chainlink/blocks" +import { ProductFilterDropdown } from "./ProductFilterDropdown.tsx" + +export interface JourneyItem { + title: string + description: string + link: string + badge?: string +} + +export interface JourneyTab { + name: string + items: JourneyItem[] +} + +interface JourneyTabGridProps { + tabs: JourneyTab[] + header: string +} + +// Product filter options +const PRODUCT_FILTERS = [ + { label: "All Products", value: "all" }, + { label: "Automation", value: "automation" }, + { label: "CCIP", value: "ccip" }, + { label: "CRE", value: "cre" }, + { label: "DataLink", value: "datalink" }, + { label: "Data Feeds", value: "data feeds" }, + { label: "Data Streams", value: "data streams" }, + { label: "DTA", value: "dta" }, + { label: "Functions", value: "functions" }, + { label: "VRF", value: "vrf" }, +] + +// Validate badge values against expected product types +const VALID_BADGE_VALUES = new Set([ + "automation", + "ccip", + "cre", + "datalink", + "data feeds", + "data streams", + "dta", + "functions", + "vrf", +]) + +function validateBadge(badge: string): boolean { + return VALID_BADGE_VALUES.has(badge) +} + +export const JourneyTabGrid = ({ tabs, header }: JourneyTabGridProps) => { + const [selectedFilters, setSelectedFilters] = useState<string[]>(["all"]) + const [activeTab, setActiveTab] = useState<string | undefined>() + + // Filter tabs based on selected products + const filteredTabs = useMemo(() => { + // If "all" is selected or no filters selected, show all items + if (selectedFilters.includes("all") || selectedFilters.length === 0) { + return tabs + } + + return tabs + .map((tab) => ({ + ...tab, + items: tab.items.filter((item) => { + if (!item.badge) return false + // Validate badge value + if (!validateBadge(item.badge)) { + console.warn(`Invalid badge value: ${item.badge}`) + return false + } + // Show item if it matches ANY of the selected filters (OR logic) + return selectedFilters.some((filter) => item.badge!.toLowerCase() === filter.toLowerCase()) + }), + })) + .filter((tab) => tab.items.length > 0) // Hide tabs with no matching items + }, [tabs, selectedFilters]) + + // Reset activeTab when filteredTabs changes + useEffect(() => { + setActiveTab(filteredTabs[0]?.name) + }, [filteredTabs]) + + return ( + <Tabs value={activeTab} onValueChange={setActiveTab} className={styles.tabGridWrapper}> + <header className={styles.gridHeader}> + <Typography + variant="h2" + style={{ + fontSize: "32px", + }} + > + {header} + </Typography> + <div style={{ marginTop: "var(--space-4x)", width: "100%" }}> + <ProductFilterDropdown + selectedFilters={selectedFilters} + onFiltersChange={setSelectedFilters} + options={PRODUCT_FILTERS} + /> + </div> + {filteredTabs.length > 0 && ( + <TabsList className={styles.tabsList}> + {filteredTabs.map((tab) => ( + <TabsTrigger key={tab.name} value={tab.name} className={styles.tabsTrigger}> + <h3 className={styles.tabTitle}>{tab.name}</h3> + </TabsTrigger> + ))} + </TabsList> + )} + </header> + + {filteredTabs.length > 0 ? ( + filteredTabs.map((tab) => ( + <TabsContent key={tab.name} value={tab.name}> + <div className={styles.gridContent}> + <div className={styles.journeyGrid}> + {tab.items.map((item) => ( + <a key={item.link} href={item.link} className={styles.journeyCard}> + <div className={styles.cardContent}> + <Typography variant="body-semi">{item.title}</Typography> + <Typography variant="body-s" color="muted"> + {item.description} + </Typography> + </div> + + <footer className={styles.journeyFooter}> + {item.badge && ( + <Tag size="sm" className={styles.footerTag}> + <Typography variant="code-s">{item.badge}</Typography> + </Tag> + )} + <img src="/assets/icons/upper-right-arrow.svg" className={styles.footerIcon} alt="" /> + </footer> + </a> + ))} + </div> + </div> + </TabsContent> + )) + ) : ( + <div style={{ padding: "var(--space-10x)", textAlign: "center" }}> + <Typography variant="body" color="muted"> + No journey cards match the selected filter. + </Typography> + </div> + )} + </Tabs> + ) +} diff --git a/src/components/JourneyCards/PaginationControls.tsx b/src/components/JourneyCards/PaginationControls.tsx new file mode 100644 index 00000000000..80352198ca1 --- /dev/null +++ b/src/components/JourneyCards/PaginationControls.tsx @@ -0,0 +1,57 @@ +interface PaginationControlsProps { + currentPage: number + totalPages: number + onPrevious: () => void + onNext: () => void + containerClassName?: string + buttonClassName?: string +} + +export const PaginationControls = ({ + currentPage, + totalPages, + onPrevious, + onNext, + containerClassName, + buttonClassName, +}: PaginationControlsProps) => { + // Only render when there's more than one page + if (totalPages <= 1) { + return null + } + + return ( + <div className={containerClassName}> + <button onClick={onPrevious} disabled={currentPage === 0} className={buttonClassName} aria-label="Previous page"> + <svg + xmlns="http://www.w3.org/2000/svg" + width="13" + height="10" + viewBox="0 0 13 10" + fill="none" + style={{ transform: "scaleX(-1)" }} + > + <path + d="M0 4.53027H11.25M11.25 4.53027L7.25 8.53027M11.25 4.53027L7.25 0.530273" + stroke="currentColor" + strokeWidth="1.5" + /> + </svg> + </button> + <button + onClick={onNext} + disabled={currentPage === totalPages - 1} + className={buttonClassName} + aria-label="Next page" + > + <svg xmlns="http://www.w3.org/2000/svg" width="13" height="10" viewBox="0 0 13 10" fill="none"> + <path + d="M0 4.53027H11.25M11.25 4.53027L7.25 8.53027M11.25 4.53027L7.25 0.530273" + stroke="currentColor" + strokeWidth="1.5" + /> + </svg> + </button> + </div> + ) +} diff --git a/src/components/JourneyCards/ProductFilterDropdown.module.css b/src/components/JourneyCards/ProductFilterDropdown.module.css new file mode 100644 index 00000000000..3a54d50c977 --- /dev/null +++ b/src/components/JourneyCards/ProductFilterDropdown.module.css @@ -0,0 +1,105 @@ +.dropdown { + position: relative; + width: 148px; +} + +.trigger { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 10px 12px; + max-height: 40px; + background-color: var(--input); + border: 1px solid var(--input-border-active); + border-radius: var(--rounded-sm, 4px); + font-size: 14px; + font-weight: 500; + color: var(--foreground); + cursor: pointer; + transition: all 0.2s ease; +} + +.trigger:hover { + border-color: var(--brand); + background-color: var(--muted); +} + +.trigger:focus { + outline: none; + border-color: var(--brand); + box-shadow: 0 0 0 3px rgba(0, 102, 255, 0.1); +} + +.chevronIcon { + flex-shrink: 0; + transition: transform 0.2s ease; + color: var(--foreground); +} + +.chevronOpen { + transform: rotate(180deg); +} + +.menu { + position: absolute; + top: calc(100% + 4px); + left: 0; + right: 0; + background-color: var(--background); + border: 1px solid var(--border); + border-radius: var(--rounded-sm, 4px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + z-index: 1000; + overflow-y: auto; + padding: 8px 0; + box-shadow: 0 16px 24px 0 rgba(0, 0, 0, 0.04); +} + +.checkboxLabel { + display: flex; + align-items: center; + padding: 12px 16px; + cursor: pointer; + transition: background-color 0.15s ease; + gap: 8px; + user-select: none; + width: 100%; +} + +.checkboxLabel:hover { + background-color: var(--muted); +} + +.checkboxInput { + position: absolute; + opacity: 0; + pointer-events: none; +} + +.customCheckbox { + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + border-radius: var(--rounded-sm, 4px); + border: 1px solid var(--input-border); + background: var(--input); + flex-shrink: 0; + transition: all 0.2s ease; +} + +.checkboxInput:checked + .customCheckbox { + background-color: var(--link); +} + +.checkboxLabel:hover .customCheckbox { + border-color: var(--link); +} + +@media (max-width: 768px) { + .dropdown { + width: 100%; + } +} diff --git a/src/components/JourneyCards/ProductFilterDropdown.tsx b/src/components/JourneyCards/ProductFilterDropdown.tsx new file mode 100644 index 00000000000..26ee7b34fe5 --- /dev/null +++ b/src/components/JourneyCards/ProductFilterDropdown.tsx @@ -0,0 +1,136 @@ +import { useState, useRef } from "react" +import styles from "./ProductFilterDropdown.module.css" +import { Typography } from "@chainlink/blocks" +import { useClickOutside } from "~/hooks/useClickOutside.tsx" + +export interface ProductFilterOption { + label: string + value: string +} + +interface ProductFilterDropdownProps { + selectedFilters: string[] + onFiltersChange: (filters: string[]) => void + options: ProductFilterOption[] +} + +export const ProductFilterDropdown = ({ selectedFilters, onFiltersChange, options }: ProductFilterDropdownProps) => { + const [isOpen, setIsOpen] = useState(false) + const dropdownRef = useRef<HTMLDivElement>(null) + + useClickOutside(dropdownRef, () => setIsOpen(false), { enabled: isOpen }) + + const handleCheckboxChange = (value: string) => { + if (value === "all") { + // When clicking "All Products" + if (selectedFilters.includes("all")) { + // If already checked, uncheck it and default to showing all + onFiltersChange(["all"]) + } else { + // If not checked, check it and clear all individual selections + onFiltersChange(["all"]) + } + } else { + // Handle individual product selection + if (selectedFilters.includes("all")) { + // If "All Products" is currently selected, uncheck it and select only this product + onFiltersChange([value]) + } else { + // "All Products" is not selected, toggle the individual product + if (selectedFilters.includes(value)) { + // Uncheck the item + const updated = selectedFilters.filter((f) => f !== value) + // If no products are selected, default to showing all + onFiltersChange(updated.length === 0 ? ["all"] : updated) + } else { + // Check the item (keep other individual selections) + onFiltersChange([...selectedFilters, value]) + } + } + } + } + + const isChecked = (value: string) => { + if (value === "all") { + return selectedFilters.includes("all") + } + // Individual products are only checked if explicitly in the filters array + // (not when "all" is selected) + return selectedFilters.includes(value) && !selectedFilters.includes("all") + } + + // Get the display text for the trigger button + const getTriggerText = () => { + // If "All Products" is selected or no filters selected + if (selectedFilters.includes("all") || selectedFilters.length === 0) { + return "All Products" + } + + // If exactly 1 product is selected + if (selectedFilters.length === 1) { + const selectedProduct = options.find((filter) => filter.value === selectedFilters[0]) + return selectedProduct?.label || "All Products" + } + + // If 2 or more products are selected + return "Multiple Products" + } + + return ( + <div className={styles.dropdown} ref={dropdownRef}> + <button + className={styles.trigger} + onClick={() => setIsOpen(!isOpen)} + aria-expanded={isOpen} + aria-haspopup="listbox" + type="button" + > + <Typography variant="body-xs">{getTriggerText()}</Typography> + <svg + className={`${styles.chevronIcon} ${isOpen ? styles.chevronOpen : ""}`} + width="16" + height="16" + viewBox="0 0 16 16" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path d="M4 6L8 10L12 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /> + </svg> + </button> + + {isOpen && ( + <div className={styles.menu} role="listbox"> + {options.map((filter) => ( + <label + key={filter.value} + className={styles.checkboxLabel} + role="option" + aria-selected={isChecked(filter.value)} + > + <input + type="checkbox" + checked={isChecked(filter.value)} + onChange={() => handleCheckboxChange(filter.value)} + className={styles.checkboxInput} + /> + <span className={styles.customCheckbox}> + {isChecked(filter.value) && ( + <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path + d="M2 6L5 9L10 3" + stroke="white" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + )} + </span> + <Typography variant="body-xs">{filter.label}</Typography> + </label> + ))} + </div> + )} + </div> + ) +} diff --git a/src/components/LandingHero/LandingHero.astro b/src/components/LandingHero/LandingHero.astro new file mode 100644 index 00000000000..5e3f9f1b18e --- /dev/null +++ b/src/components/LandingHero/LandingHero.astro @@ -0,0 +1,24 @@ +--- +import { Typography } from "@chainlink/blocks" +import MegaMenu from "../Header/Nav/ProductNavigation/Desktop/MegaMenu" +import styles from "./landingHero.module.css" +--- + +<section class={styles.wrapper}> + <div class={styles.content}> + <div className={styles.heroText}> + <Typography variant="h1" className={styles.title}> Build on the Chainlink Platform </Typography> + </div> + + <section class={styles.menu}> + <MegaMenu client:only="react" /> + </section> + </div> + + <div class={styles.backgrounds}> + <div class={styles.heroLeft}><img src="/images/hero-dotted.png" alt="" class={styles.heroDotted} /></div> + <div class={styles.heroRight}> + <img src="/images/hero-1.png" alt="" class={styles.heroImage} /> + </div> + </div> +</section> diff --git a/src/components/LandingHero/landingHero.module.css b/src/components/LandingHero/landingHero.module.css new file mode 100644 index 00000000000..9d2b6e5b2ee --- /dev/null +++ b/src/components/LandingHero/landingHero.module.css @@ -0,0 +1,85 @@ +.content { + padding: var(--space-16x); + max-width: 1440px; + width: 100%; + margin: 0 auto; + position: absolute; + inset: 0; + z-index: 5; +} + +.backgrounds { + display: flex; + height: 100%; +} + +.title { + font-weight: 400; + margin-bottom: var(--space-8x); + white-space: nowrap; +} + +.title br { + display: none; +} + +@media (min-width: 768px) { + .title br { + display: inline; + } +} + +.wrapper { + background-color: var(--muted); + position: relative; + inset: 0; + height: 746px; +} + +.heroImage { + width: 100%; + height: 100%; + object-fit: cover; +} + +.heroDotted { + width: 100%; + object-fit: cover; +} +.heroLeft { + display: flex; + align-items: end; +} + +.heroRight, +.heroLeft { + width: 50%; + height: 100%; +} + +.heroText { + max-width: 880px; /* wide enough for one line */ + padding-right: var(--space-16x); /* optical buffer from seam */ +} + +@media screen and (max-width: 991px) { + .wrapper { + background-color: transparent; + height: auto; + padding: 36px var(--space-10x); + } + .backgrounds, + .content .menu { + display: none; + } + + .content { + position: unset; + padding: 0; + } + + .title { + font-size: 40px; + margin-bottom: 0; + } +} diff --git a/src/components/LanguageSwitcherDropdown.tsx b/src/components/LanguageSwitcherDropdown.tsx index 88a3f9d1495..c79c808b120 100644 --- a/src/components/LanguageSwitcherDropdown.tsx +++ b/src/components/LanguageSwitcherDropdown.tsx @@ -1,6 +1,6 @@ -import { useState, useEffect, useRef } from "react" +import { useState, useEffect } from "react" import { selectedLanguage, type SupportedLanguage } from "~/lib/languageStore.js" -import styles from "./LanguageSwitcherDropdown.module.css" +import { SidebarDropdown, type DropdownItem } from "./SidebarDropdown/index.js" const goLogo = "/images/icons/go_logo_black.png" const tsLogo = "/images/icons/typescript_logo.png" @@ -23,10 +23,14 @@ function getInitialLanguage(): SupportedLanguage { } } +// Convert language config to dropdown items format +const languageItems: DropdownItem[] = [ + { id: "go", label: "Go", icon: goLogo }, + { id: "ts", label: "TypeScript", icon: tsLogo }, +] + export function LanguageSwitcherDropdown() { const [clientLanguage, setClientLanguage] = useState<SupportedLanguage>(getInitialLanguage) - const [isOpen, setIsOpen] = useState(false) - const dropdownRef = useRef<HTMLDivElement>(null) // After component mounts on client, sync with the store useEffect(() => { @@ -58,91 +62,23 @@ export function LanguageSwitcherDropdown() { } }, []) - // Close dropdown when clicking outside - useEffect(() => { - function handleClickOutside(event: MouseEvent) { - if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { - setIsOpen(false) - } - } - - if (isOpen) { - document.addEventListener("mousedown", handleClickOutside) - } - - return () => { - document.removeEventListener("mousedown", handleClickOutside) - } - }, [isOpen]) - - const setLanguage = (lang: SupportedLanguage) => { + const handleSelect = (lang: string) => { + const newLang = lang as SupportedLanguage // Update nanostore - selectedLanguage.set(lang) - setIsOpen(false) + selectedLanguage.set(newLang) // Dispatch custom event for page-level redirects - window.dispatchEvent(new CustomEvent("languageChanged", { detail: { language: lang } })) + window.dispatchEvent(new CustomEvent("languageChanged", { detail: { language: newLang } })) } - const currentConfig = languageConfig[clientLanguage] - return ( - <div className={styles.dropdown} ref={dropdownRef}> - <label className={styles.label} htmlFor="language-selector-trigger"> - SDK Language - </label> - <button - id="language-selector-trigger" - className={styles.trigger} - onClick={() => setIsOpen(!isOpen)} - aria-haspopup="true" - aria-expanded={isOpen} - aria-label="Select programming language" - type="button" - > - <img src={currentConfig.logo} alt={currentConfig.label} className={styles.triggerIcon} /> - <span className={styles.triggerText}>{currentConfig.label}</span> - <svg className={styles.arrow} width="12" height="12" viewBox="0 0 12 12" fill="none"> - <path - d="M2.5 4.5L6 8L9.5 4.5" - stroke="currentColor" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </svg> - </button> - - {isOpen && ( - <div className={styles.menu}> - <div className={styles.menuContent}> - {(Object.entries(languageConfig) as [SupportedLanguage, typeof languageConfig.go][]).map( - ([lang, config]) => ( - <button - key={lang} - className={`${styles.option} ${clientLanguage === lang ? styles.selected : ""}`} - onClick={() => setLanguage(lang)} - type="button" - > - <img src={config.logo} alt={config.label} className={styles.optionIcon} /> - <span>{config.label}</span> - {clientLanguage === lang && ( - <svg className={styles.checkmark} width="16" height="16" viewBox="0 0 16 16" fill="none"> - <path - d="M13.5 4.5L6 12L2.5 8.5" - stroke="currentColor" - strokeWidth="2" - strokeLinecap="round" - strokeLinejoin="round" - /> - </svg> - )} - </button> - ) - )} - </div> - </div> - )} - </div> + <SidebarDropdown + label="SDK Language" + items={languageItems} + selectedId={clientLanguage} + onSelect={handleSelect} + triggerId="language-selector-trigger" + ariaLabel="Select programming language" + /> ) } diff --git a/src/components/LayoutHero/LayoutHero.astro b/src/components/LayoutHero/LayoutHero.astro new file mode 100644 index 00000000000..ee95ce616f9 --- /dev/null +++ b/src/components/LayoutHero/LayoutHero.astro @@ -0,0 +1,45 @@ +--- +import { buttonVariants, Typography } from "@chainlink/blocks" +import styles from "./LayoutHero.module.css" + +interface Props { + title: string + description: string + buttons: Array<{ + label: string + link: string + }> + image: string +} + +const { title, description, buttons = [], image } = Astro.props as Props +--- + +<section class={styles.layoutHero}> + <div class={styles.heroContentWrapper}> + <div class={styles.heroContent}> + <h2 class={styles.heroTitle}>{title}</h2> + <Typography variant="body-s" color="muted">{description}</Typography> + <div class={styles.heroButtons}> + { + buttons.map((button, index) => ( + <a + href={button.link} + class={buttonVariants({ + variant: index === 0 ? "primary" : "tertiary", + size: "sm", + })} + > + {button.label} + </a> + )) + } + </div> + </div> + <div class={styles.heroImage}> + <img src={image} alt={title} /> + </div> + </div> + + <img class={styles.heroBackgroundImg} src="/images/ccip/ccip-hero-bg.png" /> +</section> diff --git a/src/components/LayoutHero/LayoutHero.module.css b/src/components/LayoutHero/LayoutHero.module.css new file mode 100644 index 00000000000..08edb61ed40 --- /dev/null +++ b/src/components/LayoutHero/LayoutHero.module.css @@ -0,0 +1,99 @@ +.layoutHero { + display: flex; + flex-direction: column; + gap: var(--space-8x); + margin: 0 auto; + background-color: var(--gray-100); + position: relative; + width: 100%; + height: 345px; + border-left: 1px solid var(--border); + border-right: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} + +.heroContent { + display: flex; + flex-direction: column; + padding-left: 55px; + width: 100%; + height: 100%; + justify-content: center; + max-width: 540px; +} + +.heroContentWrapper { + display: flex; + position: relative; + z-index: 2; + width: 100%; + height: 100%; +} + +.heroBackgroundImg { + position: absolute; + right: 0; + z-index: 1; +} +.heroTitle { + font-size: 3rem; + line-height: 50px; + color: var(--gray-950); + margin-bottom: var(--space-3x); + letter-spacing: -0.48px; + font-weight: 400; +} + +.heroButtons { + display: flex; + + gap: var(--space-4x); + margin-top: var(--space-8x); +} + +.heroImage { + display: flex; + position: absolute; + bottom: 35px; + right: 0; +} + +.heroImage img { + max-width: 100%; + height: auto; +} + +@media screen and (max-width: 425px) { + .layoutHero { + height: auto; + padding: var(--space-8x) 0; + } +} + +/* lesser values cause overlapping of elements */ +@media screen and (max-width: 1400px) { + .layoutHero { + border: none; + background-color: transparent; + } + .heroImage, + .heroBackgroundImg { + display: none; + } + + .heroContent { + padding-left: 0; + } + + .heroButtons { + margin-top: var(--space-6x); + } + + .heroButtons a { + width: fit-content; + } + + .heroTitle { + font-size: 40px; + } +} diff --git a/src/components/LayoutHero/README.md b/src/components/LayoutHero/README.md new file mode 100644 index 00000000000..fcc0c16e4d0 --- /dev/null +++ b/src/components/LayoutHero/README.md @@ -0,0 +1,84 @@ +# LayoutHero Component + +## What is it? + +The LayoutHero component is a reusable hero section that displays a title, description, call-to-action buttons, and an optional image. It's perfect for landing pages or the top of important pages where you want to grab attention and guide users to take action. + +## How to Use It + +### Basic Usage + +To use the LayoutHero component in your page, you'll need to import it and provide some information: + +```astro +--- +import { LayoutHero } from "@components" +--- + +<LayoutHero + title="Welcome to Our Documentation" + description="Learn how to build amazing applications with our platform" + buttons={[ + { label: "Get Started", link: "/quickstart" }, + { label: "View Documentation", link: "/docs" }, + ]} + image="/images/hero-image.png" +/> +``` + +### What Each Part Does + +**title** (Required) + +- This is the main heading that appears at the top +- Make it clear and attention-grabbing +- Example: "Welcome to Chainlink Docs" + +**description** (Required) + +- A short paragraph explaining what this page or section is about +- Keep it concise but informative +- Example: "Learn how to connect your smart contracts to real-world data" + +**buttons** (Required) + +- An array of buttons that link to other pages +- Each button needs two things: + - `label`: The text shown on the button + - `link`: Where the button takes you when clicked +- The first button will be blue (primary action) +- The second button will be white (secondary action) +- You can have 0, 1, or 2 buttons + +**image** (Required) + +- The path to an image file you want to display +- The image appears on the right side on larger screens +- Below the text on mobile devices +- Example: "/images/my-hero-image.png" + +## Examples + +### With Only One Button + +```astro +<LayoutHero + title="Start Building Today" + description="Get started with our comprehensive guides and tutorials" + buttons={[{ label: "Get Started", link: "/quickstart" }]} +/> +``` + +### With Image and Two Buttons + +```astro +<LayoutHero + title="CCIP Cross-Chain Protocol" + description="Send tokens and messages across blockchains securely and reliably" + buttons={[ + { label: "Try CCIP", link: "/ccip/getting-started" }, + { label: "Learn More", link: "/ccip/concepts" }, + ]} + image="/images/ccip-hero.png" +/> +``` diff --git a/src/components/LeftSidebar/LeftSidebar.astro b/src/components/LeftSidebar/LeftSidebar.astro index 78f691d9717..960265a8aac 100644 --- a/src/components/LeftSidebar/LeftSidebar.astro +++ b/src/components/LeftSidebar/LeftSidebar.astro @@ -6,9 +6,9 @@ import RecursiveSidebar from "./RecursiveSidebar.astro" import { LanguageSwitcherDropdown } from "~/components/LanguageSwitcherDropdown" import { ChainTypeSelector } from "~/components/ChainSelector" import { isChainAwareSection } from "~/config/chainTypes" -import { filterContentByChainType } from "~/utils/chainType" -import type { ChainType } from "~/config/types" import styles from "./leftSidebar.module.css" +import DocsHeaderTitle from "../DocsHeaderTitle/DocsHeaderTitle.astro" +import * as CONFIG from "../../config" type SectionEntryWithParent = SectionEntry & { parentSection?: string } @@ -83,14 +83,10 @@ const sidebarSections = getSidebarSections(section) --- <nav aria-labelledby="grid-left" class={styles.nav}> - { - section === "cre" && ( - <div class={styles.languageSwitcherTablet}> - <LanguageSwitcherDropdown client:only="react" /> - </div> - ) - } - {showChainSelector && <ChainTypeSelector client:only="react" />} + <div class={styles.sidebarDropdowns}> + {section === "cre" && <LanguageSwitcherDropdown client:only="react" />} + {showChainSelector && <ChainTypeSelector client:only="react" />} + </div> <ul class={styles.navGroups} data-sticky> { sidebarSections.map((group) => ( @@ -107,6 +103,39 @@ const sidebarSections = getSidebarSections(section) </li> )) } + <div class={styles.quickLinks}> + <li class={styles.headerLink}> + <a href="/builders-quick-links" target="_blank" id="quick-links-sidebar-link"> + <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path + d="M2.5 9.20055L7.18129 2H12.2965L9.62194 5.59959H13.5L5.97787 14H4.50671L7.18135 9.20055H2.5Z" + fill="#0D5DFF"></path> + </svg> + <p>Quick links</p> + </a> + </li> + <li class={styles.headerLink}> + <a + class={styles.link} + href="https://github.com/smartcontractkit/documentation" + target="_blank" + rel="noopener noreferrer" + > + <img height={16} width={16} src="/assets/icons/github-blue.svg" alt="GitHub repository" /> + <span>Github</span> + </a> + </li> + { + CONFIG.COMMUNITY_INVITE_URL && ( + <li class={styles.headerLink}> + <a href={CONFIG.COMMUNITY_INVITE_URL} target="_blank" rel="noopener noreferrer"> + <img src="/images/discord.svg" loading="lazy" width="16" height="16" alt="Discord" /> + <span>Join our community</span> + </a> + </li> + ) + } + </div> </ul> </nav> @@ -124,7 +153,7 @@ const sidebarSections = getSidebarSections(section) </style> <script> - import { initializeChainType } from "~/stores/chainType" + import { initializeChainType } from "~/stores/chainType.js" /** * Initialize chain type selection from URL on page load @@ -160,7 +189,7 @@ const sidebarSections = getSidebarSections(section) </script> <script> - import { selectedChainType } from "~/stores/chainType" + import { selectedChainType } from "~/stores/chainType.js" /** * Filters sidebar items based on selected chain type diff --git a/src/components/LeftSidebar/leftSidebar.module.css b/src/components/LeftSidebar/leftSidebar.module.css index 9299511f69d..167692c3240 100644 --- a/src/components/LeftSidebar/leftSidebar.module.css +++ b/src/components/LeftSidebar/leftSidebar.module.css @@ -1,15 +1,24 @@ .nav { - padding-bottom: calc(2 * var(--doc-padding)); width: 100%; - height: calc(100vh - var(--space-16x)); /* Subtract header height */ + height: calc(100vh - var(--space-16x)); + /* Subtract header height */ position: sticky; - top: var(--space-16x); /* Header height */ - overflow: hidden; /* Prevent nav overflow */ + top: var(--space-16x); + /* Header height */ + overflow: hidden; + /* Prevent nav overflow */ + display: flex; + flex-direction: column; +} + +.sidebarDropdowns { + padding-top: var(--space-3x); + flex-shrink: 0; } .navGroups { - padding: var(--doc-padding) var(--space-8x) var(--doc-padding) 0; - height: 100%; + padding: var(--doc-padding) var(--space-8x) calc(2 * var(--doc-padding)) 0; + flex: 1; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--gray-300) transparent; @@ -47,8 +56,7 @@ .navGroupTitle { margin-bottom: var(--space-2x); margin-top: var(--space-1x); - color: var(--gray-900); - font-weight: 600; + color: var(--muted-foreground); line-height: 24px; font-size: 15px; display: flex; @@ -57,10 +65,9 @@ cursor: pointer; list-style: none; position: relative; - padding-left: var(--space-6x); } -.navGroupTitle::before { +.navGroupTitle::after { content: ""; width: 6px; height: 6px; @@ -71,21 +78,16 @@ transition: transform 0.15s ease; position: absolute; top: calc(50% - 4px); - left: var(--space-2x); + right: var(--space-2x); } -details[open] > .navGroupTitle::before { +details[open] > .navGroupTitle::after { transform: rotate(45deg); top: calc(50% - 5px); } -details:hover .navGroupTitle::before { - border-color: var(--color-text-link); -} - .navGroupEntries { margin-bottom: 0; - padding-left: var(--space-6x); } details { @@ -113,9 +115,68 @@ details[open] > .navGroupTitle { color: hsla(var(--color-base-white), 100%, 1); } +.link { + display: flex; + align-items: center; + padding: var(--space-3x) var(--space-2x); + gap: var(--space-2x); + margin-right: var(--space-2x); + + color: var(--gray-900, #141921); + font-weight: 600; + line-height: 24px; /* 150% */ +} + +.quickLinks { + margin-top: 60px; + display: flex; + flex-direction: column; + gap: var(--space-2x); +} + +.headerLink { + font-size: 14px; + color: var(--color-text-link); + padding: var(--space-1x) var(--space-2x); +} + +.headerLink * { + margin: 0; + max-width: 100%; + color: inherit; + font: inherit; +} + +.headerLink.active, +.headerLink:hover, +.headerLink:focus { + color: var(--theme-accent); + fill: var(--theme-accent); +} + +.headerLink:focus-within { + color: var(--theme-text-light); + fill: var(--theme-text-light); +} + +.headerLink a { + display: inline-flex; + gap: var(--space-2x); + width: 100%; + padding: 0.15em 0 0.15em 0; + text-decoration: none; +} + +.headerLink { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.25rem; +} + /* Language Switcher for tablet screens (800px-1200px) */ .languageSwitcherTablet { - padding: var(--space-6x) var(--space-6x) 0 var(--space-6x); + padding: var(--space-6x) 0; display: none; } diff --git a/src/components/LeftSidebar/recursiveSidebar.module.css b/src/components/LeftSidebar/recursiveSidebar.module.css index 31a33633647..ca7720c2278 100644 --- a/src/components/LeftSidebar/recursiveSidebar.module.css +++ b/src/components/LeftSidebar/recursiveSidebar.module.css @@ -10,11 +10,13 @@ gap: var(--space-2x); line-height: 1.4; font-size: 14px; - color: var(--gray-500, #858a95); + color: var(--muted-foreground); padding: var(--space-2x) var(--space-6x) var(--space-2x) var(--space-4x); transition: color 100ms ease-in; - border-radius: 4px; - margin-right: var(--space-2x); + border-left: 1px solid var(--border); + + padding-right: var(--space-2x); + margin-bottom: 0; position: relative; } @@ -39,7 +41,7 @@ details summary.navLink.nested a { details summary.navLink:has(a.active), details summary.navLink:has(a[aria-current="page"]), details summary.navLink.active { - color: var(--color-text-link); + color: var(--foreground); } .navLink:hover, @@ -47,15 +49,19 @@ details summary.navLink.active { details summary.navLink:hover, details summary.navLink:focus { text-decoration: none; + background-color: var(--muted); + + color: var(--muted-foreground); } .navLink[aria-current="page"], details summary.navLink:has(a[aria-current="page"]), details summary.navLink.active, details summary.navLink:has(a.active) { - font-weight: 600; - background-color: rgba(28, 100, 242, 0.08); - color: var(--color-text-link); + color: var(--foreground); + border-left: 2px solid var(--brand); + font-weight: 500; + background-color: var(--muted); } .navLink.nested { @@ -75,14 +81,15 @@ details summary.navLink a { margin: 0; } -details summary.navLink:hover a { - color: var(--color-text-link); +details summary.navLink:hover { + background-color: var(--muted); + color: var(--muted-foreground); } details summary.navLink a.active, details summary.navLink a[aria-current="page"] { - font-weight: 600; - color: var(--color-text-link); + font-weight: 500; + color: var(--foreground); } .navGroupEntries { @@ -109,9 +116,6 @@ details summary.navLink a[aria-current="page"] { .navGroupEntries.nested { margin-left: 0; - margin-top: var(--space-1x); - padding-left: var(--space-4x); - margin-bottom: var(--space-1x); position: relative; } @@ -125,6 +129,10 @@ details summary.navLink a[aria-current="page"] { background-color: var(--gray-200); } +.navGroupEntries.nested .navLink { + padding-left: 28px; +} + details summary::-webkit-details-marker { display: none; } @@ -139,7 +147,7 @@ details > summary.navLink { padding-left: var(--space-4x); } -details > summary.navLink::before { +details > summary.navLink::after { content: ""; width: 6px; height: 6px; @@ -150,14 +158,18 @@ details > summary.navLink::before { transition: transform 0.15s ease; position: absolute; top: calc(50% - 4px); - left: 0; + right: var(--space-2x); } -details[open] > summary.navLink::before { +details[open] > summary.navLink::after { transform: rotate(45deg); top: calc(50% - 5px); } -details:hover > summary.navLink::before { - border-color: var(--color-text-link); +.container ul { + overflow-y: auto; + padding: var(--space-4x); + line-height: 1.5; + list-style-type: none; + word-break: break-word; } diff --git a/src/components/MediaSection/MediaSection.astro b/src/components/MediaSection/MediaSection.astro new file mode 100644 index 00000000000..6189f9326e7 --- /dev/null +++ b/src/components/MediaSection/MediaSection.astro @@ -0,0 +1,46 @@ +--- +import { Typography } from "@chainlink/blocks" +import styles from "./MediaSection.module.css" + +interface Props { + heading: string + description: string + image?: string + video?: string +} + +const { heading, description, image, video } = Astro.props +--- + +<section class={styles.section}> + <div class={styles.textContent}> + <Typography + variant="h2" + style={{ + fontSize: "32px", + }}>{heading}</Typography + > + <Typography variant="body" color="muted"> + {description} + </Typography> + </div> + + { + image && ( + <div class={styles.mediaWrapper}> + <img src={image} alt={heading} class={styles.media} /> + </div> + ) + } + + { + !image && video && ( + <div class={styles.mediaWrapper}> + <video class={styles.media} controls> + <source src={video} type="video/mp4" /> + Your browser does not support the video tag. + </video> + </div> + ) + } +</section> diff --git a/src/components/MediaSection/MediaSection.module.css b/src/components/MediaSection/MediaSection.module.css new file mode 100644 index 00000000000..f7c5673f5a8 --- /dev/null +++ b/src/components/MediaSection/MediaSection.module.css @@ -0,0 +1,25 @@ +.section { + display: flex; + flex-direction: column; + gap: var(--space-8x); +} + +.textContent { + display: flex; + flex-direction: column; + gap: var(--space-6x); +} + +.mediaWrapper { + width: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.media { + width: 100%; + max-width: 100%; + height: auto; + border-radius: var(--space-2x); +} diff --git a/src/components/MediaSection/README.md b/src/components/MediaSection/README.md new file mode 100644 index 00000000000..c03ad7205c6 --- /dev/null +++ b/src/components/MediaSection/README.md @@ -0,0 +1,44 @@ +# MediaSection Component + +## What it does + +The MediaSection component displays a section with a heading, description, and optionally an image or video. It's perfect for explaining concepts with visual aids, like showing architecture diagrams or tutorial videos. + +## How to use it + +Import the component and add it to your page with the content you want to display: + +```astro +import MediaSection from "~/components/MediaSection/MediaSection.astro" + +<MediaSection + heading="Your Section Title" + description="A description explaining what this section is about." + image="/path/to/your/image.png" +/> +``` + +## Props explained + +- **heading** (required) - The title of your section +- **description** (required) - A paragraph explaining the section content +- **image** (optional) - Path to an image file you want to display +- **video** (optional) - Path to a video file you want to display + +**Note:** You can provide either an image OR a video, not both. If you include both, only the image will show. + +## Example + +```astro +<MediaSection + heading="High-level architecture" + description="CCIP delivers cross-chain messages from a source chain to a destination chain by combining offchain consensus and onchain execution components." + image="/images/architecture.png" +/> +``` + +This will display: + +1. A heading that says "High-level architecture" +2. The description text below it +3. The architecture diagram image at the bottom diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx index 18d989f7ac2..9e705a665c6 100644 --- a/src/components/Modal/Modal.tsx +++ b/src/components/Modal/Modal.tsx @@ -1,6 +1,6 @@ import React from "react" import styles from "./Modal.module.css" -import FocusTrap from "focus-trap-react" +import { FocusTrap } from "focus-trap-react" import { createPortal } from "react-dom" import { useKeyPress } from "~/hooks/useKeyPress.ts" import { clsx } from "~/lib/clsx/clsx.ts" @@ -24,16 +24,7 @@ export function Modal({ <> {isOpen && createPortal( - // For some reason the error says that the element doesn't match even though it does - // and it also works correctly. - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore <FocusTrap> - {/* - For some reason the error says that the element doesn't match even though it does - and it also works correctly. - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - @ts-ignore */} <div> <div className={styles.overlay} onClick={onClose}></div> <div id={modalId} className={clsx(styles.modal)} tabIndex={0} style={style}> diff --git a/src/components/OverviewWrapper.astro b/src/components/OverviewWrapper.astro new file mode 100644 index 00000000000..e3eaef0fa90 --- /dev/null +++ b/src/components/OverviewWrapper.astro @@ -0,0 +1,20 @@ +<section class="overflow-wrapper"> + <slot /> +</section> + +<style> + .overflow-wrapper { + display: flex; + flex-direction: column; + width: 100%; + gap: 82px; + padding-top: 56px; + } + + @media screen and (max-width: 425px) { + .overflow-wrapper { + gap: 36px; + padding-top: 0; + } + } +</style> diff --git a/src/components/PageContent/PageContent.astro b/src/components/PageContent/PageContent.astro index 5e5689abf6b..e29180351b4 100644 --- a/src/components/PageContent/PageContent.astro +++ b/src/components/PageContent/PageContent.astro @@ -1,190 +1,224 @@ --- import { MarkdownHeading } from "astro" -import BackButton from "./BackButton.astro" export type Props = { titleHeading: MarkdownHeading + disableDefaultStyles?: boolean + hideTitle?: boolean } -const { titleHeading } = Astro.props +const { titleHeading, disableDefaultStyles, hideTitle } = Astro.props --- -<article id="article"> - <h1 id={titleHeading.slug}>{titleHeading.text}</h1> +<article id="article" data-disable-default-styles={disableDefaultStyles || undefined}> + <h1 id={titleHeading.slug} class:list={{ "sr-only": hideTitle }}>{titleHeading.text}</h1> + <slot /> </article> <style is:inline> - article :is(h1, h2, h3, h4, h5, h6) > a { - display: inline-block; - color: inherit; - width: 100%; - } - - article astro-slot > :first-child { - margin-top: 0; + /* Screen reader only - visually hidden but accessible */ + .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } /* Using padding instead of margin so intersection observers work without spaces */ - :where(article, astro-island, astro-slot) > section { + :where(article:not([data-disable-default-styles]), astro-island, astro-slot) > section { padding-top: var(--space-5x); } - /* - This is a bit of trickery that keeps the content - from shifting in the time between the DOM hydrating and the - wrapper script finishing. The margin is supplemented - by the section padding once the wrapper is created - - This also keeps the spacing intact - in case JS isn't loading on the page - */ - article > :where(h1, h2) { - margin-top: var(--space-5x) !important; - } - - article * { - max-width: 100%; - margin-bottom: 0; - } - - article :is(h1, h2, h3, h4, h5, h6, p, li) { - word-break: break-word; - } - - article p { - margin-bottom: 0; - } - - article :is(p, li) { - line-height: 28px; - } - - article label { - display: flex; - align-items: center; - gap: var(--space-2x); - } + /* Default content styles - opt-out with disableDefaultStyles prop for custom layouts like ccip/index.mdx */ + article:not([data-disable-default-styles]) { + :is(h1, h2, h3, h4, h5, h6) > a { + display: inline-block; + color: inherit; + width: 100%; + } - :where(article, article section, article astro-slot, article astro-island) > :not(section, astro-slot, astro-island) { - margin-top: var(--space-5x); - } + astro-slot > :first-child { + margin-top: 0; + } - :where(article, article section, article astro-slot, article astro-island) > pre { - margin-top: var(--space-2x); - } + /* + This is a bit of trickery that keeps the content + from shifting in the time between the DOM hydrating and the + wrapper script finishing. The margin is supplemented + by the section padding once the wrapper is created + + This also keeps the spacing intact + in case JS isn't loading on the page + */ + > :where(h1, h2) { + margin-top: var(--space-5x) !important; + } - :where(article, article section) > :is(h1, h2, h3) + :not(section, astro-slot, astro-island, h5, h6) { - margin-top: var(--space-5x) !important; - } + * { + max-width: 100%; + margin-bottom: 0; + } - :where(article, article section) > :is(h4, h5, h6) + :not(section, astro-slot, astro-island) { - margin-top: var(--space-3x) !important; - } + a:not(:is(h1 a, h2 a, h3 a, h4 a, h5 a, h6 a)) { + color: var(--color-text-link); + } - :where(article, article section, article astro-slot) > :is(h1, h2, h3, h4, h5, h6, li) { - margin-top: 0; - } + :is(h1, h2, h3, h4, h5, h6, p, li) { + word-break: break-word; + } - :where(article, article section, article astro-slot) > h1 { - font-size: 32px; - } + p { + margin-bottom: 0; + } - :where(article, article section, article astro-slot) > h2 { - padding-top: var(--space-6x); - font-size: 28px; - } + :is(p, li) { + line-height: 28px; + } - :where(article, article section, article astro-slot) > h3 { - padding-top: var(--space-8x); - font-size: 24px; - } + label { + display: flex; + align-items: center; + gap: var(--space-2x); + } - :where(article, article section, article astro-slot) > h4 { - padding-top: var(--space-5x); - font-size: 20px; - } + :is(ul, ol) { + margin-top: var(--space-3x); - :where(article, article section, article astro-slot) > :is(h5, h6) { - padding-top: var(--space-4x); - font-size: 16px; - } + > li, + > li > :is(ul, ol) { + margin-top: var(--space-2x); + } + } - article :is(ul, ol) { - margin-top: var(--space-3x); - } + li { + list-style-type: disc; - article :is(ul, ol) > li, - article :is(ul, ol) > li > :is(ul, ol) { - margin-top: var(--space-2x); - } + > * { + margin-top: var(--space-2x); + } - article li > * { - margin-top: var(--space-2x); - } + /* Offset line-height difference */ + > :not(p):last-child { + margin-bottom: var(--space-3x); + } + } - article ul { - padding-left: calc(var(--space-4x) + 2px); - } + ul { + padding-left: calc(var(--space-4x) + 2px); + } - article ol { - padding-left: var(--space-8x); - } + ol { + padding-left: var(--space-8x); + } - /* Offset line-height difference */ - article li > :not(p):last-child { - margin-bottom: var(--space-3x); - } + ::marker { + font-weight: bold; + color: var(--theme-text-light); + } - article ::marker { - font-weight: bold; - color: var(--theme-text-light); - } + iframe { + width: 100%; + height: auto; + aspect-ratio: 16 / 9; + } - article iframe { - width: 100%; - height: auto; - aspect-ratio: 16 / 9; - } + /* Offsets padding */ + :is(section, h5, h6):target { + scroll-margin-top: var(--theme-navbar-height); + } - /* Offsets padding */ - article :is(section, h5, h6):target { - scroll-margin-top: var(--theme-navbar-height); - } + /* Shared styles for article, section, and astro-slot contexts */ + :where(&, & section, & astro-slot, & astro-island) { + > :not(section, astro-slot, astro-island) { + margin-top: var(--space-5x); + } - @media (min-width: 50em) { - :where(article, article section, article astro-slot) > :is(h1, h2) { - position: sticky; - top: 0; - z-index: 3; - background: white; - border-bottom: 2px solid var(--blue-200, #dfe7fb); - padding: var(--space-6x) 0; + > pre { + margin-top: var(--space-2x); + } } - article section > :is(section, h5, h6):target { - scroll-margin-top: calc(var(--theme-navbar-height) + var(--space-20x)); - } + :where(&, & section) { + > :is(h1, h2, h3) + :not(section, astro-slot, astro-island, h5, h6) { + margin-top: var(--space-5x) !important; + } - :where(article, article section, article astro-slot) > h3 { - padding-top: var(--space-8x); + > :is(h4, h5, h6) + :not(section, astro-slot, astro-island) { + margin-top: var(--space-3x) !important; + } } - :where(article, article section, article astro-slot) > h4 { - padding-top: var(--space-6x); + :where(&, & section, & astro-slot) { + > :is(h1, h2, h3, h4, h5, h6, li) { + font-weight: bold; + margin-top: 0; + } + + > h1 { + font-size: 32px; + } + + > h2 { + padding-top: var(--space-6x); + font-size: 28px; + } + + > h3 { + padding-top: var(--space-8x); + font-size: 24px; + } + + > h4 { + padding-top: var(--space-5x); + font-size: 20px; + } + + > :is(h5, h6) { + padding-top: var(--space-4x); + font-size: 16px; + } } - } - @media (min-width: 72em) { - :where(article, article section, article astro-slot) > h1 { - font-size: 40px; + @media (min-width: 50em) { + :where(&, & section, & astro-slot) > :is(h1, h2) { + position: sticky; + top: 0; + z-index: 3; + background: white; + border-bottom: 2px solid var(--blue-200, #dfe7fb); + padding: var(--space-6x) 0; + } + + section > :is(section, h5, h6):target { + scroll-margin-top: calc(var(--theme-navbar-height) + var(--space-20x)); + } + + :where(&, & section, & astro-slot) > h3 { + padding-top: var(--space-8x); + } + + :where(&, & section, & astro-slot) > h4 { + padding-top: var(--space-6x); + } } - :where(article, article section, article astro-slot) > h2 { - font-size: 32px; - } + @media (min-width: 72em) { + :where(&, & section, & astro-slot) > h1 { + font-size: 40px; + } + + :where(&, & section, & astro-slot) > h2 { + font-size: 32px; + } - :where(article, article section, article astro-slot) > h3 { - font-size: 28px; + :where(&, & section, & astro-slot) > h3 { + font-size: 28px; + } } } </style> diff --git a/src/components/PageContent/WhatsNext.astro b/src/components/PageContent/WhatsNext.astro index 43bd4634c79..0c1cf779674 100644 --- a/src/components/PageContent/WhatsNext.astro +++ b/src/components/PageContent/WhatsNext.astro @@ -1,10 +1,12 @@ --- +import { Typography } from "@chainlink/blocks" + export type Props = { content: Record<string, string> } const { content = {} } = Astro.props as Props --- <section> - <h2>What's next</h2> + <Typography variant="h2">What's next</Typography> <ul> { Object.keys(content).map((key) => ( @@ -23,6 +25,8 @@ const { content = {} } = Astro.props as Props h2 { margin: 0; + font-weight: bold; + font-size: 2rem; } ul { @@ -42,6 +46,7 @@ const { content = {} } = Astro.props as Props li a { display: inline-block; padding: var(--space-4x); + color: var(--color-text-link); width: 100%; } diff --git a/src/components/QuickLinkCard/QuickLinkCard.astro b/src/components/QuickLinkCard/QuickLinkCard.astro new file mode 100644 index 00000000000..e4e13bc9e71 --- /dev/null +++ b/src/components/QuickLinkCard/QuickLinkCard.astro @@ -0,0 +1,44 @@ +--- +import { Typography } from "@chainlink/blocks" +import styles from "./QuickLinkCard.module.css" + +interface Link { + icon: any + label: string + link: string +} + +interface Props { + links: Link[] +} + +const { links } = Astro.props +--- + +<section class={styles.container}> + <h2 class={styles.srOnly}>Quick Links</h2> + + <div class={styles.content}> + <div class={styles.sidebar} aria-hidden="true"></div> + + <div class={styles.main}> + <div class={styles.linksGrid}> + { + links.map((link) => { + const Icon = link.icon + return ( + <a href={link.link} class={styles.linkItem}> + <span class={styles.icon}> + <Icon color="brand" /> + </span> + <Typography color="muted" variant="body-s"> + {link.label} + </Typography> + </a> + ) + }) + } + </div> + </div> + </div> +</section> diff --git a/src/components/QuickLinkCard/QuickLinkCard.module.css b/src/components/QuickLinkCard/QuickLinkCard.module.css new file mode 100644 index 00000000000..f514f3a06a0 --- /dev/null +++ b/src/components/QuickLinkCard/QuickLinkCard.module.css @@ -0,0 +1,66 @@ +.srOnly { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.content { + display: flex; +} + +.sidebar { + width: 32px; + flex-shrink: 0; + background: url("/images/info-sidebar-img.png") lightgray 50% / cover no-repeat; + position: relative; + filter: saturate(0.6); +} + +.main { + flex: 1; + min-width: 0; +} + +.linksGrid { + display: grid; + grid-template-columns: 1fr; + gap: var(--space-6x); + padding: var(--space-4x) 0 calc(var(--space-4x) - 2px) var(--space-6x); + + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); + border-right: 1px solid var(--border); +} + +.linkItem { + display: flex; + align-items: center; + gap: var(--space-2x); +} + +.label { + font-size: 1rem; + font-weight: 500; +} + +@media (min-width: 640px) { + .linksGrid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (min-width: 1024px) { + .sidebar { + display: block; + } + + .linksGrid { + grid-template-columns: repeat(3, 1fr); + } +} diff --git a/src/components/QuickLinkCard/README.md b/src/components/QuickLinkCard/README.md new file mode 100644 index 00000000000..84ecff72986 --- /dev/null +++ b/src/components/QuickLinkCard/README.md @@ -0,0 +1,214 @@ +# QuickLinkCard Component + +A responsive component that displays a grid of quick links with icons, perfect for creating a "Tools & Utilities" section or similar resource lists. + +## What This Component Does + +The QuickLinkCard component creates a visually appealing section that: + +- Shows a decorative sidebar image on larger screens +- Arranges your links in a responsive grid (1 column on mobile, 2 on tablet, 3 on desktop) +- Each link has an icon and a label +- Icons are displayed in brand color (blue) + +## How to Use It + +### Basic Usage + +1. Import the component and icon components in your Astro page: + +```astro +--- +import QuickLinkCard from "~/components/QuickLinkCard/QuickLinkCard.astro" +import { SvgEyeOptic, SvgStartup, SvgBulletList } from "@chainlink/blocks" +--- +``` + +2. Add the component with your links: + +```astro +<QuickLinkCard + links={[ + { + icon: SvgEyeOptic, + label: "View Network Configs", + link: "/network-configs", + }, + { + icon: SvgStartup, + label: "Check Transaction Status", + link: "/transaction-status", + }, + { + icon: SvgBulletList, + label: "Get Testnet Tokens", + link: "/faucet", + }, + ]} +/> +``` + +## Understanding the Props + +The component accepts one prop called `links`, which is a list (array) of link objects. Each link object has three parts: + +### `icon` (required) + +- **What it is:** An icon component that appears next to the link +- **Format:** A component from `@chainlink/blocks` or any other icon component +- **Example:** `SvgEyeOptic`, `SvgStartup`, `SvgBulletList` +- **Tip:** Use icons from the `@chainlink/blocks` package for consistency with the rest of the site + +### `label` (required) + +- **What it is:** The text that appears next to the icon +- **Format:** Plain text +- **Example:** `'View Network Configs'` +- **Tip:** Keep it short and descriptive (2-4 words works best) + +### `link` (required) + +- **What it is:** Where the link goes when clicked +- **Format:** A URL path +- **Example:** `'/network-configs'` or `'https://example.com'` +- **Tip:** Use relative paths (starting with `/`) for internal pages + +## Complete Example + +Here's a full example showing 6 links: + +```astro +--- +import QuickLinkCard from "~/components/QuickLinkCard/QuickLinkCard.astro" +import { + SvgEyeOptic, + SvgTransactionRepeatRecurring, + SvgWaveSignal, + SvgStartup, + SvgCrossChain, + SvgBulletList, +} from "@chainlink/blocks" + +// Define your links here +const quickLinks = [ + { + icon: SvgEyeOptic, + label: "View Network Configs", + link: "https://docs.chain.link/ccip/directory/mainnet", + }, + { + icon: SvgTransactionRepeatRecurring, + label: "Check Transaction Status", + link: "https://ccip.chain.link/", + }, + { + icon: SvgWaveSignal, + label: "View Lane Status", + link: "https://ccip.chain.link/status", + }, + { + icon: SvgStartup, + label: "Get Testnet Tokens", + link: "https://tokenmanager.chain.link/", + }, + { + icon: SvgCrossChain, + label: "Convert Chainlink tokens", + link: "https://www.transporter.io/", + }, + { + icon: SvgBulletList, + label: "View the Changelog", + link: "https://dev.chain.link/changelog?product=CCIP", + }, +] +--- + +<QuickLinkCard links={quickLinks} /> +``` + +## Customizing the Look + +### Icon Color + +The icon color is set in the component itself. To change it: + +1. Open: `src/components/QuickLinkCard/QuickLinkCard.astro` +2. Find line with `<Icon color="brand" />` +3. Change `"brand"` to another color from `@chainlink/blocks` (e.g., `"blue-600"`, `"green-500"`, etc.) + +### Spacing and Layout + +If you want to change spacing or other visual aspects: + +1. Open the file: `src/components/QuickLinkCard/QuickLinkCard.module.css` +2. Look for the section you want to change: + - `.linkItem` - changes how each link looks + - `.linksGrid` - changes spacing and layout of the grid + - `.sidebar` - changes the sidebar image size + +### Example Customizations + +**Make the grid spacing tighter:** + +```css +.linksGrid { + gap: var(--space-4x); /* Change from var(--space-6x) */ +} +``` + +**Change the sidebar image size:** + +```css +.sidebar img { + width: 48px; /* Change from 32px */ +} +``` + +## Responsive Behavior + +The component automatically adapts to different screen sizes: + +- **Mobile (small screens):** Links stack in 1 column, sidebar image is hidden +- **Tablet (medium screens):** Links display in 2 columns, sidebar image is hidden +- **Desktop (large screens):** Links display in 3 columns, sidebar image appears on the left + +## Available Icons + +The `@chainlink/blocks` package provides many icons. Here are some commonly used ones: + +- `SvgEyeOptic` - Eye/view icon +- `SvgTransactionRepeatRecurring` - Transaction icon +- `SvgWaveSignal` - Signal/status icon +- `SvgStartup` - Rocket/startup icon +- `SvgCrossChain` - Cross-chain/transfer icon +- `SvgBulletList` - List icon +- And many more... + +Explore the `@chainlink/blocks` package to see all available icons. + +## Tips for Best Results + +1. **Icon Tips:** + - Use icons from `@chainlink/blocks` for consistency + - Keep all icons simple and recognizable + - Match the icon to the action (eye for "view", rocket for "get started", etc.) + +2. **Label Tips:** + - Keep labels short (2-4 words) + - Use action words like "View", "Check", "Get", "Convert" + - Be clear about what happens when the link is clicked + +3. **Link Tips:** + - Test all your links to make sure they work + - Use relative paths for internal pages (starts with `/`) + - Use full URLs for external sites (starts with `http://` or `https://`) + +## Need Help? + +If something isn't working: + +1. Check that all three parts (icon, label, link) are included for each link +2. Make sure you've imported the icon components from `@chainlink/blocks` +3. Verify that your links are correct paths +4. Check the browser console for any error messages diff --git a/src/components/QuickLinks/data/productChainLinks.ts b/src/components/QuickLinks/data/productChainLinks.ts index 62e1d4c1a8f..beb52259d0c 100644 --- a/src/components/QuickLinks/data/productChainLinks.ts +++ b/src/components/QuickLinks/data/productChainLinks.ts @@ -72,7 +72,7 @@ export const productChainLinks: ProductChainLinks = { hedera: "/ccip/directory/mainnet/chain/hedera-mainnet", hemi: "/ccip/directory/mainnet/chain/hemi-mainnet", mindnetwork: "/ccip/directory/mainnet/chain/mind-mainnet", - megaeth: "/ccip/directory/testnet/chain/megaeth-testnet", + megaeth: "/ccip/directory/mainnet/chain/megaeth-mainnet", solana: "/ccip/directory/mainnet/chain/solana-mainnet", lisk: "/ccip/directory/mainnet/chain/lisk-mainnet", zora: "/ccip/directory/mainnet/chain/zora-mainnet", @@ -81,6 +81,7 @@ export const productChainLinks: ProductChainLinks = { plume: "/ccip/directory/mainnet/chain/plume-mainnet", superseed: "/ccip/directory/mainnet/chain/superseed-mainnet", taiko: "/ccip/directory/mainnet/chain/ethereum-mainnet-taiko-1", + tempo: "/ccip/directory/testnet/chain/tempo-testnet", metal: "/ccip/directory/mainnet/chain/metal-mainnet", rootstock: "/ccip/directory/mainnet/chain/rootstock-mainnet", janction: "/ccip/directory/testnet/chain/janction-testnet-sepolia", @@ -99,19 +100,25 @@ export const productChainLinks: ProductChainLinks = { abchain: "/ccip/directory/mainnet/chain/ab-mainnet", henesys: "/ccip/directory/mainnet/chain/nexon-mainnet-henesys", pharos: "/ccip/directory/testnet/chain/pharos-atlantic-testnet", + morph: "/ccip/directory/mainnet/chain/morph-mainnet", + jovay: "/ccip/directory/mainnet/chain/jovay-mainnet", + stable: "/ccip/directory/mainnet/chain/stable-mainnet", + arc: "/ccip/directory/testnet/chain/arc-testnet", + dogeos: "/ccip/directory/testnet/chain/dogeos-testnet-chikyu", }, }, CRE: { learnMoreLink: "cre", logo: creLogo, chains: { - arbitrum: "/cre/guides/workflow/using-evm-client/supported-networks", - avalanche: "/cre/guides/workflow/using-evm-client/supported-networks", - base: "/cre/guides/workflow/using-evm-client/supported-networks", - "bnb-chain": "/cre/guides/workflow/using-evm-client/supported-networks", - ethereum: "/cre/guides/workflow/using-evm-client/supported-networks", - optimism: "/cre/guides/workflow/using-evm-client/supported-networks", - polygon: "/cre/guides/workflow/using-evm-client/supported-networks", + arbitrum: "/cre/supported-networks", + avalanche: "/cre/supported-networks", + base: "/cre/supported-networks", + "bnb-chain": "/cre/supported-networks", + ethereum: "/cre/supported-networks", + optimism: "/cre/supported-networks", + polygon: "/cre/supported-networks", + zksync: "/cre/supported-networks", }, }, "Data Feeds": { @@ -133,6 +140,7 @@ export const productChainLinks: ProductChainLinks = { hyperevm: "/data-feeds/price-feeds/addresses?page=1&network=hyperevm#networks", linea: "/data-feeds/price-feeds/addresses?page=1&network=linea#networks", mantle: "/data-feeds/price-feeds/addresses?page=1&network=mantle#networks", + megaeth: "/data-feeds/price-feeds/addresses?page=1&network=megaeth#networks", metis: "/data-feeds/price-feeds/addresses?page=1&network=metis#networks", monad: "/data-feeds/price-feeds/addresses?page=1&network=monad#networks", moonbeam: "/data-feeds/price-feeds/addresses?page=1&network=moonbeam#networks", @@ -188,6 +196,7 @@ export const productChainLinks: ProductChainLinks = { monad: "/data-streams/crypto-streams", opbnb: "/data-streams/crypto-streams", optimism: "/data-streams/crypto-streams", + pharos: "/data-streams/crypto-streams", polygon: "/data-streams/crypto-streams", polygonkatana: "/data-streams/crypto-streams", plasma: "/data-streams/crypto-streams", @@ -252,87 +261,89 @@ export const productChainLinks: ProductChainLinks = { }, }, linkTokenContracts: { + "0g": "/resources/link-token-contracts#0g", + abchain: "/resources/link-token-contracts#ab-chain", abstract: "/resources/link-token-contracts#abstract", + apechain: "/resources/link-token-contracts#apechain", arbitrum: "/resources/link-token-contracts#arbitrum", + arc: "/resources/link-token-contracts#arc-network", astar: "/resources/link-token-contracts#astar", avalanche: "/resources/link-token-contracts#avalanche", base: "/resources/link-token-contracts#base", - "bnb-chain": "/resources/link-token-contracts#bnb-chain", + berachain: "/resources/link-token-contracts#berachain", + bitlayer: "/resources/link-token-contracts#bitlayer", + bittensor: "/resources/link-token-contracts#bittensor-evm", blast: "/resources/link-token-contracts#blast", + bob: "/resources/link-token-contracts#bob", + botanix: "/resources/link-token-contracts#botanix", + "bnb-chain": "/resources/link-token-contracts#bnb-chain", + bsquared: "/resources/link-token-contracts#bsquared", celo: "/resources/link-token-contracts#celo", + core: "/resources/link-token-contracts#core", + corn: "/resources/link-token-contracts#corn", + cronos: "/resources/link-token-contracts#cronos", + cronoszkevm: "/resources/link-token-contracts#cronos-zkevm", + dogeos: "/resources/link-token-contracts#dogeos", + etherlink: "/resources/link-token-contracts#etherlink", ethereum: "/resources/link-token-contracts#ethereum", + everclear: "/resources/link-token-contracts#everclear", fantom: "/resources/link-token-contracts#fantom", + fraxtal: "/resources/link-token-contracts#fraxtal", "gnosis-chain": "/resources/link-token-contracts#gnosis-chain-xdai", + hashkey: "/resources/link-token-contracts#hashkey", hedera: "/resources/link-token-contracts#hedera", + hemi: "/resources/link-token-contracts#hemi", + henesys: "/resources/link-token-contracts#henesys", + hyperevm: "/resources/link-token-contracts#hyperevm", + ink: "/resources/link-token-contracts#ink", + janction: "/resources/link-token-contracts#janction", + kaia: "/resources/link-token-contracts#kaia", kroma: "/resources/link-token-contracts#kroma", - mantle: "/resources/link-token-contracts#mantle", + lens: "/resources/link-token-contracts#lens", linea: "/resources/link-token-contracts#linea", lisk: "/resources/link-token-contracts#lisk", - mint: "/resources/link-token-contracts#mint", + mantle: "/resources/link-token-contracts#mantle", + memento: "/resources/link-token-contracts#memento", + megaeth: "/resources/link-token-contracts#megaeth", + metal: "/resources/link-token-contracts#metal", metis: "/resources/link-token-contracts#metis", + mindnetwork: "/resources/link-token-contracts#mind-network", + mint: "/resources/link-token-contracts#mint", mode: "/resources/link-token-contracts#mode", + monad: "/resources/link-token-contracts#monad", moonbeam: "/resources/link-token-contracts#moonbeam", moonriver: "/resources/link-token-contracts#moonriver", neox: "/resources/link-token-contracts#neo-x", - henesys: "/resources/link-token-contracts#henesys", + opbnb: "/resources/link-token-contracts#opbnb", optimism: "/resources/link-token-contracts#op", pharos: "/resources/link-token-contracts#pharos", plasma: "/resources/link-token-contracts#plasma", - polygonzkevm: "/resources/link-token-contracts#polygon-zkevm", + plume: "/resources/link-token-contracts#plume", polygon: "/resources/link-token-contracts#polygon", + polygonkatana: "/resources/link-token-contracts#polygon-katana", + polygonzkevm: "/resources/link-token-contracts#polygon-zkevm", + ronin: "/resources/link-token-contracts#ronin", + rootstock: "/resources/link-token-contracts#rootstock", scroll: "/resources/link-token-contracts#scroll", + sei: "/resources/link-token-contracts#sei", + shibarium: "/resources/link-token-contracts#shibarium", solana: "/resources/link-token-contracts#solana", soneium: "/resources/link-token-contracts#soneium", - wemix: "/resources/link-token-contracts#wemix", - zksync: "/resources/link-token-contracts#zksync", - zircuit: "/resources/link-token-contracts#zircuit", - ronin: "/resources/link-token-contracts#ronin", - bsquared: "/resources/link-token-contracts#bsquared", - shibarium: "/resources/link-token-contracts#shibarium", sonic: "/resources/link-token-contracts#sonic", - bob: "/resources/link-token-contracts#bob", - worldchain: "/resources/link-token-contracts#world", - xdc: "/resources/link-token-contracts#xdc", - xlayer: "/resources/link-token-contracts#x-layer", - ink: "/resources/link-token-contracts#ink", - corn: "/resources/link-token-contracts#corn", - bitlayer: "/resources/link-token-contracts#bitlayer", - hashkey: "/resources/link-token-contracts#hashkey", - botanix: "/resources/link-token-contracts#botanix", - sei: "/resources/link-token-contracts#sei", - monad: "/resources/link-token-contracts#monad", - treasure: "/resources/link-token-contracts#treasure", - unichain: "/resources/link-token-contracts#unichain", - merlin: "/resources/link-token-contracts#merlin", - fraxtal: "/resources/link-token-contracts#fraxtal", - lens: "/resources/link-token-contracts#lens", - metal: "/resources/link-token-contracts#metal", - berachain: "/resources/link-token-contracts#berachain", - hemi: "/resources/link-token-contracts#hemi", - apechain: "/resources/link-token-contracts#apechain", - cronoszkevm: "/resources/link-token-contracts#cronos-zkevm", - cronos: "/resources/link-token-contracts#cronos", - mindnetwork: "/resources/link-token-contracts#mind-network", - core: "/resources/link-token-contracts#core", - plume: "/resources/link-token-contracts#plume", - rootstock: "/resources/link-token-contracts#rootstock", starknet: "/resources/link-token-contracts#starknet", superseed: "/resources/link-token-contracts#superseed", + tac: "/resources/link-token-contracts#tac", taiko: "/resources/link-token-contracts#taiko", - megaeth: "/resources/link-token-contracts#megaeth", + tempo: "/resources/link-token-contracts#tempo", + treasure: "/resources/link-token-contracts#treasure", + unichain: "/resources/link-token-contracts#unichain", + wemix: "/resources/link-token-contracts#wemix", + worldchain: "/resources/link-token-contracts#world", + xdc: "/resources/link-token-contracts#xdc", + xlayer: "/resources/link-token-contracts#x-layer", + zircuit: "/resources/link-token-contracts#zircuit", + zksync: "/resources/link-token-contracts#zksync", zora: "/resources/link-token-contracts#zora", - etherlink: "/resources/link-token-contracts#etherlink", - opbnb: "/resources/link-token-contracts#opbnb", - janction: "/resources/link-token-contracts#janction", - polygonkatana: "/resources/link-token-contracts#polygon-katana", - "0g": "/resources/link-token-contracts#0g", - hyperevm: "/resources/link-token-contracts#hyperevm", - kaia: "/resources/link-token-contracts#kaia", - tac: "/resources/link-token-contracts#tac", - memento: "/resources/link-token-contracts#memento", - bittensor: "/resources/link-token-contracts#bittensor-evm", - everclear: "/resources/link-token-contracts#everclear", - abchain: "/resources/link-token-contracts#ab-chain", }, } @@ -415,7 +426,6 @@ export const chainNames: Record<string, string> = { tac: "Tac", kaia: "Kaia", plasma: "Plasma", - jovay: "Jovay", memento: "Memento", xdc: "XDC", bittensor: "Bittensor EVM", @@ -423,4 +433,10 @@ export const chainNames: Record<string, string> = { abchain: "AB Chain", henesys: "Henesys", pharos: "Pharos", + morph: "Morph", + jovay: "Jovay", + stable: "Stable", + tempo: "Tempo", + arc: "Arc Network", + dogeos: "DogeOS", } diff --git a/src/components/Resource/README.md b/src/components/Resource/README.md new file mode 100644 index 00000000000..097d6befad1 --- /dev/null +++ b/src/components/Resource/README.md @@ -0,0 +1,106 @@ +# ResourceGrid + +## What it does + +This component displays a grid of resource cards. Each card can represent either an article or a video, with an optional image, title, description, and link. Article cards show a "Read the full article" footer with an arrow. + +## How to use it + +1. Import the component in your Astro layout or page: + +```astro +import ResourceGrid from "~/components/Resource/ResourceGrid.astro" import type {ResourceItem} from "~/components/Resource/ResourceGrid.astro" +``` + +2. (Optional) If you want to use imported images, import them: + +```astro +import myImage from "~/assets/images/my-image.png" +``` + +3. Create an array of resources with the information for each resource card + +4. Add the component to your page and pass in the resources: + +```astro +<ResourceGrid resources={yourResourcesArray} /> +``` + +## Example + +Here's a complete example showing how to use the component: + +```astro +--- +import ResourceGrid from "~/components/Resource/ResourceGrid.astro" +import type { ResourceItem } from "~/components/Resource/ResourceGrid.astro" +import tokenPoolImage from "~/assets/images/token-pool.png" + +const resources: ResourceItem[] = [ + { + image: tokenPoolImage, + imageAlt: "Token Pool illustration", + label: "Token Pool Types", + description: + "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs.", + link: "/resources/token-pool-types", + type: "article", + }, + { + label: "Getting Started with CCIP", + description: + "Learn how to build cross-chain applications using Chainlink CCIP in this comprehensive video tutorial.", + link: "https://youtube.com/watch?v=example", + type: "video", + }, + { + image: "/images/cross-chain-messaging.png", + imageAlt: "Cross-chain messaging diagram", + label: "Understanding Cross-Chain Messaging", + description: "A deep dive into how cross-chain messaging works and how to implement it in your smart contracts.", + link: "/resources/cross-chain-messaging", + type: "article", + }, +] +--- + +<ResourceGrid resources={resources} /> +``` + +## What you need to provide + +Each item in your `resources` array needs these fields: + +| Field | Required? | What it is | Example | +| --------------- | --------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------- | +| **label** | Yes | The title of the resource | `"Token Pool Types"` | +| **link** | Yes | Where the card should link to (can be internal or external) | `"/resources/token-pool-types"` or `"https://youtube.com/..."` | +| **description** | Yes | A description explaining what the resource covers | `"Explore the various token pool types..."` | +| **type** | Yes | The type of resource - either `"article"` or `"video"` | `"article"` | +| **image** | No | Either an imported image or a path string | `myImage` (imported) or `"/images/token-pool.png"` (string path) | +| **imageAlt** | No | Description of the image for accessibility (required if image is provided) | `"Token Pool illustration"` | + +## Where to put images + +Images are optional for resource cards. You have two options: + +### Option 1: Import images (recommended for images in your project) + +1. Place your image file in the `src/assets/images/` directory +2. Import it at the top of your file: + ```astro + import myImage from "~/assets/images/my-image.png" + ``` +3. Use the imported variable in your resource object + +### Option 2: Use a path string (for public directory or external images) + +1. Place your image file in the `/public/images/` directory +2. Reference it with the full path starting with `/images/` + +Both approaches work! Use imported images for better optimization, or use path strings for simplicity. + +## Resource types + +- **article**: Displays "Read the full article" footer with an arrow icon +- **video**: No special footer (just the card with title and description). For video resources, the `image` prop can be a YouTube video thumbnail URL, and the `link` prop can be the YouTube video URL diff --git a/src/components/Resource/ResourceCard.astro b/src/components/Resource/ResourceCard.astro new file mode 100644 index 00000000000..775abded644 --- /dev/null +++ b/src/components/Resource/ResourceCard.astro @@ -0,0 +1,47 @@ +--- +import { Typography, SvgArrowRight2, SvgButtonPlay } from "@chainlink/blocks" +import styles from "./ResourceCard.module.css" +import { ResourceItem } from "./ResourceGrid.astro" + +type Props = ResourceItem + +const { image, imageAlt, label, link, description, type } = Astro.props + +const imageSrc = typeof image === "string" ? image : image?.src + +const isVideo = type === "video" +--- + +<a href={link} class={styles.card} target={isVideo ? "_blank" : "_self"}> + { + imageSrc && ( + <div class={styles.imageWrapper}> + <img src={imageSrc} alt={imageAlt} class={styles.image} /> + <div class={styles.overlay}> + <span class={styles.playButtonWrapper}> + <SvgButtonPlay color="card" width={15} height={17.25} /> + </span> + </div> + </div> + ) + } + <div class={styles.content}> + <Typography + variant="body-semi-l" + style={{ + marginBottom: isVideo ? "var(--space-2x)" : "var(--space-8x)", + }}>{label}</Typography + > + <Typography variant="body-s" color="muted"> + {description} + </Typography> + </div> + { + type === "article" && ( + <div class={styles.cardFooter}> + <span class={styles.footerText}>Read the full article</span> + <SvgArrowRight2 color="muted" width={12} height={12} /> + </div> + ) + } +</a> diff --git a/src/components/Resource/ResourceCard.module.css b/src/components/Resource/ResourceCard.module.css new file mode 100644 index 00000000000..af9c4cc67ad --- /dev/null +++ b/src/components/Resource/ResourceCard.module.css @@ -0,0 +1,104 @@ +.card { + display: flex; + flex-direction: column; + background: var(--color-background); + padding: var(--space-6x); + gap: var(--space-4x); + border-right: 1px solid var(--border); + border-bottom: 1px solid var(--border); + text-decoration: none; + transition: background-color 0.2s; + min-height: 329px; + cursor: default; +} + +.card:nth-child(-n + 3) { + border-top: 1px solid var(--border); +} + +.card:hover { + background-color: var(--muted); +} + +.overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.playButtonWrapper { + background-color: var(--brand); + width: 45px; + height: 45px; + display: flex; + justify-content: center; + align-items: center; + & svg { + color: var(--white); + fill: var(--white); + } +} + +.imageWrapper { + width: 100%; + aspect-ratio: 16 / 9; + overflow: hidden; + border-radius: var(--space-2x); + position: relative; +} + +.image { + width: 100%; + height: 100%; + object-fit: cover; +} + +.content { + display: flex; + flex-direction: column; + flex: 1; +} + +.cardLabel { + font-size: 16px; + font-weight: 525; + color: var(--foreground); + margin-bottom: var(--space-2x); +} + +.cardFooter { + display: flex; + align-items: center; + width: 100%; + gap: var(--space-2x); + margin-top: var(--space-4x); +} + +.footerText { + font-size: 14px; + color: var(--color-text-secondary); +} +@media screen and (max-width: 1024px) { + .card:nth-child(-n + 3) { + border-top: none; + } + + .card:nth-child(-n + 2) { + border-top: 1px solid var(--border); + } +} + +@media screen and (max-width: 768px) { + .card:nth-child(n) { + border-top: none; + } + + .card:nth-child(1) { + border-top: 1px solid var(--border); + } +} diff --git a/src/components/Resource/ResourceGrid.astro b/src/components/Resource/ResourceGrid.astro new file mode 100644 index 00000000000..1ec37d2aac1 --- /dev/null +++ b/src/components/Resource/ResourceGrid.astro @@ -0,0 +1,24 @@ +--- +import type { ImageMetadata } from "astro" +import ResourceCard from "./ResourceCard.astro" +import styles from "./ResourceGrid.module.css" + +export interface ResourceItem { + image?: string | ImageMetadata + imageAlt?: string + label: string + link: string + description: string + type: "article" | "video" +} + +interface Props { + resources: ResourceItem[] +} + +const { resources } = Astro.props +--- + +<div class={styles.grid}> + {resources.map((resource) => <ResourceCard {...resource} />)} +</div> diff --git a/src/components/Resource/ResourceGrid.module.css b/src/components/Resource/ResourceGrid.module.css new file mode 100644 index 00000000000..02cb548eeb9 --- /dev/null +++ b/src/components/Resource/ResourceGrid.module.css @@ -0,0 +1,17 @@ +.grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + border-left: 1px solid var(--border); +} + +@media (max-width: 1024px) { + .grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 768px) { + .grid { + grid-template-columns: 1fr; + } +} diff --git a/src/components/Resource/ResourceSection.astro b/src/components/Resource/ResourceSection.astro new file mode 100644 index 00000000000..148f2b2213d --- /dev/null +++ b/src/components/Resource/ResourceSection.astro @@ -0,0 +1,23 @@ +--- +import { Typography } from "@chainlink/blocks" +import ResourceGrid from "./ResourceGrid.astro" +import type { ResourceItem } from "./ResourceGrid.astro" +import styles from "./ResourceSection.module.css" + +interface Props { + title: string + resources: ResourceItem[] +} + +const { title, resources } = Astro.props +--- + +<section class={styles.section}> + <Typography + variant="h2" + style={{ + fontSize: "32px", + }}>{title}</Typography + > + <ResourceGrid resources={resources} /> +</section> diff --git a/src/components/Resource/ResourceSection.module.css b/src/components/Resource/ResourceSection.module.css new file mode 100644 index 00000000000..434df633c45 --- /dev/null +++ b/src/components/Resource/ResourceSection.module.css @@ -0,0 +1,11 @@ +.section { + display: flex; + flex-direction: column; + gap: var(--space-8x); +} + +@media screen and (max-width: 425px) { + .section { + gap: var(--space-6x); + } +} diff --git a/src/components/RightSidebar/CopyPageLink/CopyPageLink.module.css b/src/components/RightSidebar/CopyPageLink/CopyPageLink.module.css new file mode 100644 index 00000000000..4e04dbfdb63 --- /dev/null +++ b/src/components/RightSidebar/CopyPageLink/CopyPageLink.module.css @@ -0,0 +1,175 @@ +/** + * Styles for CopyPageLink component + * Matches left sidebar dropdown styling pattern + */ + +.container { + position: relative; + width: 100%; +} + +.label { + display: block; + font-size: 0.75rem; + font-weight: 500; + color: var(--gray-600, #4b5563); + margin-bottom: 8px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.trigger { + /* Match left sidebar dropdown styling */ + display: flex; + align-items: center; + gap: 10px; + padding: 12px 14px; + background-color: var(--gray-100, #f3f4f6); + border: none; + border-radius: 6px; + cursor: pointer; + transition: all 0.2s ease; + font-size: 15px; + font-weight: 500; + color: var(--gray-900, #111827); + width: 100%; + position: relative; +} + +.trigger:hover { + background-color: var(--gray-200, #e5e7eb); +} + +.trigger:focus-visible { + outline: 2px solid var(--blue-500, #0847f7); + outline-offset: 2px; +} + +.triggerIcon { + width: 20px; + height: 20px; + flex-shrink: 0; +} + +.triggerText { + flex: 1; + text-align: left; + min-width: 0; + font-weight: 500; + color: var(--gray-900, #111827); +} + +.arrow { + flex-shrink: 0; + width: 16px; + height: 16px; + transition: transform 0.2s ease; + color: var(--gray-500, #6b7280); +} + +.trigger[aria-expanded="true"] .arrow { + transform: rotate(180deg); +} + +.dropdown { + position: absolute; + top: calc(100% + 4px); + left: 0; + right: 0; + background: white; + border: 1px solid var(--blue-200, #bfdbfe); + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + z-index: 1000; + overflow: hidden; + isolation: isolate; +} + +.dropdownContent { + padding: 6px; + display: flex; + flex-direction: column; + gap: 0; +} + +.dropdownItem { + display: flex; + align-items: flex-start; + gap: 12px; + width: 100%; + padding: 10px 12px; + background: transparent; + border: none; + border-bottom: 1px solid var(--gray-200, #e5e7eb); + border-radius: 0; + cursor: pointer; + text-align: left; + transition: all 0.2s ease; + position: relative; +} + +.dropdownItem:last-child { + border-bottom: none; +} + +.dropdownItem:first-child { + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} + +.dropdownItem:last-child { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; +} + +.dropdownItem:hover { + background-color: var(--blue-50, #eff6ff); +} + +.dropdownItem:focus-visible { + outline: 2px solid var(--blue-500, #0847f7); + outline-offset: -2px; +} + +.itemIcon { + width: 20px; + height: 20px; + flex-shrink: 0; + margin-top: 2px; + opacity: 0.7; +} + +.dropdownItem:hover .itemIcon { + opacity: 1; +} + +.itemContent { + flex: 1; + min-width: 0; +} + +.itemTitle { + font-size: 14px; + font-weight: 500; + color: var(--gray-900, #111827); + margin-bottom: 2px; +} + +.itemDescription { + font-size: 12px; + color: var(--gray-600, #4b5563); + line-height: 1.4; +} + +/* Responsive adjustments */ +@media (max-width: 1200px) { + .trigger { + padding: 10px 12px; + font-size: 14px; + } + + .triggerIcon { + width: 18px; + height: 18px; + } +} diff --git a/src/components/RightSidebar/CopyPageLink/CopyPageLink.tsx b/src/components/RightSidebar/CopyPageLink/CopyPageLink.tsx new file mode 100644 index 00000000000..b699145392c --- /dev/null +++ b/src/components/RightSidebar/CopyPageLink/CopyPageLink.tsx @@ -0,0 +1,339 @@ +/** + * Copy Page Link component for the MoreMenu + * Provides multiple actions for copying page content as markdown + */ + +import { useState, useRef, useEffect } from "react" +import { extractPageContent, copyToClipboard } from "./contentExtractor.js" +import { MarkdownPreviewModal } from "./MarkdownPreviewModal.js" +import type { CopyPageLinkProps, CopyAction } from "./types.js" +import styles from "./CopyPageLink.module.css" + +export function CopyPageLink({ className }: CopyPageLinkProps) { + const [isDropdownOpen, setIsDropdownOpen] = useState(false) + const [isModalOpen, setIsModalOpen] = useState(false) + const [extractedMarkdown, setExtractedMarkdown] = useState("") + const [pageTitle, setPageTitle] = useState("") + const [copiedAction, setCopiedAction] = useState<CopyAction | null>(null) + const dropdownRef = useRef<HTMLDivElement>(null) + const buttonRef = useRef<HTMLButtonElement>(null) + + // Close dropdown when clicking outside + useEffect(() => { + if (!isDropdownOpen) return + + const handleClickOutside = (event: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) && + buttonRef.current && + !buttonRef.current.contains(event.target as Node) + ) { + setIsDropdownOpen(false) + } + } + + document.addEventListener("mousedown", handleClickOutside) + return () => document.removeEventListener("mousedown", handleClickOutside) + }, [isDropdownOpen]) + + // Close dropdown on ESC + useEffect(() => { + if (!isDropdownOpen) return + + const handleEscape = (event: KeyboardEvent) => { + if (event.key === "Escape") { + setIsDropdownOpen(false) + buttonRef.current?.focus() + } + } + + document.addEventListener("keydown", handleEscape) + return () => document.removeEventListener("keydown", handleEscape) + }, [isDropdownOpen]) + + const toggleDropdown = () => { + setIsDropdownOpen(!isDropdownOpen) + } + + const handleAction = async (action: CopyAction) => { + setIsDropdownOpen(false) + + try { + // Try to fetch from API first (high quality markdown) + let markdown: string + let title: string + + try { + const currentPath = window.location.pathname + // Get current language from localStorage (same as left sidebar) + const storedLang = localStorage.getItem("docs-language-preference") + const currentLang = storedLang ? storedLang.replace(/"/g, "") : "go" + const response = await fetch(`/api/page-markdown?path=${encodeURIComponent(currentPath)}&lang=${currentLang}`) + + if (response.ok) { + markdown = await response.text() + // Extract title from markdown (first line after frontmatter) + const titleMatch = markdown.match(/^# (.+)$/m) + title = titleMatch ? titleMatch[1] : document.title + } else { + throw new Error("API fetch failed") + } + } catch (apiError) { + // Fallback to client-side extraction + console.warn("API fetch failed, falling back to client-side extraction:", apiError) + const content = extractPageContent() + + if (!content) { + alert("Failed to extract page content. Please try again.") + return + } + + markdown = content.markdown + title = content.title + } + + setExtractedMarkdown(markdown) + setPageTitle(title) + + switch (action) { + case "copy": + await copyToClipboard(markdown) + showCopyFeedback("copy") + break + + case "preview": + setIsModalOpen(true) + break + + case "chatgpt": { + // Copy markdown to clipboard first + await copyToClipboard(markdown) + + // Create instruction prompt for ChatGPT + const pageUrl = window.location.href + const instructionPrompt = `I'm analyzing a Chainlink documentation page: ${pageUrl} + +I have the full page content on my clipboard as plain text (Markdown). +The Chainlink docs site already copied it for me. + +Please ask me to paste it now. After I paste, please: +- Explain the contents clearly +- Answer any questions I have about Chainlink +- Help me understand how to implement the features described` + + const chatgptUrl = `https://chatgpt.com/?prompt=${encodeURIComponent(instructionPrompt)}` + + window.open(chatgptUrl, "_blank", "noopener,noreferrer") + break + } + + case "claude": { + // Copy markdown to clipboard first + await copyToClipboard(markdown) + + // Create instruction prompt for Claude + const pageUrl = window.location.href + const instructionPrompt = `I'm analyzing a Chainlink documentation page: ${pageUrl} + +I have the full page content on my clipboard as plain text (Markdown). +The Chainlink docs site already copied it for me. + +Please ask me to paste it now. After I paste, please: +- Explain the contents clearly +- Answer any questions I have about Chainlink +- Help me understand how to implement the features described` + + const claudeUrl = `https://claude.ai/new?q=${encodeURIComponent(instructionPrompt)}` + + window.open(claudeUrl, "_blank", "noopener,noreferrer") + break + } + } + } catch (error) { + console.error(`Error handling action ${action}:`, error) + alert(`Failed to ${action} page content. Please try again.`) + } + } + + const showCopyFeedback = (action: CopyAction) => { + setCopiedAction(action) + setTimeout(() => setCopiedAction(null), 2000) + } + + const closeModal = () => { + setIsModalOpen(false) + } + + return ( + <> + <div className={`${styles.container} ${className || ""}`}> + <label className={styles.label} htmlFor="copy-page-trigger"> + Copy Page + </label> + <button + id="copy-page-trigger" + ref={buttonRef} + className={styles.trigger} + onClick={toggleDropdown} + aria-expanded={isDropdownOpen} + aria-haspopup="true" + aria-label="Copy page content options" + type="button" + > + <svg + className={styles.triggerIcon} + width="20" + height="20" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + > + <path + d="M8 5H6C5.46957 5 4.96086 5.21071 4.58579 5.58579C4.21071 5.96086 4 6.46957 4 7V19C4 19.5304 4.21071 20.0391 4.58579 20.4142C4.96086 20.7893 5.46957 21 6 21H18C18.5304 21 19.0391 20.7893 19.4142 20.4142C19.7893 20.0391 20 19.5304 20 19V7C20 6.46957 19.7893 5.96086 19.4142 5.58579C19.0391 5.21071 18.5304 5 18 5H16M8 5C8 5.53043 8.21071 6.03914 8.58579 6.41421C8.96086 6.78929 9.46957 7 10 7H14C14.5304 7 15.0391 6.78929 15.4142 6.41421C15.7893 6.03914 16 5.53043 16 5M8 5C8 4.46957 8.21071 3.96086 8.58579 3.58579C8.96086 3.21071 9.46957 3 10 3H14C14.5304 3 15.0391 3.21071 15.4142 3.58579C15.7893 3.96086 16 4.46957 16 5M12 12H15M12 16H15M9 12H9.01M9 16H9.01" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + <span className={styles.triggerText}>{copiedAction === "copy" ? "Copied!" : "Copy page"}</span> + <svg className={styles.arrow} width="12" height="12" viewBox="0 0 12 12" fill="none"> + <path + d="M2.5 4.5L6 8L9.5 4.5" + stroke="currentColor" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + </button> + + {isDropdownOpen && ( + <div ref={dropdownRef} className={styles.dropdown} role="menu"> + <div className={styles.dropdownContent}> + <button + className={styles.dropdownItem} + onClick={() => handleAction("copy")} + role="menuitem" + type="button" + > + <svg + className={styles.itemIcon} + width="20" + height="20" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + > + <path + d="M9 5H7C6.46957 5 5.96086 5.21071 5.58579 5.58579C5.21071 5.96086 5 6.46957 5 7V19C5 19.5304 5.21071 20.0391 5.58579 20.4142C5.96086 20.7893 6.46957 21 7 21H17C17.5304 21 18.0391 20.7893 18.4142 20.4142C18.7893 20.0391 19 19.5304 19 19V7C19 6.46957 18.7893 5.96086 18.4142 5.58579C18.0391 5.21071 17.5304 5 17 5H15M9 5C9 5.53043 9.21071 6.03914 9.58579 6.41421C9.96086 6.78929 10.4696 7 11 7H13C13.5304 7 14.0391 6.78929 14.4142 6.41421C14.7893 6.03914 15 5.53043 15 5M9 5C9 4.46957 9.21071 3.96086 9.58579 3.58579C9.96086 3.21071 10.4696 3 11 3H13C13.5304 3 14.0391 3.21071 14.4142 3.58579C14.7893 3.96086 15 4.46957 15 5M12 12H15M12 16H15M9 12H9.01M9 16H9.01" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + <div className={styles.itemContent}> + <div className={styles.itemTitle}>Copy page</div> + <div className={styles.itemDescription}>Copy the page as MarkDown</div> + </div> + </button> + + <button + className={styles.dropdownItem} + onClick={() => handleAction("preview")} + role="menuitem" + type="button" + > + <svg + className={styles.itemIcon} + width="20" + height="20" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + > + <path + d="M15 12C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12Z" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M2.45801 12C3.73201 7.943 7.52301 5 12.001 5C16.479 5 20.268 7.943 21.542 12C20.268 16.057 16.479 19 12.001 19C7.52301 19 3.73201 16.057 2.45801 12Z" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + <div className={styles.itemContent}> + <div className={styles.itemTitle}>View as MarkDown</div> + <div className={styles.itemDescription}>View this page as plain text</div> + </div> + </button> + + <button + className={styles.dropdownItem} + onClick={() => handleAction("chatgpt")} + role="menuitem" + type="button" + > + <svg + className={styles.itemIcon} + width="20" + height="20" + fill="currentColor" + xmlns="http://www.w3.org/2000/svg" + strokeWidth="1.5" + viewBox="-0.17090198558635983 0.482230148717937 41.14235318283891 40.0339509076386" + aria-hidden="true" + > + <path + d="M37.532 16.87a9.963 9.963 0 0 0-.856-8.184 10.078 10.078 0 0 0-10.855-4.835A9.964 9.964 0 0 0 18.306.5a10.079 10.079 0 0 0-9.614 6.977 9.967 9.967 0 0 0-6.664 4.834 10.08 10.08 0 0 0 1.24 11.817 9.965 9.965 0 0 0 .856 8.185 10.079 10.079 0 0 0 10.855 4.835 9.965 9.965 0 0 0 7.516 3.35 10.078 10.078 0 0 0 9.617-6.981 9.967 9.967 0 0 0 6.663-4.834 10.079 10.079 0 0 0-1.243-11.813zM22.498 37.886a7.474 7.474 0 0 1-4.799-1.735c.061-.033.168-.091.237-.134l7.964-4.6a1.294 1.294 0 0 0 .655-1.134V19.054l3.366 1.944a.12.12 0 0 1 .066.092v9.299a7.505 7.505 0 0 1-7.49 7.496zM6.392 31.006a7.471 7.471 0 0 1-.894-5.023c.06.036.162.099.237.141l7.964 4.6a1.297 1.297 0 0 0 1.308 0l9.724-5.614v3.888a.12.12 0 0 1-.048.103l-8.051 4.649a7.504 7.504 0 0 1-10.24-2.744zM4.297 13.62A7.469 7.469 0 0 1 8.2 10.333c0 .068-.004.19-.004.274v9.201a1.294 1.294 0 0 0 .654 1.132l9.723 5.614-3.366 1.944a.12.12 0 0 1-.114.01L7.04 23.856a7.504 7.504 0 0 1-2.743-10.237zm27.658 6.437l-9.724-5.615 3.367-1.943a.121.121 0 0 1 .113-.01l8.052 4.648a7.498 7.498 0 0 1-1.158 13.528v-9.476a1.293 1.293 0 0 0-.65-1.132zm3.35-5.043c-.059-.037-.162-.099-.236-.141l-7.965-4.6a1.298 1.298 0 0 0-1.308 0l-9.723 5.614v-3.888a.12.12 0 0 1 .048-.103l8.05-4.645a7.497 7.497 0 0 1 11.135 7.763zm-21.063 6.929l-3.367-1.944a.12.12 0 0 1-.065-.092v-9.299a7.497 7.497 0 0 1 12.293-5.756 6.94 6.94 0 0 0-.236.134l-7.965 4.6a1.294 1.294 0 0 0-.654 1.132l-.006 11.225zm1.829-3.943l4.33-2.501 4.332 2.5v5l-4.331 2.5-4.331-2.5V18z" + fill="currentColor" + /> + </svg> + <div className={styles.itemContent}> + <div className={styles.itemTitle}>Open in ChatGPT</div> + <div className={styles.itemDescription}>Ask questions about this page</div> + </div> + </button> + + <button + className={styles.dropdownItem} + onClick={() => handleAction("claude")} + role="menuitem" + type="button" + > + <svg + className={styles.itemIcon} + width="20" + height="20" + fill="currentColor" + fillRule="evenodd" + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + aria-hidden="true" + > + <path d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z" /> + </svg> + <div className={styles.itemContent}> + <div className={styles.itemTitle}>Open in Claude</div> + <div className={styles.itemDescription}>Ask questions about this page</div> + </div> + </button> + </div> + </div> + )} + </div> + + <MarkdownPreviewModal markdown={extractedMarkdown} isOpen={isModalOpen} onClose={closeModal} title={pageTitle} /> + </> + ) +} diff --git a/src/components/RightSidebar/CopyPageLink/MarkdownPreviewModal.module.css b/src/components/RightSidebar/CopyPageLink/MarkdownPreviewModal.module.css new file mode 100644 index 00000000000..14f42931a77 --- /dev/null +++ b/src/components/RightSidebar/CopyPageLink/MarkdownPreviewModal.module.css @@ -0,0 +1,259 @@ +/** + * Styles for MarkdownPreviewModal component + */ + +.backdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; + padding: var(--space-4x); + animation: fadeIn 0.2s ease-out; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.modal { + background: var(--color-background-primary, #ffffff); + border-radius: var(--border-radius-primary, 8px); + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2); + display: flex; + flex-direction: column; + max-width: 800px; + width: 100%; + max-height: 90vh; + animation: slideIn 0.3s ease-out; + outline: none; +} + +@keyframes slideIn { + from { + transform: translateY(-20px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +} + +/* Mobile: full screen */ +@media (max-width: 768px) { + .backdrop { + padding: 0; + } + + .modal { + max-width: 100%; + max-height: 100vh; + border-radius: 0; + height: 100%; + } +} + +.header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-4x) var(--space-5x); + border-bottom: 1px solid var(--theme-divider, var(--gray-200)); +} + +.title { + margin: 0; + font-size: 18px; + font-weight: 600; + color: var(--color-text-heading, var(--gray-900)); +} + +.closeButton { + background: none; + border: none; + font-size: 24px; + color: var(--gray-600); + cursor: pointer; + padding: var(--space-1x); + line-height: 1; + transition: color 0.2s ease; + border-radius: var(--border-radius-primary, 4px); + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; +} + +.closeButton:hover { + color: var(--gray-900); + background-color: var(--theme-bg-hover, var(--gray-100)); +} + +.closeButton:focus-visible { + outline: 2px solid var(--blue-600); + outline-offset: 2px; +} + +.content { + flex: 1; + overflow: auto; + padding: var(--space-4x) var(--space-5x); +} + +.markdown { + margin: 0; + padding: var(--space-4x); + background-color: var(--gray-50); + border-radius: var(--border-radius-primary, 4px); + overflow: auto; + font-size: 13px; + line-height: 1.6; + font-family: "Courier New", Courier, monospace; + white-space: pre-wrap; + word-break: break-word; + border: 1px solid var(--gray-200); + color: var(--gray-900); +} + +.markdown code { + font-family: inherit; + background: none; + padding: 0; +} + +.footer { + display: flex; + gap: var(--space-3x); + padding: var(--space-4x) var(--space-5x); + border-top: 1px solid var(--theme-divider, var(--gray-200)); + justify-content: flex-end; +} + +.copyButton, +.cancelButton { + display: flex; + align-items: center; + justify-content: center; + gap: var(--space-2x); + padding: var(--space-2x) var(--space-4x); + border-radius: var(--border-radius-primary, 4px); + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + border: none; + min-width: 80px; +} + +.copyButton { + background-color: var(--blue-600); + color: white; +} + +.copyButton:hover { + background-color: var(--blue-700); +} + +.copyButton:active { + background-color: var(--blue-800); +} + +.copyButton:focus-visible { + outline: 2px solid var(--blue-600); + outline-offset: 2px; +} + +.cancelButton { + background-color: transparent; + color: var(--gray-700); + border: 1px solid var(--gray-300); +} + +.cancelButton:hover { + background-color: var(--gray-100); + border-color: var(--gray-400); +} + +.cancelButton:focus-visible { + outline: 2px solid var(--blue-600); + outline-offset: 2px; +} + +/* Mobile adjustments */ +@media (max-width: 768px) { + .header, + .content, + .footer { + padding: var(--space-3x) var(--space-4x); + } + + .footer { + flex-direction: column-reverse; + } + + .copyButton, + .cancelButton { + width: 100%; + } +} + +/* Screen reader only utility */ +.srOnly { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +/* Dark theme support */ +@media (prefers-color-scheme: dark) { + .modal { + background: var(--color-background-primary, #1a1a1a); + } + + .title { + color: var(--color-text-heading, #ffffff); + } + + .markdown { + background-color: var(--gray-900); + color: var(--gray-100); + border-color: var(--gray-700); + } + + .closeButton { + color: var(--gray-400); + } + + .closeButton:hover { + color: var(--gray-100); + background-color: var(--gray-800); + } + + .cancelButton { + color: var(--gray-300); + border-color: var(--gray-600); + } + + .cancelButton:hover { + background-color: var(--gray-800); + border-color: var(--gray-500); + } +} diff --git a/src/components/RightSidebar/CopyPageLink/MarkdownPreviewModal.tsx b/src/components/RightSidebar/CopyPageLink/MarkdownPreviewModal.tsx new file mode 100644 index 00000000000..c4a84face22 --- /dev/null +++ b/src/components/RightSidebar/CopyPageLink/MarkdownPreviewModal.tsx @@ -0,0 +1,130 @@ +/** + * Modal component for previewing markdown content + */ + +import { useEffect, useRef, useState } from "react" +import { createPortal } from "react-dom" +import { FocusTrap } from "focus-trap-react" +import { useKeyPress } from "~/hooks/useKeyPress.ts" +import { copyToClipboard } from "./contentExtractor.js" +import type { MarkdownPreviewModalProps } from "./types.js" +import styles from "./MarkdownPreviewModal.module.css" + +export function MarkdownPreviewModal({ markdown, isOpen, onClose, title }: MarkdownPreviewModalProps) { + const modalRef = useRef<HTMLDivElement>(null) + const previousActiveElement = useRef<HTMLElement | null>(null) + const [isCopied, setIsCopied] = useState(false) + + // Use the shared useKeyPress hook for ESC key handling + useKeyPress("Escape", { onDown: onClose }) + + useEffect(() => { + if (!isOpen) return + + // Store the previously focused element + previousActiveElement.current = document.activeElement as HTMLElement + + // Focus the modal + modalRef.current?.focus() + + // Prevent body scroll when modal is open + document.body.style.overflow = "hidden" + + return () => { + document.body.style.overflow = "" + + // Restore focus to the previous element + previousActiveElement.current?.focus() + } + }, [isOpen]) + + const handleCopyClick = async () => { + try { + await copyToClipboard(markdown) + setIsCopied(true) + setTimeout(() => setIsCopied(false), 2000) + } catch (error) { + console.error("Failed to copy markdown:", error) + alert("Failed to copy to clipboard. Please try again.") + } + } + + const handleBackdropClick = (e: React.MouseEvent<HTMLDivElement>) => { + if (e.target === e.currentTarget) { + onClose() + } + } + + if (!isOpen) return null + if (typeof document === "undefined") return null // SSR safety + + return createPortal( + <FocusTrap> + <div className={styles.backdrop} onClick={handleBackdropClick}> + <div + ref={modalRef} + className={styles.modal} + role="dialog" + aria-modal="true" + aria-labelledby="modal-title" + aria-describedby="modal-description" + tabIndex={-1} + > + <div className={styles.header}> + <h2 id="modal-title" className={styles.title}> + {title || "Markdown Preview"} + </h2> + <button className={styles.closeButton} onClick={onClose} aria-label="Close modal" type="button"> + ✕ + </button> + </div> + + <div className={styles.content}> + <div id="modal-description" className={styles.srOnly}> + Preview of extracted markdown content. You can copy this content or close the preview. + </div> + <pre className={styles.markdown} data-no-copy-button="true"> + <code>{markdown}</code> + </pre> + </div> + + <div className={styles.footer}> + <button className={styles.copyButton} onClick={handleCopyClick} type="button"> + {isCopied ? ( + <> + <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path + d="M13.5 4.5L6 12L2.5 8.5" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + Copied! + </> + ) : ( + <> + <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path + d="M9 5H7C6.46957 5 5.96086 5.21071 5.58579 5.58579C5.21071 5.96086 5 6.46957 5 7V19C5 19.5304 5.21071 20.0391 5.58579 20.4142C5.96086 20.7893 6.46957 21 7 21H17C17.5304 21 18.0391 20.7893 18.4142 20.4142C18.7893 20.0391 19 19.5304 19 19V7C19 6.46957 18.7893 5.96086 18.4142 5.58579C18.0391 5.21071 17.5304 5 17 5H15M9 5C9 5.53043 9.21071 6.03914 9.58579 6.41421C9.96086 6.78929 10.4696 7 11 7H13C13.5304 7 14.0391 6.78929 14.4142 6.41421C14.7893 6.03914 15 5.53043 15 5M9 5C9 4.46957 9.21071 3.96086 9.58579 3.58579C9.96086 3.21071 10.4696 3 11 3H13C13.5304 3 14.0391 3.21071 14.4142 3.58579C14.7893 3.96086 15 4.46957 15 5M12 12H15M12 16H15M9 12H9.01M9 16H9.01" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + Copy + </> + )} + </button> + <button className={styles.cancelButton} onClick={onClose} type="button"> + Close + </button> + </div> + </div> + </div> + </FocusTrap>, + document.body + ) +} diff --git a/src/components/RightSidebar/CopyPageLink/contentExtractor.ts b/src/components/RightSidebar/CopyPageLink/contentExtractor.ts new file mode 100644 index 00000000000..7a99770e7de --- /dev/null +++ b/src/components/RightSidebar/CopyPageLink/contentExtractor.ts @@ -0,0 +1,404 @@ +/** + * Content extraction utility for converting documentation pages to Markdown + */ + +import type { ExtractedContent, ExtractionConfig } from "./types.js" +import { + formatHeading, + formatLink, + formatBold, + formatItalic, + formatInlineCode, + formatCodeBlock, + formatBlockquote, + formatTable, + formatImage, + formatHorizontalRule, + formatFrontmatter, + cleanText, + resolveUrl, + stripHighlightComments, +} from "~/lib/markdown/index.js" + +/** + * Default configuration for content extraction + */ +const DEFAULT_CONFIG: ExtractionConfig = { + selectorsToRemove: [ + // Navigation and UI elements + "nav", + ".breadcrumb", + ".pagination", + + // Interactive elements + "button", + ".copy-iconbutton", + ".copy-code-button", + + // Sidebar and TOC + ".sidebar", + ".table-of-contents", + ".right-sidebar", + ".left-sidebar", + + // Footer and metadata + "footer", + ".theme-edit-this-page", + ".theme-last-updated", + ".edit-page", + + // Feedback and social + ".feedback", + ".social-links", + ".share-buttons", + + // Ads and external content + ".advertisement", + "iframe", + + // Chainlink-specific elements + ".header-link", + ".anchor-link", + + // Astro-specific elements (hydration scripts, etc.) + "script", + "style", + "astro-island", + ], + contentSelector: "article, main, .content, [role='main']", + includeFrontmatter: true, +} + +/** + * Extracts the main content from the current page + * @param config - Extraction configuration + * @returns The extracted content or null if extraction fails + */ +export function extractPageContent(config: Partial<ExtractionConfig> = {}): ExtractedContent | null { + const fullConfig = { ...DEFAULT_CONFIG, ...config } + + try { + // Find the main content element + const mainContent = document.querySelector(fullConfig.contentSelector) + if (!mainContent) { + console.error("Could not find main content element") + return null + } + + // Clone the content to avoid modifying the page + const contentClone = mainContent.cloneNode(true) as HTMLElement + + // Remove unwanted elements + fullConfig.selectorsToRemove.forEach((selector) => { + const elements = contentClone.querySelectorAll(selector) + elements.forEach((el) => el.remove()) + }) + + // Get page title + const title = getPageTitle() + + // Convert to markdown + const markdown = convertToMarkdown(contentClone) + + // Add frontmatter if enabled + const finalMarkdown = fullConfig.includeFrontmatter + ? addFrontmatter({ markdown, title, url: window.location.href }) + : markdown + + return { + markdown: finalMarkdown, + title, + url: window.location.href, + timestamp: new Date(), + } + } catch (error) { + console.error("Error extracting page content:", error) + return null + } +} + +/** + * Gets the page title from various possible sources + * @returns The page title + */ +function getPageTitle(): string { + // Try document title first + if (document.title && document.title !== "Documentation") { + return document.title.replace(" | Chainlink Documentation", "").trim() + } + + // Try h1 heading + const h1 = document.querySelector("article h1, main h1, h1") + if (h1?.textContent) { + return h1.textContent.trim() + } + + // Try meta og:title + const ogTitle = document.querySelector('meta[property="og:title"]') + const ogTitleContent = ogTitle?.getAttribute("content") + if (ogTitleContent) { + return ogTitleContent.trim() + } + + return "Documentation Page" +} + +/** + * Converts HTML element to Markdown + * @param element - The HTML element to convert + * @returns The markdown string + */ +function convertToMarkdown(element: HTMLElement): string { + let markdown = "" + + // Process child nodes + element.childNodes.forEach((node) => { + if (node.nodeType === Node.TEXT_NODE) { + const text = node.textContent?.trim() + if (text) { + markdown += cleanText(text) + "\n" + } + } else if (node.nodeType === Node.ELEMENT_NODE) { + const el = node as HTMLElement + markdown += convertElementToMarkdown(el) + } + }) + + return markdown.trim() +} + +/** + * Converts a single HTML element to Markdown based on its tag + * @param el - The HTML element + * @returns The markdown representation + */ +function convertElementToMarkdown(el: HTMLElement): string { + // Check for CodeHighlightBlockMulti FIRST before processing by tag + if (el.classList.contains("code-block-container")) { + return convertCodeBlockMultiToMarkdown(el) + } + + const tag = el.tagName.toLowerCase() + + switch (tag) { + case "h1": + return formatHeading(1, cleanText(el.textContent || "")) + case "h2": + return formatHeading(2, cleanText(el.textContent || "")) + case "h3": + return formatHeading(3, cleanText(el.textContent || "")) + case "h4": + return formatHeading(4, cleanText(el.textContent || "")) + case "h5": + return formatHeading(5, cleanText(el.textContent || "")) + case "h6": + return formatHeading(6, cleanText(el.textContent || "")) + + case "p": + return `${convertToMarkdown(el)}\n\n` + + case "a": { + const href = el.getAttribute("href") || "" + const text = cleanText(el.textContent || "") + const fullUrl = resolveUrl(href) + return formatLink(text, fullUrl) + } + + case "strong": + case "b": + return formatBold(cleanText(el.textContent || "")) + + case "em": + case "i": + return formatItalic(cleanText(el.textContent || "")) + + case "code": + // Inline code + if (el.parentElement?.tagName !== "PRE") { + return formatInlineCode(el.textContent || "") + } + // Block code - handled by pre tag + return el.textContent || "" + + case "pre": { + const code = el.querySelector("code") + const language = code?.className?.match(/language-(\w+)/)?.[1] || "" + const codeText = code?.textContent || el.textContent || "" + return formatCodeBlock(codeText, language) + } + + case "ul": + case "ol": { + const items = Array.from(el.children) + .filter((child) => child.tagName.toLowerCase() === "li") + .map((li, index) => { + const bullet = tag === "ul" ? "-" : `${index + 1}.` + const content = convertToMarkdown(li as HTMLElement).trim() + return `${bullet} ${content}` + }) + .join("\n") + return `${items}\n\n` + } + + case "li": + return convertToMarkdown(el) + + case "blockquote": + return formatBlockquote(convertToMarkdown(el)) + + case "table": + return convertTableToMarkdown(el) + + case "img": { + const src = el.getAttribute("src") || "" + const alt = el.getAttribute("alt") || "" + const fullSrc = resolveUrl(src) + return formatImage(alt, fullSrc) + } + + case "hr": + return formatHorizontalRule() + + case "br": + return "\n" + + case "div": + case "section": + case "aside": { + // Check for special Chainlink components (callouts, admonitions, etc.) + if (el.classList.contains("callout") || el.classList.contains("admonition")) { + return convertCalloutToMarkdown(el) + } + return convertToMarkdown(el) + } + + default: + // For unknown tags, process children + return convertToMarkdown(el) + } +} + +/** + * Converts a table element to Markdown + * @param table - The table element + * @returns The markdown table + */ +function convertTableToMarkdown(table: HTMLElement): string { + const rows: string[][] = [] + + // Get all rows + const tableRows = table.querySelectorAll("tr") + tableRows.forEach((row) => { + const cells: string[] = [] + row.querySelectorAll("td, th").forEach((cell) => { + cells.push(cleanText(cell.textContent || "")) + }) + if (cells.length > 0) { + rows.push(cells) + } + }) + + if (rows.length === 0) return "" + + return formatTable(rows) +} + +/** + * Converts CodeHighlightBlockMulti component to Markdown + * @param container - The code block container element (cloned) + * @returns The markdown code block + */ +function convertCodeBlockMultiToMarkdown(container: HTMLElement): string { + // Get the current language from the container + const currentLang = container.getAttribute("data-lang") || "" + const blockId = container.getAttribute("id") || "" + + // The container is a CLONE, so it doesn't have the JavaScript properties. + // We need to find the ORIGINAL element in the page to get _languagesData + interface LanguageData { + code: string + title?: string + } + + let languagesData: Record<string, LanguageData> | undefined + + if (blockId) { + const originalContainer = document.getElementById(blockId) as HTMLElement & { + _languagesData?: Record<string, LanguageData> + } + if (originalContainer) { + languagesData = originalContainer._languagesData + } + } + + // If we found the original data, use it + if (languagesData && languagesData[currentLang]) { + const codeContent = languagesData[currentLang].code || "" + // Strip highlight comments using the shared formatter + const cleanCode = stripHighlightComments(codeContent) + return formatCodeBlock(cleanCode, currentLang) + } + + // Fallback: Extract code from the visible DOM table in the clone + const codeLines: string[] = [] + const lineElements = container.querySelectorAll(".line") + lineElements.forEach((lineElement) => { + const lineText = lineElement.textContent || "" + codeLines.push(lineText) + }) + + const codeContent = codeLines.join("\n") + return formatCodeBlock(codeContent, currentLang) +} + +/** + * Converts callout/admonition elements to Markdown + * @param el - The callout element + * @returns The markdown representation + */ +function convertCalloutToMarkdown(el: HTMLElement): string { + const type = el.getAttribute("data-type") || "note" + const content = convertToMarkdown(el).trim() + return `> **${type.toUpperCase()}**\n> ${content.replace(/\n/g, "\n> ")}\n\n` +} + +/** + * Adds frontmatter to the markdown content + * @param content - The content object + * @returns The markdown with frontmatter + */ +function addFrontmatter(content: { markdown: string; title: string; url: string }): string { + const frontmatter = formatFrontmatter({ + title: content.title, + url: content.url, + extracted: new Date().toISOString(), + }) + + return frontmatter + content.markdown +} + +/** + * Copies text to clipboard using the modern Clipboard API + * @param text - The text to copy + * @returns Promise that resolves when copy is complete + */ +export async function copyToClipboard(text: string): Promise<void> { + try { + if (navigator.clipboard && navigator.clipboard.writeText) { + await navigator.clipboard.writeText(text) + } else { + // Fallback for older browsers + const textArea = document.createElement("textarea") + textArea.value = text + textArea.style.position = "fixed" + textArea.style.left = "-999999px" + document.body.appendChild(textArea) + textArea.select() + document.execCommand("copy") + document.body.removeChild(textArea) + } + } catch (error) { + console.error("Failed to copy to clipboard:", error) + throw new Error("Failed to copy to clipboard") + } +} diff --git a/src/components/RightSidebar/CopyPageLink/index.ts b/src/components/RightSidebar/CopyPageLink/index.ts new file mode 100644 index 00000000000..22a777ffc0d --- /dev/null +++ b/src/components/RightSidebar/CopyPageLink/index.ts @@ -0,0 +1,8 @@ +/** + * Barrel export for CopyPageLink module + */ + +export { CopyPageLink } from "./CopyPageLink.js" +export { MarkdownPreviewModal } from "./MarkdownPreviewModal.js" +export * from "./types.js" +export * from "./contentExtractor.js" diff --git a/src/components/RightSidebar/CopyPageLink/types.ts b/src/components/RightSidebar/CopyPageLink/types.ts new file mode 100644 index 00000000000..86df43198db --- /dev/null +++ b/src/components/RightSidebar/CopyPageLink/types.ts @@ -0,0 +1,66 @@ +/** + * Type definitions for CopyPageLink component + */ + +/** + * Available actions for the copy page feature + */ +export type CopyAction = "copy" | "preview" | "chatgpt" | "claude" + +/** + * Extracted content from the documentation page + */ +export interface ExtractedContent { + /** The markdown content of the page */ + markdown: string + /** The title of the page */ + title: string + /** The full URL of the page */ + url: string + /** Timestamp when content was extracted */ + timestamp: Date +} + +/** + * Props for the CopyPageLink component + */ +export interface CopyPageLinkProps { + /** Optional class name for styling */ + className?: string +} + +/** + * Props for the MarkdownPreviewModal component + */ +export interface MarkdownPreviewModalProps { + /** The markdown content to display */ + markdown: string + /** Whether the modal is open */ + isOpen: boolean + /** Callback to close the modal */ + onClose: () => void + /** Page title for modal header */ + title?: string +} + +/** + * Configuration for content extraction + */ +export interface ExtractionConfig { + /** Selectors for elements to remove from content */ + selectorsToRemove: string[] + /** Main content selector */ + contentSelector: string + /** Whether to include frontmatter */ + includeFrontmatter: boolean +} + +/** + * Result of a copy operation + */ +export interface CopyResult { + /** Whether the operation was successful */ + success: boolean + /** Error message if operation failed */ + error?: string +} diff --git a/src/components/RightSidebar/LlmsLink.tsx b/src/components/RightSidebar/LlmsLink.tsx index 31b6f55b406..42bc23ac2bc 100644 --- a/src/components/RightSidebar/LlmsLink.tsx +++ b/src/components/RightSidebar/LlmsLink.tsx @@ -8,6 +8,20 @@ interface LlmsLinkProps { currentPageLanguage?: string | null } +// Map section slugs to display names +const SECTION_DISPLAY_NAMES: Record<string, string> = { + vrf: "VRF", + ccip: "CCIP", + "data-feeds": "Data Feeds", + "data-streams": "Data Streams", + "dta-technical-standard": "DTA", + automation: "Automation", + "chainlink-functions": "Functions", + quickstarts: "Quickstarts", + resources: "Resources", + // Add more as needed +} + export function LlmsLink({ section, supportedLanguages, currentPageLanguage }: LlmsLinkProps) { // Subscribe to the language store for reactive updates const storeLanguage = useStore(selectedLanguage) @@ -18,17 +32,27 @@ export function LlmsLink({ section, supportedLanguages, currentPageLanguage }: L // Generate the appropriate link const hasLanguages = supportedLanguages.length > 0 let llmsHref = "" - let llmsLabel = "View as plain text for LLMs" + let llmsLabel = "Complete docs (TXT)" if (hasLanguages) { // Language-specific section (like CRE) const langToUse = effectiveLanguage && supportedLanguages.includes(effectiveLanguage) ? effectiveLanguage : supportedLanguages[0] llmsHref = `/${section}/llms-full-${langToUse}.txt` - llmsLabel = `View ${langToUse.toUpperCase()} docs for LLMs` + + // For CRE: just show language, no product name + if (section === "cre") { + llmsLabel = `Complete ${langToUse.toUpperCase()} docs (TXT)` + } else { + // For other language-specific sections (if any in future) + const productName = SECTION_DISPLAY_NAMES[section] || section.toUpperCase() + llmsLabel = `Complete ${productName} ${langToUse.toUpperCase()} docs (TXT)` + } } else { - // Single file section + // Single file section - include product name llmsHref = `/${section}/llms-full.txt` + const productName = SECTION_DISPLAY_NAMES[section] || section.toUpperCase() + llmsLabel = `Complete ${productName} docs (TXT)` } return ( diff --git a/src/components/RightSidebar/MoreMenu.astro b/src/components/RightSidebar/MoreMenu.astro index b7c61cbf93e..3ea4d3d931f 100644 --- a/src/components/RightSidebar/MoreMenu.astro +++ b/src/components/RightSidebar/MoreMenu.astro @@ -6,7 +6,6 @@ import { LlmsLink } from "./LlmsLink" const { editHref, frontmatter } = Astro.props const pathname = Astro.url.pathname const section = pathname.split("/").filter(Boolean)[0] - // Determine language from frontmatter or filename const sdkLang = frontmatter?.sdkLang const filename = pathname.split("/").pop() || "" @@ -64,48 +63,6 @@ const supportedLanguages = cfg?.languages || [] </li> ) } - <li class="header-link"> - <a href="/builders-quick-links" target="_blank" id="quick-links-sidebar-link"> - <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> - <path - d="M2.5 9.20055L7.18129 2H12.2965L9.62194 5.59959H13.5L5.97787 14H4.50671L7.18135 9.20055H2.5Z" - fill="#0D5DFF"></path> - </svg> - <p>Quick links for builders</p> - </a> - </li> - { - CONFIG.COMMUNITY_INVITE_URL && ( - <li class="header-link"> - <a href={CONFIG.COMMUNITY_INVITE_URL} target="_blank"> - <svg - viewBox="0 0 28 28" - version="1.1" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - fill="#0D5DFF" - stroke="#0D5DFF" - width="16" - height="16" - > - <> - <g stroke-width="0" /> - <g stroke-linecap="round" stroke-linejoin="round" /> - <g> - <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> - <g id="people_community" fill="#0D5DFF" fill-rule="nonzero"> - <path d="M17.75,18 C18.7164983,18 19.5,18.7835017 19.5,19.75 L19.5,21.7519766 L19.4921156,21.8604403 C19.1813607,23.9866441 17.2715225,25.0090369 14.0667905,25.0090369 C10.8736123,25.0090369 8.93330141,23.9983408 8.51446278,21.8965776 L8.5,21.75 L8.5,19.75 C8.5,18.7835017 9.28350169,18 10.25,18 L17.75,18 Z M18.2439108,11.9999135 L24.25,12 C25.2164983,12 26,12.7835017 26,13.75 L26,15.7519766 L25.9921156,15.8604403 C25.6813607,17.9866441 23.7715225,19.0090369 20.5667905,19.0090369 L20.3985759,19.007437 C20.0900029,17.9045277 19.1110503,17.0815935 17.9288034,17.0057197 L17.75,17 L16.8277704,17.0007255 C17.8477843,16.1757619 18.5,14.9140475 18.5,13.5 C18.5,12.9740145 18.4097576,12.4691063 18.2439108,11.9999135 Z M3.75,12 L9.75608915,11.9999135 C9.59024243,12.4691063 9.5,12.9740145 9.5,13.5 C9.5,14.8308682 10.0777413,16.0267978 10.996103,16.8506678 L11.1722296,17.0007255 L10.25,17 C8.9877951,17 7.92420242,17.85036 7.60086562,19.0094363 L7.5667905,19.0090369 C4.37361228,19.0090369 2.43330141,17.9983408 2.01446278,15.8965776 L2,15.75 L2,13.75 C2,12.7835017 2.78350169,12 3.75,12 Z M14,10 C15.9329966,10 17.5,11.5670034 17.5,13.5 C17.5,15.4329966 15.9329966,17 14,17 C12.0670034,17 10.5,15.4329966 10.5,13.5 C10.5,11.5670034 12.0670034,10 14,10 Z M20.5,4 C22.4329966,4 24,5.56700338 24,7.5 C24,9.43299662 22.4329966,11 20.5,11 C18.5670034,11 17,9.43299662 17,7.5 C17,5.56700338 18.5670034,4 20.5,4 Z M7.5,4 C9.43299662,4 11,5.56700338 11,7.5 C11,9.43299662 9.43299662,11 7.5,11 C5.56700338,11 4,9.43299662 4,7.5 C4,5.56700338 5.56700338,4 7.5,4 Z" /> - </g> - </g> - </g> - </> - </svg> - - <p>Join our community</p> - </a> - </li> - ) - } </ul> <style> diff --git a/src/components/RightSidebar/RightSidebar.astro b/src/components/RightSidebar/RightSidebar.astro index 4f4517a0148..3d8f0918ba1 100644 --- a/src/components/RightSidebar/RightSidebar.astro +++ b/src/components/RightSidebar/RightSidebar.astro @@ -3,25 +3,20 @@ import MoreMenu from "./MoreMenu.astro" import { Feedback } from "../PageContent/Feedback" import { MarkdownHeading } from "astro" import TableOfContents from "~/components/TableOfContents/TableOfContents" -import { LanguageSwitcherDropdown } from "~/components/LanguageSwitcherDropdown" +import { CopyPageLink } from "./CopyPageLink" export type Props = { githubEditUrl: string headings: MarkdownHeading[] - showLanguageSwitcher?: boolean frontmatter?: Record<string, any> } -const { githubEditUrl, showLanguageSwitcher, headings, frontmatter } = Astro.props +const { githubEditUrl, headings, frontmatter } = Astro.props --- <section class="sidebar-nav" aria-labelledby="grid-right" data-sticky> - { - showLanguageSwitcher && ( - <div class="language-switcher-wrapper"> - <LanguageSwitcherDropdown client:only="react" /> - </div> - ) - } + <div class="copy-page-wrapper"> + <CopyPageLink client:only="react" /> + </div> <h2 class="heading">On this page</h2> <div class="toc-wrapper"> <TableOfContents client:media="(min-width: 50em)" initialHeadings={headings} /> @@ -60,7 +55,7 @@ const { githubEditUrl, showLanguageSwitcher, headings, frontmatter } = Astro.pro margin-top: var(--space-3x); } - .language-switcher-wrapper { + .copy-page-wrapper { margin-bottom: var(--space-6x); } diff --git a/src/components/LanguageSwitcherDropdown.module.css b/src/components/SidebarDropdown/SidebarDropdown.module.css similarity index 90% rename from src/components/LanguageSwitcherDropdown.module.css rename to src/components/SidebarDropdown/SidebarDropdown.module.css index 1df7c41ca4d..7d6e192d3f1 100644 --- a/src/components/LanguageSwitcherDropdown.module.css +++ b/src/components/SidebarDropdown/SidebarDropdown.module.css @@ -1,3 +1,14 @@ +.selector { + display: flex; + align-items: center; + padding: var(--space-3x) var(--space-3x); + border-bottom: 1px solid var(--border-color, #e5e7eb); + background: var(--color-background-primary, #ffffff); + position: sticky; + top: 0; + z-index: 10; +} + .dropdown { position: relative; width: 100%; diff --git a/src/components/SidebarDropdown/SidebarDropdown.tsx b/src/components/SidebarDropdown/SidebarDropdown.tsx new file mode 100644 index 00000000000..753bf0c58cb --- /dev/null +++ b/src/components/SidebarDropdown/SidebarDropdown.tsx @@ -0,0 +1,141 @@ +/** @jsxImportSource react */ +import { useState, useRef, useEffect } from "react" +import styles from "./SidebarDropdown.module.css" + +export interface DropdownItem { + id: string + label: string + icon: string + description?: string +} + +interface SidebarDropdownProps { + label: string + items: DropdownItem[] + selectedId: string + onSelect: (id: string) => void + triggerId: string + ariaLabel: string +} + +/** + * Generic Sidebar Dropdown Component + * + * A reusable dropdown component for sidebar navigation. + * Handles all UI rendering and interaction logic. + * + * Features: + * - Sticky positioning at top of sidebar + * - Click-outside to close + * - Keyboard accessible (ARIA compliant, Escape key) + * - Mobile responsive + */ +export function SidebarDropdown({ label, items, selectedId, onSelect, triggerId, ariaLabel }: SidebarDropdownProps) { + const [isOpen, setIsOpen] = useState(false) + const dropdownRef = useRef<HTMLDivElement>(null) + + const selectedItem = items.find((item) => item.id === selectedId) + + const handleSelect = (id: string) => { + setIsOpen(false) + onSelect(id) + } + + const handleToggle = () => { + setIsOpen(!isOpen) + } + + // Close dropdown when clicking outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsOpen(false) + } + } + + const handleEscape = (event: KeyboardEvent) => { + if (event.key === "Escape") { + setIsOpen(false) + } + } + + if (isOpen) { + document.addEventListener("mousedown", handleClickOutside) + document.addEventListener("keydown", handleEscape) + } + + return () => { + document.removeEventListener("mousedown", handleClickOutside) + document.removeEventListener("keydown", handleEscape) + } + }, [isOpen]) + + if (!selectedItem) { + return null + } + + return ( + <div className={styles.selector} ref={dropdownRef}> + <div className={styles.dropdown}> + <label className={styles.label} htmlFor={triggerId}> + {label} + </label> + <button + id={triggerId} + type="button" + className={styles.trigger} + onClick={handleToggle} + aria-expanded={isOpen} + aria-haspopup="true" + aria-label={ariaLabel} + > + <img src={selectedItem.icon} alt={selectedItem.label} className={styles.triggerIcon} /> + <span className={styles.triggerText}>{selectedItem.label}</span> + <svg className={styles.arrow} width="12" height="12" viewBox="0 0 12 12" fill="none"> + <path + d="M2.5 4.5L6 8L9.5 4.5" + stroke="currentColor" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + </button> + + {isOpen && ( + <div className={styles.menu}> + <div className={styles.menuContent}> + {items.map((item) => { + const isActive = selectedId === item.id + + return ( + <button + key={item.id} + type="button" + className={`${styles.option} ${isActive ? styles.selected : ""}`} + onClick={() => handleSelect(item.id)} + title={item.description} + > + <img src={item.icon} alt={item.label} className={styles.optionIcon} /> + <span>{item.label}</span> + {isActive && ( + <svg className={styles.checkmark} width="16" height="16" viewBox="0 0 16 16" fill="none"> + <path + d="M13.5 4.5L6 12L2.5 8.5" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + )} + </button> + ) + })} + </div> + </div> + )} + </div> + </div> + ) +} diff --git a/src/components/SidebarDropdown/index.ts b/src/components/SidebarDropdown/index.ts new file mode 100644 index 00000000000..9e63bfe0e2d --- /dev/null +++ b/src/components/SidebarDropdown/index.ts @@ -0,0 +1,2 @@ +export { SidebarDropdown } from "./SidebarDropdown.js" +export type { DropdownItem } from "./SidebarDropdown.js" diff --git a/src/components/TabGrid/ChainAwareTabGrid.tsx b/src/components/TabGrid/ChainAwareTabGrid.tsx new file mode 100644 index 00000000000..74ce5b495db --- /dev/null +++ b/src/components/TabGrid/ChainAwareTabGrid.tsx @@ -0,0 +1,49 @@ +/** @jsxImportSource react */ +import { useStore } from "@nanostores/react" +import { selectedChainType } from "~/stores/chainType.js" +import styles from "./TabGrid.module.css" +import { GridItem } from "./GridCard.tsx" +import { ItemGrid } from "./ItemGrid.tsx" +import { Typography } from "@chainlink/blocks" + +export interface Tab { + name: string + links: GridItem[] +} + +interface ChainAwareTabGridProps { + tabs: Tab[] + header: string + columns?: 1 | 2 | 3 | 4 +} + +export const ChainAwareTabGrid = ({ tabs, header, columns = 3 }: ChainAwareTabGridProps) => { + const activeChainType = useStore(selectedChainType) + + const activeTab = tabs.find((tab) => tab.name.toLowerCase() === activeChainType.toLowerCase()) + + const displayTab = activeTab || tabs[0] + + if (!displayTab) { + return null + } + + return ( + <div className={styles.tabGridWrapper}> + <header className={styles.gridHeader}> + <Typography + variant="h2" + style={{ + fontSize: "32px", + }} + > + {header} + </Typography> + </header> + + <div className={styles.gridContent}> + <ItemGrid links={displayTab.links} columns={columns} /> + </div> + </div> + ) +} diff --git a/src/components/TabGrid/GridCard.module.css b/src/components/TabGrid/GridCard.module.css new file mode 100644 index 00000000000..655ffb7cd16 --- /dev/null +++ b/src/components/TabGrid/GridCard.module.css @@ -0,0 +1,80 @@ +.card { + display: flex; + background: var(--color-background); + padding: var(--space-6x); + align-items: start; + gap: var(--space-6x); + border-right: 1px solid var(--border); + border-bottom: 1px solid var(--border); + flex-direction: column; + &:hover .cardFooter { + opacity: 1; + } +} + +[data-columns="1"] > .card:nth-child(1) { + border-top: 1px solid var(--border); +} + +[data-columns="2"] > .card:nth-child(-n + 2) { + border-top: 1px solid var(--border); +} + +[data-columns="3"] > .card:nth-child(-n + 3) { + border-top: 1px solid var(--border); +} + +[data-columns="4"] > .card:nth-child(-n + 4) { + border-top: 1px solid var(--border); +} + +/* Tablet: adjust border-top for 2-column layouts */ +@media (max-width: 1024px) { + [data-columns="3"] > .card:nth-child(-n + 3), + [data-columns="4"] > .card:nth-child(-n + 4) { + border-top: none; + } + + [data-columns="3"] > .card:nth-child(-n + 2), + [data-columns="4"] > .card:nth-child(-n + 2) { + border-top: 1px solid var(--border); + } +} + +/* Mobile: single column - only first card has border-top */ +@media (max-width: 768px) { + [data-columns] > .card:nth-child(n) { + border-top: none; + } + + [data-columns] > .card:nth-child(1) { + border-top: 1px solid var(--border); + } +} + +.card:hover { + background-color: var(--muted); +} + +.cardFooter { + opacity: 0; + margin-top: auto; + /* enforcing a width */ + min-width: 16px; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; +} + +.cardFooter img { + width: 10px; + height: 10px; +} + +.cardTitle { + font-size: 16px; + font-weight: 525; + color: var(--foreground); + margin-bottom: var(--space-2x); +} diff --git a/src/components/TabGrid/GridCard.tsx b/src/components/TabGrid/GridCard.tsx new file mode 100644 index 00000000000..e6d4281a267 --- /dev/null +++ b/src/components/TabGrid/GridCard.tsx @@ -0,0 +1,27 @@ +import { Typography } from "@chainlink/blocks" +import styles from "./GridCard.module.css" + +export interface GridItem { + title: string + description: string + link: string + badge?: string +} + +export const GridCard = ({ title, description, link, badge }: GridItem) => { + return ( + <a href={link} className={styles.card}> + <div> + <p className={styles.cardTitle}>{title}</p> + <Typography variant="body-s" style={{ lineHeight: "24px" }}> + {description} + </Typography> + </div> + + <div className={styles.cardFooter}> + {badge && <span className={styles.badge}>{badge}</span>} + <img src="/assets/icons/upper-right-arrow.svg" alt="arrow" /> + </div> + </a> + ) +} diff --git a/src/components/TabGrid/ItemGrid.tsx b/src/components/TabGrid/ItemGrid.tsx new file mode 100644 index 00000000000..0a2ed5e92d3 --- /dev/null +++ b/src/components/TabGrid/ItemGrid.tsx @@ -0,0 +1,17 @@ +import { GridCard, GridItem } from "./GridCard.tsx" +import styles from "./TabGrid.module.css" + +interface ItemGridProps { + links: GridItem[] + columns?: 1 | 2 | 3 | 4 +} + +export const ItemGrid = ({ links, columns = 3 }: ItemGridProps) => { + return ( + <div className={styles.grid} style={{ gridTemplateColumns: `repeat(${columns}, 1fr)` }} data-columns={columns}> + {links.map((link, index) => ( + <GridCard key={`${link.title}-${index}`} {...link} /> + ))} + </div> + ) +} diff --git a/src/components/TabGrid/README.md b/src/components/TabGrid/README.md new file mode 100644 index 00000000000..d7449326810 --- /dev/null +++ b/src/components/TabGrid/README.md @@ -0,0 +1,182 @@ +# TabGrid Components + +Two components for displaying grid items organized by category: one with built-in tabs and one that syncs with the global chain type selector. + +## Components + +### TabGrid + +A tabbed interface for displaying grid items organized by category with its own tab selector. + +#### What is this? + +The TabGrid component displays a collection of items in a clean, organized layout with tabs. Each tab represents a category of items (like "EVM" or "Solana"), and clicking on a tab shows the relevant items as clickable cards. + +This component is useful when you have multiple items and want to group them by topic or category, making it easier for users to find what they need. + +#### Usage + +```tsx +import { TabGrid } from "@components/TabGrid/TabGrid" +;<TabGrid + header="Tutorials" + tabs={[ + { + name: "Getting Started", + links: [ + { + title: "Quick Start Guide", + description: "Learn the basics in 5 minutes", + link: "/docs/quickstart", + }, + { + title: "Installation", + description: "Set up your development environment", + link: "/docs/installation", + }, + ], + }, + { + name: "Advanced", + links: [ + { + title: "Architecture Overview", + description: "Understand the system design", + link: "/docs/architecture", + }, + ], + }, + ]} +/> +``` + +--- + +### ChainAwareTabGrid + +A grid component that automatically filters content based on the selected chain type from the ChainTypeSelector dropdown. + +#### What is this? + +The ChainAwareTabGrid component displays a collection of items filtered by the currently selected blockchain type (EVM, Solana, Aptos, etc.). Unlike the regular TabGrid which has its own tab selector, this component syncs with the global chain type selector in the DocsLayout sidebar/header. + +This component is ideal for product landing pages (like CCIP) where content should automatically update based on the chain type selected in the main navigation. + +#### Usage + +```tsx +import { ChainAwareTabGrid } from "@components/TabGrid/ChainAwareTabGrid" + +// Define tutorials for each chain type +const tutorials = [ + { + name: "EVM", + links: [ + { + title: "Transfer Tokens", + description: "Unlock seamless token transfers from contracts", + link: "/ccip/tutorials/evm/transfer-tokens-from-contract", + }, + { + title: "Transfer Tokens with Data", + description: "Go beyond basic transfers with logic-infused token movements", + link: "/ccip/tutorials/evm/programmable-token-transfers", + }, + ], + }, + { + name: "Solana", + links: [ + { + title: "Getting Started with Solana", + description: "Learn the basics of building on Solana blockchain", + link: "/ccip/tutorials/svm", + }, + { + title: "Solana Token Transfers", + description: "Transfer tokens on the Solana blockchain", + link: "/ccip/tutorials/svm/source/token-transfers", + }, + ], + }, + { + name: "Aptos", + links: [ + { + title: "Getting Started with Aptos", + description: "Start building on the Aptos blockchain", + link: "/ccip/tutorials/aptos", + }, + ], + }, +] + +;<ChainAwareTabGrid header="Tutorials" client:visible tabs={tutorials} /> +``` + +#### How it works + +1. The component subscribes to the global `selectedChainType` store +2. When the user changes the chain type using the ChainTypeSelector dropdown, the component automatically updates +3. It finds the tab matching the selected chain type (case-insensitive) +4. Displays only the content for that chain type +5. Falls back to the first tab if no match is found + +#### When to use + +- **Use ChainAwareTabGrid** when content should sync with the global chain type selector (e.g., product landing pages) +- **Use TabGrid** when you need independent tab navigation that doesn't relate to blockchain types + +## How to set it up + +Both components require a `tabs` prop, which is an array of tab objects. Each tab object contains: + +- A **name** (the label shown on the tab button for TabGrid, or the chain type identifier for ChainAwareTabGrid) +- A list of **links** (the items shown when that tab is active) + +Each grid item needs three pieces of information: + +- **title** - The name of the item +- **description** - A short sentence explaining what the item covers +- **link** - The URL where the item can be found + +## Props Reference + +### `TabGrid` + +| Prop | Type | Required | Description | +| --------- | -------- | -------- | ------------------------------------------------- | +| `header` | `string` | Yes | The heading text displayed above the tabs | +| `tabs` | `Tab[]` | Yes | List of tabs, each containing a category of items | +| `columns` | `number` | No | Number of columns in the grid (defaults to 3) | + +### `ChainAwareTabGrid` + +| Prop | Type | Required | Description | +| --------- | -------- | -------- | ------------------------------------------------------------------------------ | +| `header` | `string` | Yes | The heading text displayed above the grid | +| `tabs` | `Tab[]` | Yes | List of tabs, each with a `name` matching a chain type (e.g., "EVM", "Solana") | +| `columns` | `number` | No | Number of columns in the grid (defaults to 3) | + +### `Tab` + +| Property | Type | Required | Description | +| -------- | ------------ | -------- | -------------------------------------------------------------------------------------------- | +| `name` | `string` | Yes | For TabGrid: any label. For ChainAwareTabGrid: must match chain type (e.g., "EVM", "Solana") | +| `links` | `GridItem[]` | Yes | The list of items to show when this tab is selected | + +### `GridItem` + +| Property | Type | Required | Description | +| ------------- | -------- | -------- | ------------------------------------------------- | +| `title` | `string` | Yes | The item's heading | +| `description` | `string` | Yes | A brief explanation of what users will learn | +| `link` | `string` | Yes | The URL path to the item page | +| `badge` | `string` | No | Optional badge label (e.g., "CCIP", "DATA FEEDS") | + +## Components + +- **TabGrid** - Main container with tabs and header (includes tab selector) +- **ChainAwareTabGrid** - Main container that syncs with global chain type selector (no built-in tabs) +- **ItemGrid** - Grid layout for item cards +- **GridCard** - Individual item card with hover effects diff --git a/src/components/TabGrid/TabGrid.module.css b/src/components/TabGrid/TabGrid.module.css new file mode 100644 index 00000000000..86fcc0aaa87 --- /dev/null +++ b/src/components/TabGrid/TabGrid.module.css @@ -0,0 +1,84 @@ +.grid { + display: grid; + border-left: 1px solid var(--border); + margin-top: 36px 0; +} + +.gridHeader { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--space-8x); +} + +.tabsTrigger { + height: 32px; + padding: var(--space-1x) var(--space-2x); + justify-content: center; + align-items: center; + border-radius: var(--space-2x); + background-color: var(--pill); + border: 1px solid var(--pill-border); +} + +.tabsTrigger:hover { + background-color: var(--pill-hover); +} + +.tabsTrigger[data-state="active"] { + background-color: var(--pill-active); + border-color: var(--pill-active); + border-bottom: 1px solid var(--pill-active); + + & h3 { + color: var(--pill-active-foreground); + } +} + +.tabTitle { + color: var(--pill-foreground); + font-weight: 400; +} + +.tabsList { + display: flex; + gap: var(--space-2x); + border-bottom: 0; +} + +/* Tablet: reduce columns to 2 for 3+ column layouts */ +@media (max-width: 1024px) { + [data-columns="3"], + [data-columns="4"] { + grid-template-columns: repeat(2, 1fr) !important; + } +} + +/* Mobile: single column for all layouts */ +@media (max-width: 768px) { + .grid { + grid-template-columns: 1fr !important; + } + + .gridHeader > h2 { + font-size: 28px; + } +} + +@media screen and (max-width: 425px) { + .gridSection { + margin-top: 0; + } + + .gridHeader { + margin-bottom: var(--space-6x); + } +} + +@media screen and (max-width: 390px) { + .gridHeader { + flex-direction: column; + align-items: start; + gap: var(--space-2x); + } +} diff --git a/src/components/TabGrid/TabGrid.tsx b/src/components/TabGrid/TabGrid.tsx new file mode 100644 index 00000000000..5b73bcdd43b --- /dev/null +++ b/src/components/TabGrid/TabGrid.tsx @@ -0,0 +1,47 @@ +import styles from "./TabGrid.module.css" +import { GridItem } from "./GridCard.tsx" +import { ItemGrid } from "./ItemGrid.tsx" +import { Tabs, TabsContent, TabsList, TabsTrigger, Typography } from "@chainlink/blocks" + +export interface Tab { + name: string + links: GridItem[] +} + +interface TabGridProps { + tabs: Tab[] + header: string + columns?: 1 | 2 | 3 | 4 +} + +export const TabGrid = ({ tabs, header, columns = 3 }: TabGridProps) => { + return ( + <Tabs defaultValue={tabs[0].name} className={styles.tabGridWrapper}> + <header className={styles.gridHeader}> + <Typography + variant="h2" + style={{ + fontSize: "32px", + }} + > + {header} + </Typography> + <TabsList className={styles.tabsList}> + {tabs.map((tab) => ( + <TabsTrigger key={tab.name} value={tab.name} className={styles.tabsTrigger}> + <h3 className={styles.tabTitle}>{tab.name}</h3> + </TabsTrigger> + ))} + </TabsList> + </header> + + {tabs.map((tab) => ( + <TabsContent key={tab.name} value={tab.name}> + <div className={styles.gridContent}> + <ItemGrid links={tab.links} columns={columns} /> + </div> + </TabsContent> + ))} + </Tabs> + ) +} diff --git a/src/components/TechnicalStandards/TechnicalStandards.astro b/src/components/TechnicalStandards/TechnicalStandards.astro new file mode 100644 index 00000000000..11e4e1d85b4 --- /dev/null +++ b/src/components/TechnicalStandards/TechnicalStandards.astro @@ -0,0 +1,132 @@ +--- +import { Typography } from "@chainlink/blocks" + +const cards = [ + { + title: "Digital Transfer Agent (DTA)", + description: "You might be interested in this end-to-end solution. It can solve your problems.", + image: "/images/ccip/ccip-hero-bg.png", + href: "/", + }, + { + title: "Delivery vs. Payment (DvP)", + description: "You might be interested in this end-to-end solution. It can solve your problems.", + image: "/images/code-sample.png", + href: "/", + }, +] +--- + +<div class="technical-standards"> + <Typography variant="h2">Technical Standards</Typography> + + <div class="list"> + { + cards.map((card) => ( + <a href={card.href} class="standard-card"> + <div class="card-image" style={`background-image: url(${card.image})`} /> + <div class="card-body"> + <div class="card-text"> + <Typography variant="h5">{card.title}</Typography> + <Typography variant="body-l" color="muted"> + {card.description} + </Typography> + </div> + </div> + <img src="/assets/icons/upper-right-arrow.svg" class="card-arrow" /> + </a> + )) + } + </div> +</div> + +<style> + .technical-standards > h2 { + margin-bottom: var(--space-6x); + font-size: 28px; + } + .list { + display: grid; + grid-template-columns: 1fr; + border: 1px solid var(--border); + } + + .standard-card { + display: flex; + flex-direction: column; + padding: var(--space-6x); + gap: var(--space-6x); + align-items: start; + } + + .standard-card:hover { + background-color: var(--muted); + } + + .standard-card:hover .card-arrow { + opacity: 1; + } + + .card-image { + width: 70px; + height: 70px; + background-repeat: no-repeat; + } + .standard-card:first-child { + border-bottom: 1px solid var(--border); + } + + .standard-card:first-child .card-image { + } + + .card-body, + .card-text { + display: flex; + flex-direction: column; + gap: var(--space-4x); + flex: 1; + } + + .card-arrow { + height: 12px; + width: 12px; + opacity: 0; + align-self: flex-end; + display: none; + } + + @media screen and (min-width: 543px) { + .standard-card { + flex-direction: row; + } + + .card-image { + width: 140px; + height: 140px; + } + + .card-arrow { + display: block; + } + } + + @media (min-width: 50em) { + .list { + grid-template-columns: repeat(2, 1fr); + } + .standard-card { + flex-direction: row; + } + + .standard-card:first-child { + border-right: 1px solid var(--border); + border-bottom: 0; + } + + .card-body, + .card-text { + flex: 1; + justify-content: space-between; + } + } +</style> diff --git a/src/components/ToolsUtilitiesGrid/README.md b/src/components/ToolsUtilitiesGrid/README.md new file mode 100644 index 00000000000..550b5ae7de0 --- /dev/null +++ b/src/components/ToolsUtilitiesGrid/README.md @@ -0,0 +1,82 @@ +# ToolsUtilitiesGrid + +## What it does + +This component displays a grid of clickable cards that showcase tools and utilities. Each card includes an icon, title, description, and link. It's perfect for creating a visual directory of resources, tools, or utilities that users can browse and click through to. + +## How to use it + +1. Import the component in your Astro layout or page: + +```astro +import ToolsUtilitiesGrid from "~/components/ToolsUtilitiesGrid/ToolsUtilitiesGrid.astro" +``` + +2. Create an array of links with the information for each tool/utility you want to display + +3. Add the component to your page and pass in the links: + +```astro +<ToolsUtilitiesGrid links={yourLinksArray} /> +``` + +## Example + +Here's a complete example showing how to use the component: + +```astro +--- +import ToolsUtilitiesGrid from "~/components/ToolsUtilitiesGrid/ToolsUtilitiesGrid.astro" + +const toolsAndUtilities = [ + { + image: "/images/ccip-logo.svg", + imageAlt: "CCIP API icon", + label: "CCIP API", + link: "/ccip/api", + description: "An API for message retrieval and lane latency information.", + }, + { + image: "/images/js-logo.svg", + imageAlt: "JavaScript SDK icon", + label: "Javascript SDK", + link: "https://github.com/smartcontractkit/ccip-javascript-sdk", + description: "Integrate CCIP functionality directly into your web applications for EVM-compatible chains.", + }, + { + image: "/images/hardhat-logo.svg", + imageAlt: "Hardhat icon", + label: "Hardhat Starter Kit", + link: "https://github.com/smartcontractkit/hardhat-starter-kit", + description: + "Ready-to-go boilerplate for basic CCIP use cases that help you get started building quickly with Hardhat.", + }, +] +--- + +<ToolsUtilitiesGrid links={toolsAndUtilities} /> +``` + +## What you need to provide + +Each item in your `links` array needs these fields: + +| Field | What it is | Example | +| --------------- | ----------------------------------------------------------- | -------------------------------------------------------------- | +| **image** | The full path to the icon/logo image | `"/images/ccip-logo.svg"` | +| **imageAlt** | Description of the image for accessibility | `"CCIP API icon"` | +| **label** | The title/name of the tool or utility | `"CCIP API"` | +| **link** | Where the card should link to (can be internal or external) | `"/ccip/api"` or `"https://github.com/..."` | +| **description** | A short description explaining what the tool does | `"An API for message retrieval and lane latency information."` | + +## Where to put images + +Place your icon/logo images in the `/public/images/` directory, and reference them with the full path starting with `/images/`. + +For example, if you use `image: "/images/my-tool-logo.svg"`, the actual file should be at: + +``` +/public/images/my-tool-logo.svg +``` + +You can also use images from other locations by providing the full path (e.g., `"/assets/logos/my-logo.png"`). diff --git a/src/components/ToolsUtilitiesGrid/ToolItem.astro b/src/components/ToolsUtilitiesGrid/ToolItem.astro new file mode 100644 index 00000000000..eb5b7f590c7 --- /dev/null +++ b/src/components/ToolsUtilitiesGrid/ToolItem.astro @@ -0,0 +1,28 @@ +--- +import { Typography } from "@chainlink/blocks" +import styles from "./toolsUtilities.module.css" +import { Link } from "./types" + +type Props = Link + +const { description, image, imageAlt, label, link } = Astro.props +--- + +<a href={link} class={styles.card}> + <div class={styles.imageContainer}><img src={image} alt={imageAlt} class={styles.image} /></div> + + <div class={styles.content}> + <div> + <Typography + variant="body-semi" + style={{ + fontWeight: 500, + fontSize: "18px", + }}>{label}</Typography + > + <Typography variant="body-s" color="muted">{description}</Typography> + </div> + + <img src="/assets/icons/upper-right-arrow.svg" class={styles.arrow} /> + </div> +</a> diff --git a/src/components/ToolsUtilitiesGrid/ToolsUtilitiesGrid.astro b/src/components/ToolsUtilitiesGrid/ToolsUtilitiesGrid.astro new file mode 100644 index 00000000000..fa875b286c8 --- /dev/null +++ b/src/components/ToolsUtilitiesGrid/ToolsUtilitiesGrid.astro @@ -0,0 +1,26 @@ +--- +import styles from "./toolsUtilities.module.css" + +import { Link } from "./types" +import ToolItem from "./ToolItem.astro" +import { Typography } from "@chainlink/blocks" + +interface Props { + links: Link[] +} + +const { links } = Astro.props +--- + +<section class={styles.wrapper}> + <Typography + variant="h2" + style={{ + fontSize: "32px", + }}>Tools & Utilities</Typography + > + + <div class={styles.container}> + {links.map((link) => <ToolItem {...link} />)} + </div> +</section> diff --git a/src/components/ToolsUtilitiesGrid/toolsUtilities.module.css b/src/components/ToolsUtilitiesGrid/toolsUtilities.module.css new file mode 100644 index 00000000000..c1e36191486 --- /dev/null +++ b/src/components/ToolsUtilitiesGrid/toolsUtilities.module.css @@ -0,0 +1,60 @@ +.container { + display: grid; + grid-template-columns: repeat(3, 1fr); + margin-top: var(--space-8x); +} + +.card { + padding: var(--space-6x); + display: flex; + gap: var(--space-4x); + align-items: start; +} + +.card:hover { + background: var(--muted); + & .arrow { + opacity: 1; + } +} + +.imageContainer { + min-width: 48px; + height: 48px; + background: var(--background-alt); + border: 1px solid var(--border); + border-radius: var(--space-1x); + display: flex; + align-items: center; + justify-content: center; +} + +.content { + display: flex; + + & > img { + align-self: end; + } +} + +.arrow { + opacity: 0; +} + +@media screen and (max-width: 1135px) { + .container { + grid-template-columns: repeat(2, 1fr); + } +} + +@media screen and (max-width: 525px) { + .container { + grid-template-columns: repeat(1, 1fr); + } +} + +@media screen and (max-width: 425px) { + .container { + margin-top: var(--space-6x); + } +} diff --git a/src/components/ToolsUtilitiesGrid/types.ts b/src/components/ToolsUtilitiesGrid/types.ts new file mode 100644 index 00000000000..2c645744a9f --- /dev/null +++ b/src/components/ToolsUtilitiesGrid/types.ts @@ -0,0 +1,7 @@ +export interface Link { + image: string + imageAlt: string + label: string + link: string + description: string +} diff --git a/src/components/TryItOut/README.md b/src/components/TryItOut/README.md new file mode 100644 index 00000000000..50a8e94c97a --- /dev/null +++ b/src/components/TryItOut/README.md @@ -0,0 +1,92 @@ +# TryItOut Component + +A component that displays an interactive accordion of features alongside a dynamically changing code sample preview. The code sample updates based on which accordion item is currently expanded. + +## Usage + +```astro +<TryItOut + accordionTabs={[ + { + title: "Your Feature Title", + text: "A brief description of what this feature does.", + codeSampleSrc: "/samples/YourCodeFile.sol", + }, + ]} + ctas={[ + { text: "Get Started", href: "/getting-started", variant: "primary" }, + { text: "Learn More", href: "/docs", variant: "secondary" }, + ]} +/> +``` + +## Props + +### `accordionTabs` (required) + +A list of expandable sections that describe different features. Each tab needs: + +- **title**: The heading text for the accordion item +- **text**: The description that appears when the accordion is expanded +- **codeSampleSrc**: The file path to the code sample for this specific tab (should point to a file in the `/samples/` folder) + +**Example:** + +```js +;[ + { + title: "Transfer Tokens", + text: "Move tokens between different blockchains easily.", + codeSampleSrc: "/samples/CCIP/TokenTransfer.sol", + }, + { + title: "Fetch Data", + text: "Get real-time information from external sources.", + codeSampleSrc: "/samples/DataFeeds/PriceFeed.sol", + }, +] +``` + +### `ctas` (optional) + +An array of call-to-action buttons to display in the footer. If not provided, defaults to "Create CRE account" and "Get the SDK" buttons. + +Each CTA object needs: + +- **text**: The button text +- **href**: The button link URL +- **variant** (optional): Either "primary" or "secondary" (defaults to "primary") + +**Example:** + +```js +;[ + { text: "Get Started", href: "/getting-started", variant: "primary" }, + { text: "View Docs", href: "/documentation", variant: "secondary" }, +] +``` + +## How It Works + +The component uses [Astro's nano stores](https://docs.astro.build/en/core-concepts/sharing-state/) to track which accordion item is currently expanded. When you click on a different accordion item, the code sample automatically updates to show the code associated with that item. + +### Technical Implementation + +**Why we pre-render all code samples:** + +All code samples are rendered at build time using the `<CodeSample>` Astro component and included in the HTML. While this means all code samples are present in the DOM, they are toggled via visibility rather than dynamically loaded. This approach is necessary because: + +1. **Astro components are build-time only** - The `<CodeSample>` component uses Astro's Prism integration which only runs during the build process, not at runtime +2. **Proper syntax highlighting** - Pre-rendering ensures all code has proper syntax highlighting applied via Prism +3. **Performance** - No runtime file reading or syntax highlighting processing; instant switching between code samples +4. **Simplicity** - Avoids complex API endpoints or client-side file fetching + +**Accessibility considerations:** + +Inactive code samples are hidden from both visual users and assistive technology: + +- `display: none` hides them visually +- `aria-hidden="true"` ensures screen readers ignore hidden code blocks +- Only the active code sample has `aria-hidden="false"`, making it visible to screen readers + +When the active accordion changes, the visibility and `aria-hidden` attributes are updated via JavaScript to show the new code sample and hide all others. diff --git a/src/components/TryItOut/TryItOut.astro b/src/components/TryItOut/TryItOut.astro new file mode 100644 index 00000000000..1100ae2d050 --- /dev/null +++ b/src/components/TryItOut/TryItOut.astro @@ -0,0 +1,147 @@ +--- +import { buttonVariants, Typography } from "@chainlink/blocks" +import styles from "./styles.module.css" +import CodeSample from "../CodeSample/CodeSample.astro" +import { TryItOutAccordion } from "./TryItOutAccordion" +import { clsx } from "~/lib/clsx/clsx" + +interface CTA { + text: string + href: string + variant?: "primary" | "secondary" +} + +interface Tab { + title: string + text: string + codeSampleSrc: string + ctas?: CTA[] +} + +interface Props { + accordionTabs: Tab[] +} + +const { accordionTabs } = Astro.props +--- + +<div class={styles.container}> + <section class={styles.body}> + <Typography variant="h2" className={styles.title}> Try it out </Typography> + + <section class={styles.content}> + <div class={styles.contentLeft}> + <TryItOutAccordion client:load tabs={accordionTabs} /> + + {/* Desktop CTAs (dynamic per active tab) */} + <footer class={styles.contentFooter}> + { + accordionTabs.map((tab, index) => ( + <div + class="cta-item" + data-cta-index={index} + style={index === 0 ? "" : "display: none;"} + aria-hidden={index === 0 ? "false" : "true"} + > + {(tab.ctas ?? []).map((cta) => ( + <a + href={cta.href} + class={clsx( + buttonVariants({ + variant: cta.variant === "secondary" ? "tertiary" : "primary", + size: "default", + }), + cta.variant === "secondary" && styles.secondaryBtn + )} + > + {cta.text} + </a> + ))} + </div> + )) + } + </footer> + </div> + + <section class={styles.image}> + { + accordionTabs.map((tab, index) => ( + <div + class="code-sample-item" + data-code-index={index} + style={index === 0 ? "" : "display: none;"} + aria-hidden={index === 0 ? "false" : "true"} + > + <CodeSample showButtons={false} src={tab.codeSampleSrc} /> + </div> + )) + } + </section> + + {/* Mobile CTAs (dynamic per active tab) */} + <footer class={styles.contentFooterMobile}> + { + accordionTabs.map((tab, index) => ( + <div + class="cta-item-mobile" + data-cta-index={index} + style={index === 0 ? "" : "display: none;"} + aria-hidden={index === 0 ? "false" : "true"} + > + {(tab.ctas ?? []).map((cta) => ( + <a + href={cta.href} + class={clsx( + buttonVariants({ + variant: cta.variant === "secondary" ? "tertiary" : "primary", + size: "default", + }), + cta.variant === "secondary" && styles.secondaryBtn + )} + > + {cta.text} + </a> + ))} + </div> + )) + } + </footer> + </section> + </section> +</div> + +<script> + import { activeAccordionIndex } from "~/stores/tryItOutStore.ts" + + // Subscribe to nano store changes + activeAccordionIndex.subscribe((newIndex) => { + // Hide all code samples and mark as hidden for screen readers + const allCodeSamples = document.querySelectorAll(".code-sample-item") + allCodeSamples.forEach((el) => { + ;(el as HTMLElement).style.display = "none" + ;(el as HTMLElement).setAttribute("aria-hidden", "true") + }) + + // Show the active one and mark as visible for screen readers + const activeCodeSample = document.querySelector(`[data-code-index="${newIndex}"]`) + if (activeCodeSample) { + ;(activeCodeSample as HTMLElement).style.display = "block" + ;(activeCodeSample as HTMLElement).setAttribute("aria-hidden", "false") + } + + // Hide all CTA groups + const allCtas = document.querySelectorAll("[data-cta-index]") + allCtas.forEach((el) => { + ;(el as HTMLElement).style.display = "none" + ;(el as HTMLElement).setAttribute("aria-hidden", "true") + }) + + // Show the active CTA group(s) + // IMPORTANT: remove inline display so CSS (flex) can apply + const activeCtas = document.querySelectorAll(`[data-cta-index="${newIndex}"]`) + activeCtas.forEach((el) => { + ;(el as HTMLElement).style.removeProperty("display") // ✅ key fix + ;(el as HTMLElement).setAttribute("aria-hidden", "false") + }) + }) +</script> diff --git a/src/components/TryItOut/TryItOutAccordion.tsx b/src/components/TryItOut/TryItOutAccordion.tsx new file mode 100644 index 00000000000..7328daa63ab --- /dev/null +++ b/src/components/TryItOut/TryItOutAccordion.tsx @@ -0,0 +1,37 @@ +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Typography } from "@chainlink/blocks" +import { activeAccordionIndex } from "~/stores/tryItOutStore.ts" +import styles from "./styles.module.css" + +interface AccordionTab { + title: string + text: string + codeSampleSrc: string +} + +interface TryItOutAccordionProps { + tabs: AccordionTab[] +} + +export const TryItOutAccordion = ({ tabs }: TryItOutAccordionProps) => { + const handleValueChange = (value: string) => { + if (value) { + activeAccordionIndex.set(parseInt(value, 10)) + } + } + + return ( + <Accordion collapsible type="single" defaultValue="0" onValueChange={handleValueChange}> + {tabs.map((tab, idx) => ( + <AccordionItem key={idx} value={String(idx)} className={styles.accordionItem}> + <AccordionTrigger className={styles.accordionTrigger}> + {tab.title}{" "} + <Typography variant="code" className={styles.indicator}> + 0{idx + 1} + </Typography> + </AccordionTrigger> + <AccordionContent className={styles.text}>{tab.text}</AccordionContent> + </AccordionItem> + ))} + </Accordion> + ) +} diff --git a/src/components/TryItOut/styles.module.css b/src/components/TryItOut/styles.module.css new file mode 100644 index 00000000000..e02874ae434 --- /dev/null +++ b/src/components/TryItOut/styles.module.css @@ -0,0 +1,153 @@ +.container { + background-color: var(--tertiary-foreground); + padding: var(--space-10x) var(--space-16x); + margin: 86px 0; +} + +.title { + margin-bottom: var(--space-8x); + color: var(--background); +} + +.secondaryBtn { + color: var(--white) !important; +} + +.contentFooter { + display: flex; + gap: var(--space-6x); + margin-top: 55px; +} + +/* NEW: CTA group wrapper should behave like the old footer (buttons as direct children) */ +.contentFooter :global(.cta-item), +.contentFooterMobile :global(.cta-item-mobile) { + display: flex; + gap: var(--space-6x); /* match footer spacing */ + align-items: center; +} + +/* Optional: ensure hidden groups don't occupy space (extra-safe) */ +.contentFooter :global(.cta-item[aria-hidden="true"]), +.contentFooterMobile :global(.cta-item-mobile[aria-hidden="true"]) { + display: none; +} + +/* prevent CTA row reflow across tabs */ +.contentFooter, +.contentFooterMobile { + min-height: 56px; /* keeps vertical stability too */ +} + +/* apply to actual anchor buttons inside the active CTA group */ +.contentFooter :global(.cta-item) a, +.contentFooterMobile :global(.cta-item-mobile) a { + width: 280px; /* tune */ + justify-content: center; /* centers text inside button */ + text-align: center; + white-space: nowrap; /* avoid wrapping */ +} + +.content { + display: grid; + grid-template-columns: 1fr 1fr; + justify-content: space-between; + gap: var(--space-24x); +} + +.accordionItem { + border-bottom: none; + border-top: 1px solid var(--segment-button-foreground); + display: flex; + flex-direction: column; + + * { + transition: all 0.2s linear; + } +} + +.contentLeft { + display: flex; + flex-direction: column; + justify-content: center; +} + +.text { + color: var(--gray-400); +} + +.indicator { + color: var(--gray-400); +} + +.accordionTrigger { + color: var(--gray-400); + padding: var(--space-4x) 0; + border: none; + outline: none; + & p { + color: var(--gray-400); + } + + & svg { + display: none; + } + + & span { + word-wrap: normal; + } +} + +.image { + width: 100%; + max-height: 412px; + overflow-y: auto; + border-bottom: 1.5px solid var(--stepper-counter-pending-foreground); + border-radius: 6.317px; +} + +.accordionItem[data-state="open"] { + border-top: 2px solid var(--link); + + & .accordionTrigger { + color: var(--white); + } + & .indicator { + color: var(--link); + } +} + +.body { + max-width: var(--fullwidth-max-width); + width: 100%; + margin: 0 auto; +} + +.contentFooterMobile { + display: none; + gap: var(--space-6x); +} + +@media screen and (max-width: 425px) { + .contentFooterMobile { + flex-direction: column; + } +} + +@media screen and (max-width: 768px) { + .content { + grid-template-columns: 1fr; + gap: var(--space-8x); + } + + .title { + font-size: 28px; + } + .contentFooter { + display: none; + } + + .contentFooterMobile { + display: flex; + } +} diff --git a/src/components/index.ts b/src/components/index.ts index b91fe04a3f6..64617eaf7b6 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -10,6 +10,7 @@ export { default as CodeSample } from "./CodeSample/CodeSample.astro" export { default as Address } from "./Address" export { default as CopyText } from "./CopyText" +export { CopyPageLink } from "./RightSidebar/CopyPageLink" export { default as Aside } from "./Aside.astro" export { default as ReleaseNotes } from "./ReleaseNotes.astro" export { default as Icon } from "./Icon.astro" diff --git a/src/config/cdn.ts b/src/config/cdn.ts new file mode 100644 index 00000000000..28de60e15b9 --- /dev/null +++ b/src/config/cdn.ts @@ -0,0 +1,15 @@ +/** + * CDN Base URLs and asset path configuration + * Centralized configuration for all CDN-hosted assets + */ + +// CloudFront CDN base URL +export const CLOUDFRONT_CDN_BASE = "https://d2f70xi62kby8n.cloudfront.net" + +// Asset-specific paths +export const TOKEN_ICONS_PATH = `${CLOUDFRONT_CDN_BASE}/tokens` +export const VERIFIER_ICON_PATH = `${CLOUDFRONT_CDN_BASE}/verifiers` +export const NETWORK_ICON_PATH = `${CLOUDFRONT_CDN_BASE}/bridge/icons/networks` + +// Other CDNs (for future centralization if needed) +export const IMGIX_CDN_BASE = "https://smartcontract.imgix.net" diff --git a/src/config/data/ccip/data.ts b/src/config/data/ccip/data.ts index 3eec6d88f9e..e86b3907ac9 100644 --- a/src/config/data/ccip/data.ts +++ b/src/config/data/ccip/data.ts @@ -13,9 +13,14 @@ import { Network, DecomConfig, DecommissionedNetwork, + VerifiersConfig, + Verifier, + VerifierType, + PoolType, } from "./types.ts" import { determineTokenMechanism } from "./utils.ts" import { ExplorerInfo, SupportedChain, ChainType } from "@config/types.ts" +import { NETWORK_ICON_PATH, VERIFIER_ICON_PATH } from "@config/cdn.ts" import { directoryToSupportedChain, getChainIcon, @@ -27,6 +32,7 @@ import { getTokenIconUrl, getNativeCurrency, } from "@features/utils/index.ts" +import { normalizeTechnologyName } from "@features/utils/networkIcons.ts" // For mainnet import chainsMainnetv120 from "@config/data/ccip/v1_2_0/mainnet/chains.json" with { type: "json" } @@ -42,6 +48,10 @@ import tokensTestnetv120 from "@config/data/ccip/v1_2_0/testnet/tokens.json" wit import decomMainnetv120 from "@config/data/ccip/v1_2_0/mainnet/decom.json" with { type: "json" } import decomTestnetv120 from "@config/data/ccip/v1_2_0/testnet/decom.json" with { type: "json" } +// For verifiers +import verifiersMainnetv120 from "@config/data/ccip/v1_2_0/mainnet/verifiers.json" with { type: "json" } +import verifiersTestnetv120 from "@config/data/ccip/v1_2_0/testnet/verifiers.json" with { type: "json" } + // Import errors by version // eslint-disable-next-line camelcase import * as errors_v1_5_0 from "./errors/v1_5_0/index.ts" @@ -171,7 +181,7 @@ export const events: VersionedEvents = { export const networkFees: NetworkFees = { tokenTransfers: { [TokenMechanism.LockAndUnlock]: { - allLanes: { gasTokenFee: "0.07 %", linkFee: "0.063 %" }, + allLanes: { gasTokenFee: "0.05 %", linkFee: "0.063 %" }, }, [TokenMechanism.LockAndMint]: { fromEthereum: { gasTokenFee: "0.50 USD", linkFee: "0.45 USD" }, @@ -264,13 +274,14 @@ export const getAllSupportedTokens = (params: { environment: Environment; versio Object.entries(laneReferenceData).forEach(([destinationChainRdd, destinationLaneReferenceData]) => { const supportedTokens = destinationLaneReferenceData.supportedTokens - if (supportedTokens) { - Object.entries(supportedTokens).forEach(([token, tokenConfig]) => { + if (supportedTokens && Array.isArray(supportedTokens)) { + supportedTokens.forEach((token) => { const destinationChain = directoryToSupportedChain(destinationChainRdd) tokens[token] = tokens[token] || {} tokens[token][sourceChain] = tokens[token][sourceChain] || {} - tokens[token][sourceChain][destinationChain] = tokenConfig + // Rate limiter config is now in separate files, store empty config + tokens[token][sourceChain][destinationChain] = {} }) } }) @@ -308,8 +319,9 @@ export const getTokenMechanism = (params: { const tokenConfig = tokensReferenceData[params.token] const sourceChainPoolInfo = tokenConfig[sourceChainRdd] const destinationChainPoolInfo = tokenConfig[destinationChainRdd] - const sourceChainPoolType = sourceChainPoolInfo.poolType - const destinationChainPoolType = destinationChainPoolInfo.poolType + const sourceChainPoolType = (sourceChainPoolInfo.pool?.type || sourceChainPoolInfo.poolType) as PoolType + const destinationChainPoolType = (destinationChainPoolInfo.pool?.type || + destinationChainPoolInfo.poolType) as PoolType const tokenMechanism = determineTokenMechanism(sourceChainPoolType, destinationChainPoolType) return tokenMechanism } @@ -466,7 +478,7 @@ export const getTokensOfChain = ({ chain, filter }: { chain: string; filter: Env return Object.keys(tokensData).filter((token) => { const tokenData = tokensData[token] // Check if tokenData for the given chain exists and isn't 'feeTokenOnly' - if (tokenData[chain] && tokenData[chain].poolType !== "feeTokenOnly") { + if (tokenData[chain] && tokenData[chain].pool && tokenData[chain].pool.type !== "feeTokenOnly") { const lanes = getAllTokenLanes({ token, environment: filter }) // Ensure there is at least one lane and that the lane exists for the given chain return Object.keys(lanes).length > 0 && lanes[chain] && Object.keys(lanes[chain]).length > 0 @@ -584,8 +596,14 @@ export const getChainsOfToken = ({ token, filter }: { token: string; filter: Env })() // Get all valid chains for the given token - return Object.entries(tokensData[token]) - .filter(([, tokenData]) => tokenData.poolType !== "feeTokenOnly") + const tokenData = tokensData[token] + if (!tokenData) { + console.warn(`No token data found for ${token} in ${filter} environment`) + return [] + } + + return Object.entries(tokenData) + .filter(([, tokenData]) => tokenData.pool && tokenData.pool.type !== "feeTokenOnly") .filter(([chain]) => { const lanes = getAllTokenLanes({ token, environment: filter }) return Object.keys(lanes).length > 0 && lanes[chain] && Object.keys(lanes[chain]).length > 0 @@ -609,6 +627,11 @@ export const getAllNetworkLanes = async ({ const allLanes = lanesReferenceData[chain] + // Handle chains with no outbound lanes (e.g., newly added chains) + if (!allLanes) { + return [] + } + const lanesData: { name: string logo: string @@ -669,11 +692,13 @@ export function getAllTokenLanes({ for (const destinationChain in sourceData) { const destinationData = sourceData[destinationChain] - // Check if the token is supported - if (destinationData?.supportedTokens?.[token]) { + // Check if the token is supported (supportedTokens is now an array) + const supportedTokens = destinationData?.supportedTokens + if (Array.isArray(supportedTokens) && supportedTokens.includes(token)) { allDestinationLanes[sourceChain] = { ...allDestinationLanes[sourceChain], - [destinationChain]: destinationData.supportedTokens[token], + // Rate limiter config is now in separate files, store empty config + [destinationChain]: {}, } } } @@ -815,3 +840,245 @@ export const getDecommissionedNetwork = ({ chain, filter }: { chain: string; fil const decommissionedChains = getAllDecommissionedNetworks({ filter }) return decommissionedChains.find((network) => network.chain === chain) } + +// ============================================================================ +// Verifier utilities +// ============================================================================ + +/** + * Load verifiers data for a specific environment and version + */ +export const loadVerifiersData = ({ environment, version }: { environment: Environment; version: Version }) => { + let verifiersReferenceData: VerifiersConfig + + if (environment === Environment.Mainnet && version === Version.V1_2_0) { + verifiersReferenceData = verifiersMainnetv120 as unknown as VerifiersConfig + } else if (environment === Environment.Testnet && version === Version.V1_2_0) { + verifiersReferenceData = verifiersTestnetv120 as unknown as VerifiersConfig + } else { + throw new Error(`Invalid environment/version combination for verifiers: ${environment}/${version}`) + } + + return { verifiersReferenceData } +} + +/** + * Get logo URL for a verifier by ID + * Uses CloudFront CDN, same infrastructure as token icons + */ +export const getVerifierIconUrl = (verifierId: string): string => { + return `${VERIFIER_ICON_PATH}/${verifierId}.svg` +} + +/** + * Get logo URL for a network by ID + * Uses CloudFront CDN, same infrastructure as token icons + */ +export const getNetworkIconUrl = (networkName: string | undefined): string | undefined => { + if (!networkName) { + return + } + const normalizedName = normalizeTechnologyName(networkName) + return `${NETWORK_ICON_PATH}/${normalizedName}.svg` +} + +/** + * Map verifier type to display-friendly name + */ +export const getVerifierTypeDisplay = (type: VerifierType): string => { + const VERIFIER_TYPE_DISPLAY: Record<VerifierType, string> = { + committee: "Committee", + api: "API", + } + + return VERIFIER_TYPE_DISPLAY[type] || type +} + +/** + * Get all verifiers for a specific environment as a flattened list + */ +export const getAllVerifiers = ({ + environment, + version = Version.V1_2_0, +}: { + environment: Environment + version?: Version +}): Verifier[] => { + const { verifiersReferenceData } = loadVerifiersData({ environment, version }) + + const verifiers: Verifier[] = [] + + // Flatten the network -> address -> metadata structure + for (const [networkId, addressMap] of Object.entries(verifiersReferenceData)) { + for (const [address, metadata] of Object.entries(addressMap)) { + verifiers.push({ + ...metadata, + network: networkId, + address, + logo: getVerifierIconUrl(metadata.id), + }) + } + } + + // Sort by verifier name, then by network + return verifiers.sort((a, b) => { + const nameComparison = a.name.localeCompare(b.name) + if (nameComparison !== 0) return nameComparison + return a.network.localeCompare(b.network) + }) +} + +/** + * Get all verifiers for a specific network + */ +export const getVerifiersByNetwork = ({ + networkId, + environment, + version = Version.V1_2_0, +}: { + networkId: string + environment: Environment + version?: Version +}): Verifier[] => { + const { verifiersReferenceData } = loadVerifiersData({ environment, version }) + + const addressMap = verifiersReferenceData[networkId] + if (!addressMap) { + return [] + } + + const verifiers: Verifier[] = [] + for (const [address, metadata] of Object.entries(addressMap)) { + verifiers.push({ + ...metadata, + network: networkId, + address, + logo: getVerifierIconUrl(metadata.id), + }) + } + + return verifiers.sort((a, b) => a.name.localeCompare(b.name)) +} + +/** + * Get all verifiers of a specific type (committee or api) + */ +export const getVerifiersByType = ({ + type, + environment, + version = Version.V1_2_0, +}: { + type: VerifierType + environment: Environment + version?: Version +}): Verifier[] => { + const allVerifiers = getAllVerifiers({ environment, version }) + return allVerifiers.filter((verifier) => verifier.type === type) +} + +/** + * Get all networks where a specific verifier exists (by verifier ID) + */ +export const getVerifierById = ({ + id, + environment, + version = Version.V1_2_0, +}: { + id: string + environment: Environment + version?: Version +}): Verifier[] => { + const allVerifiers = getAllVerifiers({ environment, version }) + return allVerifiers.filter((verifier) => verifier.id === id) +} + +/** + * Get a specific verifier by network and address + */ +export const getVerifier = ({ + networkId, + address, + environment, + version = Version.V1_2_0, +}: { + networkId: string + address: string + environment: Environment + version?: Version +}): Verifier | undefined => { + const { verifiersReferenceData } = loadVerifiersData({ environment, version }) + + const addressMap = verifiersReferenceData[networkId] + if (!addressMap) { + return undefined + } + + const metadata = addressMap[address] + if (!metadata) { + return undefined + } + + return { + ...metadata, + network: networkId, + address, + logo: getVerifierIconUrl(metadata.id), + } +} + +/** + * Get all network IDs where a specific verifier exists + * Similar to getChainsOfToken for tokens + */ +export const getNetworksOfVerifier = ({ + id, + environment, + version = Version.V1_2_0, +}: { + id: string + environment: Environment + version?: Version +}): string[] => { + const verifiers = getVerifierById({ id, environment, version }) + return verifiers.map((v) => v.network) +} + +/** + * Get unique verifiers for display (deduplicated by ID) + * Returns one entry per verifier with totalNetworks count + * Useful for landing page display where each verifier should appear once + */ +export const getAllUniqueVerifiers = ({ + environment, + version = Version.V1_2_0, +}: { + environment: Environment + version?: Version +}): Array<{ + id: string + name: string + type: VerifierType + logo: string + totalNetworks: number +}> => { + const allVerifiers = getAllVerifiers({ environment, version }) + + // Get unique verifier IDs + const uniqueIds = Array.from(new Set(allVerifiers.map((v) => v.id))) + + // Map to display format with network count + return uniqueIds + .map((id) => { + const instances = allVerifiers.filter((v) => v.id === id) + const firstInstance = instances[0] + + return { + id, + name: firstInstance.name, + type: firstInstance.type, + logo: firstInstance.logo, + totalNetworks: instances.length, + } + }) + .sort((a, b) => a.name.localeCompare(b.name)) +} diff --git a/src/config/data/ccip/selectors.yml b/src/config/data/ccip/selectors.yml index b10a86e7cef..943a855c5d5 100644 --- a/src/config/data/ccip/selectors.yml +++ b/src/config/data/ccip/selectors.yml @@ -6,758 +6,1063 @@ selectors: 31: selector: "8953668971247136127" name: "bitcoin-testnet-rootstock" + network_type: testnet 41: selector: "729797994450396300" name: "telos-evm-testnet" + network_type: testnet 45: selector: "4340886533089894000" name: "polkadot-testnet-darwinia-pangoro" + network_type: testnet 51: selector: "3017758115101368649" name: "xdc-testnet" + network_type: testnet 53: selector: "8955032871639343000" name: "coinex_smart_chain-testnet" + network_type: testnet 81: selector: "6955638871347136141" name: "polkadot-testnet-astar-shibuya" + network_type: testnet 97: selector: "13264668187771770619" name: "binance_smart_chain-testnet" + network_type: testnet 133: selector: "4356164186791070119" name: "ethereum-testnet-sepolia-hashkey-1" + network_type: testnet 157: selector: "17833296867764334567" name: "shibarium-testnet-puppynet" + network_type: testnet 111: selector: "572210378683744374" name: "velas-testnet" + network_type: testnet 195: selector: "2066098519157881736" name: "ethereum-testnet-sepolia-xlayer-1" + network_type: testnet 240: selector: "16487132492576884721" name: "cronos-zkevm-testnet-sepolia" + network_type: testnet 280: selector: "6802309497652714138" name: "ethereum-testnet-goerli-zksync-1" + network_type: testnet 282: selector: "3842103497652714138" name: "cronos-testnet-zkevm-1" + network_type: testnet 296: selector: "222782988166878823" name: "hedera-testnet" + network_type: testnet 300: selector: "6898391096552792247" name: "ethereum-testnet-sepolia-zksync-1" + network_type: testnet 338: selector: "2995292832068775165" name: "cronos-testnet" + network_type: testnet 398: selector: "5061593697262339000" name: "near-testnet" + network_type: testnet 420: selector: "2664363617261496610" name: "ethereum-testnet-goerli-optimism-1" + network_type: testnet 462: selector: "7317911323415911000" name: "areon-testnet" + network_type: testnet 678: selector: "9107126442626377432" name: "janction-mainnet" + network_type: mainnet 679: selector: "5059197667603797935" name: "janction-testnet-sepolia" + network_type: testnet 682: selector: "6260932437388305511" name: "private-testnet-obsidian" + network_type: testnet 919: selector: "829525985033418733" name: "ethereum-testnet-sepolia-mode-1" + network_type: testnet 1001: selector: "2624132734533621656" name: "kaia-testnet-kairos" + network_type: testnet 1029: selector: "4459371029167934217" name: "bittorrent_chain-testnet" + network_type: testnet 1112: selector: "9284632837123596123" name: "wemix-testnet" + network_type: testnet 1114: selector: "4264732132125536123" name: "core-testnet" + network_type: testnet 1123: selector: "1948510578179542068" name: "bitcoin-testnet-bsquared-1" + network_type: testnet 12325: selector: "3486622437121596122" name: "ethereum-testnet-sepolia-arbitrum-1-l3x-1" + network_type: testnet 1287: selector: "5361632739113536121" name: "polkadot-testnet-moonbeam-moonbase" + network_type: testnet 2088: selector: "2333097300889804761" name: "polkadot-testnet-centrifuge-altair" + network_type: testnet 1337: selector: "3379446385462418246" name: "geth-testnet" + network_type: testnet 31337: selector: "7759470850252068959" name: "anvil-devnet" + network_type: testnet 45439: selector: "8446413392851542429" name: "private-testnet-opala" + network_type: testnet 1442: selector: "11059667695644972511" name: "ethereum-testnet-goerli-polygon-zkevm-1" + network_type: testnet 1908: selector: "4888058894222120000" name: "bitcichain-testnet" + network_type: testnet 2129: selector: "12168171414969487009" name: "memento-testnet" + network_type: testnet 2201: selector: "11793402411494852765" name: "stable-testnet" + network_type: testnet 2221: selector: "2110537777356199208" name: "kava-testnet" + network_type: testnet 2358: selector: "5990477251245693094" name: "ethereum-testnet-sepolia-kroma-1" + network_type: testnet 2442: selector: "1654667687261492630" name: "ethereum-testnet-sepolia-polygon-zkevm-1" + network_type: testnet 2522: selector: "8901520481741771655" name: "ethereum-testnet-holesky-fraxtal-1" + network_type: testnet 2810: selector: "8304510386741731151" name: "ethereum-testnet-holesky-morph-1" + network_type: testnet 3636: selector: "1467223411771711614" name: "bitcoin-testnet-botanix" + network_type: testnet 4002: selector: "4905564228793744293" name: "fantom-testnet" + network_type: testnet 4202: selector: "5298399861320400553" name: "ethereum-testnet-sepolia-lisk-1" + network_type: testnet 5001: selector: "4168263376276232250" name: "ethereum-testnet-goerli-mantle-1" + network_type: testnet 5003: selector: "8236463271206331221" name: "ethereum-testnet-sepolia-mantle-1" + network_type: testnet 9559: selector: "1113014352258747600" name: "neonlink-testnet" + network_type: testnet 10143: selector: "2183018362218727504" name: "monad-testnet" + network_type: testnet 13473: selector: "4526165231216331901" name: "ethereum-testnet-sepolia-immutable-zkevm-1" + network_type: testnet 16600: selector: "16088006396410204581" name: "0g-testnet-newton" + network_type: testnet 16601: selector: "2131427466778448014" name: "0g-testnet-galileo" + network_type: testnet 16602: selector: "6892437333620424805" name: "0g-testnet-galileo-1" + network_type: testnet 33111: selector: "9900119385908781505" name: "apechain-testnet-curtis" - 43111: - selector: "1804312132722180201" - name: "hemi-mainnet" + network_type: testnet + 33431: + selector: "13222148116102326311" + name: "edge-testnet" + network_type: testnet 43113: selector: "14767482510784806043" name: "avalanche-testnet-fuji" + network_type: testnet 44787: selector: "3552045678561919002" name: "celo-testnet-alfajores" + network_type: testnet 48898: selector: "13781831279385219069" name: "zircuit-testnet-garfield" + network_type: testnet 48899: selector: "4562743618362911021" name: "ethereum-testnet-sepolia-zircuit-1" + network_type: testnet 59140: selector: "1355246678561316402" name: "ethereum-testnet-goerli-linea-1" + network_type: testnet 59141: selector: "5719461335882077547" name: "ethereum-testnet-sepolia-linea-1" + network_type: testnet 59902: selector: "3777822886988675105" name: "ethereum-testnet-sepolia-metis-1" + network_type: testnet 76578: selector: "781901677223027175" + network_type: testnet 80001: selector: "12532609583862916517" name: "polygon-testnet-mumbai" + network_type: testnet 80002: selector: "16281711391670634445" name: "polygon-testnet-amoy" + network_type: testnet 80085: selector: "12336603543561911511" name: "berachain-testnet-artio" + network_type: testnet 80084: selector: "8999465244383784164" name: "berachain-testnet-bartio" + network_type: testnet 80069: selector: "7728255861635209484" name: "berachain-testnet-bepolia" + network_type: testnet 80087: selector: "2285225387454015855" name: "zero-g-testnet-galileo" + network_type: testnet 84531: selector: "5790810961207155433" name: "ethereum-testnet-goerli-base-1" + network_type: testnet 84532: selector: "10344971235874465080" name: "ethereum-testnet-sepolia-base-1" + network_type: testnet 98867: selector: "13874588925447303949" name: "plume-testnet-sepolia" + network_type: testnet 10200: selector: "8871595565390010547" name: "gnosis_chain-testnet-chiado" + network_type: testnet 421613: selector: "6101244977088475029" name: "ethereum-testnet-goerli-arbitrum-1" + network_type: testnet 421614: selector: "3478487238524512106" name: "ethereum-testnet-sepolia-arbitrum-1" + network_type: testnet 432201: selector: "1458281248224512906" name: "avalanche-subnet-dexalot-testnet" + network_type: testnet 717160: selector: "4418231248214522936" name: "ethereum-testnet-sepolia-polygon-validium-1" + network_type: testnet 743111: selector: "16126893759944359622" name: "hemi-testnet-sepolia" + network_type: testnet 763373: selector: "9763904284804119144" name: "ink-testnet-sepolia" + network_type: testnet 534351: selector: "2279865765895943307" name: "ethereum-testnet-sepolia-scroll-1" + network_type: testnet 686868: selector: "5269261765892944301" name: "bitcoin-testnet-merlin" + network_type: testnet 5668: selector: "8911150974185440581" name: "nexon-dev" + network_type: testnet 595581: selector: "7837562506228496256" name: "avalanche-testnet-nexon" + network_type: testnet 807424: selector: "14632960069656270105" name: "nexon-qa" + network_type: testnet 847799: selector: "5556806327594153475" name: "nexon-stage" + network_type: testnet 810181: selector: "5837261596322416298" name: "zklink_nova-testnet" + network_type: testnet 978658: selector: "3676916124122457866" name: "treasure-testnet-topaz" + network_type: testnet 31415926: selector: "7060342227814389000" name: "filecoin-testnet" + network_type: testnet 11155111: selector: "16015286601757825753" name: "ethereum-testnet-sepolia" + network_type: testnet 11155420: selector: "5224473277236331295" name: "ethereum-testnet-sepolia-optimism-1" + network_type: testnet 21000001: selector: "1467427327723633929" name: "ethereum-testnet-sepolia-corn-1" + network_type: testnet 168587773: selector: "2027362563942762617" name: "ethereum-testnet-sepolia-blast-1" + network_type: testnet 978657: selector: "10443705513486043421" name: "ethereum-testnet-sepolia-arbitrum-1-treasure-1" + network_type: testnet 1946: selector: "686603546605904534" name: "ethereum-testnet-sepolia-soneium-1" + network_type: testnet 2021: selector: "13116810400804392105" name: "ronin-testnet-saigon" + network_type: testnet 2023: selector: "3260900564719373474" name: "private-testnet-granite" + network_type: testnet 2024: selector: "6915682381028791124" name: "private-testnet-andesite" + network_type: testnet 2025: selector: "15513093881969820114" name: "dtcc-testnet-andesite" + network_type: testnet 200810: selector: "3789623672476206327" name: "bitcoin-testnet-bitlayer-1" + network_type: testnet 808813: selector: "5535534526963509396" name: "bitcoin-testnet-sepolia-bob-1" + network_type: testnet 37111: selector: "6827576821754315911" name: "ethereum-testnet-sepolia-lens-1" + network_type: testnet 1328: selector: "1216300075444106652" name: "sei-testnet-atlantic" + network_type: testnet 57054: selector: "3676871237479449268" name: "sonic-testnet-blaze" + network_type: testnet 998: selector: "4286062357653186312" name: "hyperliquid-testnet" + network_type: testnet 1513: selector: "4237030917318060427" name: "story-testnet" + network_type: testnet 5611: selector: "13274425992935471758" name: "binance_smart_chain-testnet-opbnb-1" + network_type: testnet 17000: selector: "7717148896336251131" name: "ethereum-testnet-holesky" + network_type: testnet 1301: selector: "14135854469784514356" name: "ethereum-testnet-sepolia-unichain-1" + network_type: testnet 167009: selector: "7248756420937879088" name: "ethereum-testnet-holesky-taiko-1" + network_type: testnet 161221135: selector: "14684575664602284776" name: "plume-testnet" + network_type: testnet 98864: selector: "3743020999916460931" name: "plume-devnet" + network_type: testnet 4801: selector: "5299555114858065850" name: "ethereum-testnet-sepolia-worldchain-1" + network_type: testnet 192940: selector: "7189150270347329685" name: "mind-testnet" + network_type: testnet 1338: selector: "2181150070347029680" + network_type: testnet 6342: selector: "2443239559770384419" name: "megaeth-testnet" + network_type: testnet 6343: selector: "18241817625092392675" name: "megaeth-testnet-2" + network_type: testnet 999999999: selector: "16244020411108056671" name: "zora-testnet" + network_type: testnet 1687: selector: "10749384167430721561" name: "mint-testnet" + network_type: testnet 11124: selector: "16235373811196386733" name: "abstract-testnet" + network_type: testnet 53302: selector: "13694007683517087973" name: "superseed-testnet" + network_type: testnet 128123: selector: "1910019406958449359" name: "etherlink-testnet" + network_type: testnet 1740: selector: "6286293440461807648" name: "metal-testnet" + network_type: testnet 6930: selector: "305104239123120457" name: "nibiru-testnet" + network_type: testnet 9000: selector: "344208382356656551" name: "ondo-testnet" + network_type: testnet 129399: selector: "9090863410735740267" name: "polygon-testnet-tatara" + network_type: testnet 9746: selector: "3967220077692964309" name: "plasma-testnet" + network_type: testnet 688688: selector: "4012524741200567430" name: "pharos-testnet" + network_type: testnet 812242: selector: "7225665875429174318" name: "codex-testnet" + network_type: testnet 2391: selector: "9488606126177218005" name: "tac-testnet" + network_type: testnet 945: selector: "2177900824115119161" name: "bittensor-testnet" + network_type: testnet 2019775: selector: "945045181441419236" name: "jovay-testnet" + network_type: testnet 6398: selector: "379340054879810246" name: "everclear-testnet-sepolia" + network_type: testnet 1952: selector: "10212741611335999305" name: "xlayer-testnet" + network_type: testnet 560048: selector: "10380998176179737091" name: "ethereum-testnet-hoodi" + network_type: testnet 11142220: selector: "3761762704474186180" name: "celo-sepolia" + network_type: testnet 167012: selector: "9873759436596923887" name: "ethereum-testnet-hoodi-taiko" + network_type: testnet 167013: selector: "15858691699034549072" name: "ethereum-testnet-hoodi-taiko-1" + network_type: testnet 26888: selector: "7051849327615092843" name: "ab-testnet" + network_type: testnet 688689: selector: "16098325658947243212" name: "pharos-atlantic-testnet" + network_type: testnet 2910: selector: "1064004874793747259" name: "ethereum-testnet-hoodi-morph" + network_type: testnet 5042002: selector: "3034092155422581607" name: "arc-testnet" + network_type: testnet 42429: selector: "3963528237232804922" name: "tempo-testnet" + network_type: testnet + 42431: + selector: "8457817439310187923" + name: "tempo-testnet-moderato" + network_type: testnet + 10087: + selector: "3667207123485082040" + name: gate-layer-testnet + network_type: testnet + 85: + selector: "3558960680482140165" + name: gate-chain-testnet-meteora + network_type: testnet + 99999: + selector: "9418205736192840573" + name: "adi-testnet" + network_type: testnet + 14601: + selector: "1763698235108410440" + name: "sonic-testnet" + network_type: testnet + 424242: + selector: "4489326297382772450" + name: "private-testnet-mica" + network_type: testnet + 12227332: + selector: "2217764097022649312" + name: "neox-testnet-t4" + network_type: testnet + 3448148188: + selector: "2052925811360307749" + name: "tron-testnet-nile-evm" + network_type: testnet + 2494104990: + selector: "13231703482326770598" + name: "tron-testnet-shasta-evm" + network_type: testnet + 6281971: + selector: "7254999290874773717" + name: dogeos-testnet-chikyu + network_type: testnet # Mainnets 1: selector: "5009297550715157269" name: "ethereum-mainnet" + network_type: mainnet 10: selector: "3734403246176062136" name: "ethereum-mainnet-optimism-1" + network_type: mainnet 25: selector: "1456215246176062136" name: "cronos-mainnet" + network_type: mainnet 30: selector: "11964252391146578476" name: "rootstock-mainnet" + network_type: mainnet 40: selector: "1477345371608778000" name: "telos-evm-mainnet" + network_type: mainnet 46: selector: "8866418665544333000" name: "polkadot-mainnet-darwinia" + network_type: mainnet 50: selector: "17673274061779414707" name: "xdc-mainnet" + network_type: mainnet 52: selector: "1761333065194157300" name: "coinex_smart_chain-mainnet" + network_type: mainnet 56: selector: "11344663589394136015" name: "binance_smart_chain-mainnet" + network_type: mainnet 100: selector: "465200170687744372" name: "gnosis_chain-mainnet" + network_type: mainnet 106: selector: "374210358663784372" name: "velas-mainnet" + network_type: mainnet 109: selector: "3993510008929295315" name: "shibarium-mainnet" + network_type: mainnet 130: selector: "1923510103922296319" name: "ethereum-mainnet-unichain-1" + network_type: mainnet 137: selector: "4051577828743386545" name: "polygon-mainnet" + network_type: mainnet 146: selector: "1673871237479749969" name: "sonic-mainnet" + network_type: mainnet 177: selector: "7613811247471741961" name: "ethereum-mainnet-hashkey-1" + network_type: mainnet 196: selector: "3016212468291539606" name: "ethereum-mainnet-xlayer-1" + network_type: mainnet 199: selector: "3776006016387883143" name: "bittorrent_chain-mainnet" + network_type: mainnet 252: selector: "1462016016387883143" name: "fraxtal-mainnet" + network_type: mainnet 255: selector: "3719320017875267166" name: "ethereum-mainnet-kroma-1" + network_type: mainnet 259: selector: "8239338020728974000" name: "neonlink-mainnet" + network_type: mainnet 295: selector: "3229138320728879060" name: "hedera-mainnet" + network_type: mainnet 314: selector: "4561443241176882990" name: "filecoin-mainnet" + network_type: mainnet 324: selector: "1562403441176082196" name: "ethereum-mainnet-zksync-1" + network_type: mainnet 388: selector: "8788096068760390840" name: "cronos-zkevm-mainnet" + network_type: mainnet 397: selector: "2039744413822257700" name: "near-mainnet" + network_type: mainnet 463: selector: "1939936305787790600" name: "areon-mainnet" + network_type: mainnet 592: selector: "6422105447186081193" name: "polkadot-mainnet-astar" + network_type: mainnet 988: selector: "16978377838628290997" name: "stable-mainnet" + network_type: mainnet 999: selector: "2442541497099098535" name: "hyperliquid-mainnet" + network_type: mainnet 1088: selector: "8805746078405598895" name: "ethereum-mainnet-metis-1" + network_type: mainnet 1101: selector: "4348158687435793198" name: "ethereum-mainnet-polygon-zkevm-1" + network_type: mainnet 1111: selector: "5142893604156789321" name: "wemix-mainnet" + network_type: mainnet 1116: selector: "1224752112135636129" name: "core-mainnet" + network_type: mainnet 61166: selector: "5214452172935136222" name: "treasure-mainnet" - 12227332: - selector: "2217764097022649312" - name: "neox-testnet-t4" + network_type: mainnet 12324: selector: "3162193654116181371" name: "ethereum-mainnet-arbitrum-1-l3x-1" + network_type: mainnet 1284: selector: "1252863800116739621" name: "polkadot-mainnet-moonbeam" + network_type: mainnet 1285: selector: "1355020143337428062" name: "kusama-mainnet-moonriver" + network_type: mainnet 1868: selector: "12505351618335765396" name: "soneium-mainnet" + network_type: mainnet 1907: selector: "4874388048629246000" name: "bitcichain-mainnet" + network_type: mainnet 2222: selector: "7550000543357438061" name: "kava-mainnet" + network_type: mainnet + 3343: + selector: "6325494908023253251" + name: "edge-mainnet" + network_type: mainnet 3637: selector: "4560701533377838164" name: "bitcoin-mainnet-botanix" + network_type: mainnet 3776: selector: "1540201334317828111" name: "ethereum-mainnet-astar-zkevm-1" + network_type: mainnet 4200: selector: "241851231317828981" name: "bitcoin-merlin-mainnet" + network_type: mainnet 5000: selector: "1556008542357238666" name: "ethereum-mainnet-mantle-1" + network_type: mainnet 8217: selector: "9813823125703490621" name: "kaia-mainnet" + network_type: mainnet 8453: selector: "15971525489660198786" name: "ethereum-mainnet-base-1" + network_type: mainnet 13371: selector: "1237925231416731909" name: "ethereum-mainnet-immutable-zkevm-1" + network_type: mainnet 33139: selector: "14894068710063348487" name: "apechain-mainnet" + network_type: mainnet 34443: selector: "7264351850409363825" name: "ethereum-mainnet-mode-1" + network_type: mainnet 42161: selector: "4949039107694359620" name: "ethereum-mainnet-arbitrum-1" + network_type: mainnet 42220: selector: "1346049177634351622" name: "celo-mainnet" + network_type: mainnet 43114: selector: "6433500567565415381" name: "avalanche-mainnet" + network_type: mainnet 47763: selector: "7222032299962346917" name: "neox-mainnet" + network_type: mainnet 51888: selector: "6473245816409426016" name: "memento-mainnet" + network_type: mainnet 80094: selector: "1294465214383781161" name: "berachain-mainnet" + network_type: mainnet 98865: selector: "3208172210661564830" + network_type: testnet 98866: selector: "17912061998839310979" name: "plume-mainnet" + network_type: mainnet 432204: selector: "5463201557265485081" name: "avalanche-subnet-dexalot-mainnet" + network_type: mainnet 57073: selector: "3461204551265785888" name: "ethereum-mainnet-ink-1" + network_type: mainnet 59144: selector: "4627098889531055414" name: "ethereum-mainnet-linea-1" + network_type: mainnet 81457: selector: "4411394078118774322" name: "ethereum-mainnet-blast-1" + network_type: mainnet 534352: selector: "13204309965629103672" name: "ethereum-mainnet-scroll-1" + network_type: mainnet 810180: selector: "4350319965322101699" name: "zklink_nova-mainnet" + network_type: mainnet 2031: selector: "8175830712062617656" name: "polkadot-mainnet-centrifuge" + network_type: mainnet 978670: selector: "1010349088906777999" name: "ethereum-mainnet-arbitrum-1-treasure-1" - 424242: - selector: "4489326297382772450" - name: "private-testnet-mica" + network_type: mainnet 48900: selector: "17198166215261833993" name: "ethereum-mainnet-zircuit-1" + network_type: mainnet 223: selector: "5406759801798337480" name: "bitcoin-mainnet-bsquared-1" + network_type: mainnet 200901: selector: "7937294810946806131" name: "bitcoin-mainnet-bitlayer-1" + network_type: mainnet 60808: selector: "3849287863852499584" name: "bitcoin-mainnet-bob-1" + network_type: mainnet 1329: selector: "9027416829622342829" name: "sei-mainnet" + network_type: mainnet 2020: selector: "6916147374840168594" name: "ronin-mainnet" + network_type: mainnet 204: selector: "465944652040885897" name: "binance_smart_chain-mainnet-opbnb-1" + network_type: mainnet 167000: selector: "16468599424800719238" name: "ethereum-mainnet-taiko-1" + network_type: mainnet 250: selector: "3768048213127883732" name: "fantom-mainnet" + network_type: mainnet 480: selector: "2049429975587534727" name: "ethereum-mainnet-worldchain-1" + network_type: mainnet 21000000: selector: "9043146809313071210" name: "corn-mainnet" + network_type: mainnet 2818: selector: "18164309074156128038" name: "morph-mainnet" + network_type: mainnet 232: selector: "5608378062013572713" name: "lens-mainnet" + network_type: mainnet 228: selector: "11690709103138290329" name: "mind-mainnet" - 3448148188: - selector: "2052925811360307749" - name: "tron-testnet-nile-evm" - 2494104990: - selector: "13231703482326770598" - name: "tron-testnet-shasta-evm" + network_type: mainnet 728126428: selector: "1546563616611573946" name: "tron-mainnet-evm" + network_type: mainnet 3360022319: selector: "13231703482326770600" name: "tron-devnet-evm" + network_type: testnet 7777777: selector: "3555797439612589184" name: "zora-mainnet" + network_type: mainnet 5330: selector: "470401360549526817" name: "superseed-mainnet" + network_type: mainnet 2741: selector: "3577778157919314504" name: "abstract-mainnet" + network_type: mainnet 1135: selector: "15293031020466096408" name: "lisk-mainnet" + network_type: mainnet 185: selector: "17164792800244661392" name: "mint-mainnet" + network_type: mainnet 42793: selector: "13624601974233774587" name: "etherlink-mainnet" + network_type: mainnet 1750: selector: "13447077090413146373" name: "metal-mainnet" + network_type: mainnet 6900: selector: "17349189558768828726" name: "nibiru-mainnet" + network_type: mainnet 60118: selector: "15758750456714168963" name: "nexon-mainnet-lith" + network_type: mainnet 68414: selector: "12657445206920369324" name: "nexon-mainnet-henesys" + network_type: mainnet 7000: selector: "10817664450262215148" name: "zetachain-mainnet" + network_type: mainnet 1030: selector: "3358365939762719202" name: "conflux-mainnet" + network_type: mainnet 747474: selector: "2459028469735686113" name: "polygon-mainnet-katana" + network_type: mainnet 9745: selector: "9335212494177455608" name: "plasma-mainnet" + network_type: mainnet 81224: selector: "9478124434908827753" name: "codex-mainnet" + network_type: mainnet 239: selector: "5936861837188149645" name: "tac-mainnet" + network_type: mainnet 143: selector: "8481857512324358265" name: "monad-mainnet" + network_type: mainnet 16661: selector: "4426351306075016396" name: "0g-mainnet" + network_type: mainnet 964: selector: "2135107236357186872" name: "bittensor-mainnet" + network_type: mainnet 5734951: selector: "1523760397290643893" name: "jovay-mainnet" + network_type: mainnet 25327: selector: "9723842205701363942" name: "everclear-mainnet" + network_type: mainnet 36888: selector: "4829375610284793157" name: "ab-mainnet" + network_type: mainnet 4326: selector: "6093540873831549674" name: "megaeth-mainnet" + network_type: mainnet + 10088: + selector: "9373518659714509671" + name: gate-layer-mainnet + network_type: mainnet + 86: + selector: "9688382747979139404" + name: gate-chain-mainnet + network_type: mainnet + 1672: + selector: "7801139999541420232" + name: pharos-mainnet + network_type: mainnet + 36900: + selector: "4059281736450291836" + name: "adi-mainnet" + network_type: mainnet + 4217: + selector: "7281642695469137430" + name: "tempo-mainnet" + network_type: mainnet + 43111: + selector: "1804312132722180201" + name: "hemi-mainnet" + network_type: mainnet diff --git a/src/config/data/ccip/selectors_aptos.yml b/src/config/data/ccip/selectors_aptos.yml index a9e553aed94..9ac04e05a49 100644 --- a/src/config/data/ccip/selectors_aptos.yml +++ b/src/config/data/ccip/selectors_aptos.yml @@ -2,9 +2,12 @@ selectors: 1: name: aptos-mainnet selector: "4741433654826277614" + network_type: mainnet 2: name: aptos-testnet selector: "743186221051783445" + network_type: testnet 4: name: aptos-localnet selector: "4457093679053095497" + network_type: testnet diff --git a/src/config/data/ccip/selectors_solana.yml b/src/config/data/ccip/selectors_solana.yml index 758e832c6bb..ecb3b50ceec 100644 --- a/src/config/data/ccip/selectors_solana.yml +++ b/src/config/data/ccip/selectors_solana.yml @@ -2,9 +2,12 @@ selectors: "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d": # bash58 encoded genesis hash, https://solana.com/docs/rpc/http/getgenesishash name: solana-mainnet selector: "124615329519749607" + network_type: mainnet "4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY": name: solana-testnet selector: "6302590918974934319" + network_type: testnet "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG": name: solana-devnet selector: "16423721717087811551" + network_type: testnet diff --git a/src/config/data/ccip/types.ts b/src/config/data/ccip/types.ts index e12d25d1828..3fee210b5f2 100644 --- a/src/config/data/ccip/types.ts +++ b/src/config/data/ccip/types.ts @@ -17,7 +17,7 @@ export type SupportedTokensConfig = { } export type LaneConfig = { - supportedTokens?: SupportedTokensConfig + supportedTokens?: string[] rateLimiterConfig?: RateLimiterConfig onRamp: { address: string @@ -36,11 +36,21 @@ export type DestinationsLaneConfig = { export type PoolType = "lockRelease" | "burnMint" | "usdc" | "feeTokenOnly" +export type PoolRawType = "LockRelease" | "BurnMint" | "usdc" + +type Pool = { + address?: string + rawType: PoolRawType + type: PoolType + version: string +} + type PoolInfo = { tokenAddress: string allowListEnabled: boolean + pool?: Pool poolAddress?: string - poolType: PoolType + poolType?: string name?: string symbol: string decimals: number @@ -232,3 +242,24 @@ export interface DecommissionedNetwork { explorer: ExplorerInfo chainType: ChainType } + +// Verifier types +export type VerifierType = "committee" | "api" + +export interface VerifierMetadata { + id: string + name: string + type: VerifierType +} + +export interface VerifiersConfig { + [networkId: string]: { + [address: string]: VerifierMetadata + } +} + +export interface Verifier extends VerifierMetadata { + network: string + address: string + logo: string +} diff --git a/src/config/data/ccip/utils.ts b/src/config/data/ccip/utils.ts index 5a4783a37b6..014fd16d1a3 100644 --- a/src/config/data/ccip/utils.ts +++ b/src/config/data/ccip/utils.ts @@ -2,7 +2,7 @@ import { SupportedChain } from "~/config/types.ts" import { chainToTechnology } from "~/config/chains.ts" import { NetworkFeeStructure, PoolType, TokenMechanism, LaneSpecificFeeKey, RateLimiterConfig } from "./types.ts" import { networkFees } from "./data.ts" -import { commify } from "~/utils/index.js" +import { commify } from "~/utils/number.ts" import { formatUnits } from "ethers" // Define valid pool type combinations and their corresponding mechanisms @@ -33,9 +33,9 @@ export const determineTokenMechanism = ( export const tokenPoolDisplay = (poolType?: PoolType) => { const poolTypeMapping: Record<PoolType, string> = { - lockRelease: "Lock/Release", - burnMint: "Burn/Mint", - usdc: "Burn/Mint", + lockRelease: "LockRelease", + burnMint: "BurnMint", + usdc: "BurnMint", feeTokenOnly: "Fee Token Only", } diff --git a/src/config/data/ccip/v1_2_0/mainnet/chains.json b/src/config/data/ccip/v1_2_0/mainnet/chains.json index 3ff82daadfb..1e787d51fbd 100644 --- a/src/config/data/ccip/v1_2_0/mainnet/chains.json +++ b/src/config/data/ccip/v1_2_0/mainnet/chains.json @@ -576,7 +576,7 @@ "version": "1.0.0" }, "chainSelector": "3461204551265785888", - "feeTokens": ["LINK", "WETH"], + "feeTokens": ["GHO", "LINK", "WETH"], "registryModule": { "address": "0x04c5046A1f4E3fFf094c26dFCAA75eF293932f18", "version": "1.6.0" @@ -1018,6 +1018,26 @@ "version": "1.5.1" } }, + "jovay-mainnet": { + "armProxy": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.0.0" + }, + "chainSelector": "1523760397290643893", + "feeTokens": ["LINK", "WETH"], + "registryModule": { + "address": "0xf4a170A36D4C656F614d44453f73308Bdb275196", + "version": "1.6.0" + }, + "router": { + "address": "0x492641F648a4986844848E0beFE66D14817bCE34", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.5.0" + } + }, "kaia-mainnet": { "armProxy": { "address": "0x98E7867DE8D5904bEda540Ee2Ee4E941Ac1caFD9", @@ -1138,6 +1158,26 @@ "version": "1.5.1" } }, + "megaeth-mainnet": { + "armProxy": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.0.0" + }, + "chainSelector": "6093540873831549674", + "feeTokens": ["LINK", "WETH"], + "registryModule": { + "address": "0x1E11bAB3f07fa72312182fFDc460AE45400E6e7b", + "version": "1.6.0" + }, + "router": { + "address": "0xfa546248C54939AA6C48279CdC1EAf9A1125c411", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0xf4a170A36D4C656F614d44453f73308Bdb275196", + "version": "1.5.0" + } + }, "memento-mainnet": { "armProxy": { "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", @@ -1250,6 +1290,26 @@ "version": "1.5.0" } }, + "morph-mainnet": { + "armProxy": { + "address": "0x15C03488B29e27d62BAf10E30b0c474bf60E0264", + "version": "1.0.0" + }, + "chainSelector": "18164309074156128038", + "feeTokens": ["LINK", "WETH"], + "registryModule": { + "address": "0x9A82E768C885DEF7C4b47451Fd4Db53d8B21ed07", + "version": "1.6.0" + }, + "router": { + "address": "0x3201a20D2a33820C0DaC8Bc93C4819755C2a8c7F", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0xEfd5fEFEdE55B5C41B8fa0d171a79ba5BeadD2Aa", + "version": "1.5.0" + } + }, "nexon-mainnet-henesys": { "armProxy": { "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", @@ -1276,7 +1336,7 @@ "version": "1.0.0" }, "chainSelector": "9335212494177455608", - "feeTokens": ["LINK", "WXPL"], + "feeTokens": ["GHO", "LINK", "WXPL"], "registryModule": { "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", "version": "1.6.0" @@ -1524,6 +1584,26 @@ "version": "1.5.1" } }, + "stable-mainnet": { + "armProxy": { + "address": "0x8A76fe7fA6da27f85a626c5C53730B38D13603d7", + "version": "1.0.0" + }, + "chainSelector": "16978377838628290997", + "feeTokens": ["LINK", "WgUSDT"], + "registryModule": { + "address": "0x7CcFb2Fa43637b4858Cb1269CF0d64a99e8C668a", + "version": "1.6.0" + }, + "router": { + "address": "0xECFF67559c0583027A5fbd85136E33bC4D66eeA0", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0x3c23e6FB09064e9A64829Fa8FEe27Ad19A27Bfa9", + "version": "1.5.0" + } + }, "superseed-mainnet": { "armProxy": { "address": "0x1A99FF887e5bb3962dA97F409487663B5F539799", diff --git a/src/config/data/ccip/v1_2_0/mainnet/lanes.json b/src/config/data/ccip/v1_2_0/mainnet/lanes.json index 03b56166fc6..0a3b4900f34 100644 --- a/src/config/data/ccip/v1_2_0/mainnet/lanes.json +++ b/src/config/data/ccip/v1_2_0/mainnet/lanes.json @@ -9,6 +9,22 @@ "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", "enforceOutOfOrder": false, "version": "1.6.0" + }, + "supportedTokens": { + "W0G": { + "rateLimiterConfig": { + "in": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + }, + "out": { + "capacity": "0", + "isEnabled": false, + "rate": "0" + } + } + } } }, "ethereum-mainnet-arbitrum-1": { @@ -20,7 +36,8 @@ "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", "enforceOutOfOrder": false, "version": "1.6.0" - } + }, + "supportedTokens": ["W0G"] }, "ethereum-mainnet-base-1": { "offRamp": { @@ -31,7 +48,8 @@ "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", "enforceOutOfOrder": false, "version": "1.6.0" - } + }, + "supportedTokens": ["W0G"] }, "hyperliquid-mainnet": { "offRamp": { @@ -45,6 +63,18 @@ } }, "mainnet": { + "offRamp": { + "address": "0xb0B4b5847E35033766d5B49CD9C0fC40F459321F", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LINK", "USDC", "USDT", "W0G", "wstETH"] + }, + "monad-mainnet": { "offRamp": { "address": "0xb0B4b5847E35033766d5B49CD9C0fC40F459321F", "version": "1.6.0" @@ -55,21 +85,7 @@ "version": "1.6.0" }, "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { + "W0G": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -82,34 +98,6 @@ "rate": "0" } } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - }, - "out": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - } - } } } }, @@ -122,36 +110,9 @@ "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", "enforceOutOfOrder": true, "version": "1.6.0" - } - } - }, - "ab-mainnet": { - "mainnet": { - "offRamp": { - "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x9b04018b5285FF16F3967Af108Bdc72423d547cC", - "enforceOutOfOrder": false, - "version": "1.6.0" }, "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USD1": { + "W0G": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -168,6 +129,20 @@ } } }, + "ab-mainnet": { + "mainnet": { + "offRamp": { + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x9b04018b5285FF16F3967Af108Bdc72423d547cC", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LINK", "USD1"] + } + }, "abstract-mainnet": { "mainnet": { "offRamp": { @@ -178,6 +153,22 @@ "address": "0xb4a8D5807faff7da4AeF857837Fe89a903A01511", "enforceOutOfOrder": false, "version": "1.5.0" + }, + "supportedTokens": { + "wstETH": { + "rateLimiterConfig": { + "in": { + "capacity": "500000000000000000000", + "isEnabled": true, + "rate": "5787000000000000" + }, + "out": { + "capacity": "300000000000000000000", + "isEnabled": true, + "rate": "3472000000000000" + } + } + } } } }, @@ -260,50 +251,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["USD1", "brBTC", "uniBTC"] }, "ethereum-mainnet-arbitrum-1": { "offRamp": { @@ -326,22 +274,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388000000" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388000000" - } - } - } - } + "supportedTokens": ["LINK"] }, "ethereum-mainnet-ink-1": { "offRamp": { @@ -365,6 +298,17 @@ "version": "1.6.0" } }, + "ethereum-mainnet-mantle-1": { + "offRamp": { + "address": "0x20f808de3375db34d17cc946ec6b43fc26962f6afa125182dc903359756caf6b", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x20f808de3375db34d17cc946ec6b43fc26962f6afa125182dc903359756caf6b", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, "ethereum-mainnet-optimism-1": { "offRamp": { "address": "0x20f808de3375db34d17cc946ec6b43fc26962f6afa125182dc903359756caf6b", @@ -397,64 +341,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388000000" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["LINK", "USD1", "brBTC", "uniBTC"] }, "plasma-mainnet": { "offRamp": { @@ -477,22 +364,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388000000" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388000000" - } - } - } - } + "supportedTokens": ["LINK"] }, "xdai-mainnet": { "offRamp": { @@ -518,18 +390,18 @@ "version": "1.6.0" } }, - "bitcoin-mainnet-bitlayer-1": { + "berachain-mainnet": { "offRamp": { - "address": "0x0fE086Ae8236323573D46FBA132f375253aCe842", - "version": "1.5.0" + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" }, "onRamp": { - "address": "0x6Be0c76c36EE77F5d2e0523a214CDCB132d71a19", + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" }, "supportedTokens": { - "YBTC.B": { + "savUSD": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -545,6 +417,18 @@ } } }, + "bitcoin-mainnet-bitlayer-1": { + "offRamp": { + "address": "0x0fE086Ae8236323573D46FBA132f375253aCe842", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6Be0c76c36EE77F5d2e0523a214CDCB132d71a19", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["YBTC.B"] + }, "bitcoin-mainnet-bob-1": { "offRamp": { "address": "0x8BD0E5EF01A26A6032B3813A35C7c867e58EDEbC", @@ -555,36 +439,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, "bsc-mainnet": { "offRamp": { @@ -596,134 +451,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "NXPC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BETS", "LBTC", "LEND", "NXPC", "SHIB", "SolvBTC", "YBTC.B", "savBTC", "xSolvBTC"] }, "core-mainnet": { "offRamp": { @@ -736,6 +464,17 @@ "version": "1.5.0" } }, + "corn-mainnet": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, "ethereum-mainnet-arbitrum-1": { "offRamp": { "address": "0x508Ea280D46E4796Ce0f1Acf8BEDa610c4238dB3", @@ -746,35 +485,100 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, + "supportedTokens": [ + "BETS", + "BOLD", + "GHO", + "GRT", + "LEND", + "SDY", + "SHIB", + "SILO", + "SolvBTC", + "USDC", + "USDM", + "VRTX", + "wstLINK", + "xSILO", + "xSolvBTC" + ] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x37879EBFCb807f8C397fCe2f42DC0F5329AD6823", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x139D4108C23e66745Eda4ab47c25C83494b7C14d", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BOLD", + "BYTES", + "GHO", + "GRT", + "LBTC", + "LEND", + "MYST", + "Memento", + "ORNG", + "SHIB", + "SolvBTC", + "USDC", + "USDM", + "VRTX", + "wstLINK", + "xSolvBTC" + ] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x43EDFd14D03911c3BddD891b27cb9Af3F8778E36", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x06d019530F1eECfd8B7fF2b3EaD54206aFb86A93", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["GHO", "SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": [ + "SolvBTC", + "avBTC", + "avETH", + "avETHx", + "avUSD", + "avUSDx", + "savBTC", + "savETH", + "savUSD", + "xSolvBTC" + ] + }, + "ethereum-mainnet-mantle-1": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "30000000000000000000000000", - "isEnabled": true, - "rate": "50000000000000000000000" - }, - "out": { - "capacity": "30000000000000000000000000", - "isEnabled": true, - "rate": "50000000000000000000000" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, "GHO": { "rateLimiterConfig": { "in": { @@ -789,63 +593,7 @@ } } }, - "GRT": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11574074070000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11574074070000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDY": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SILO": { + "VRTX": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -858,185 +606,158 @@ "rate": "0" } } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } } } }, - "ethereum-mainnet-base-1": { + "ethereum-mainnet-optimism-1": { "offRamp": { - "address": "0x37879EBFCb807f8C397fCe2f42DC0F5329AD6823", + "address": "0x376C0AFC9E64efE0d9202E1F02c3d7f9Dc15e404", "version": "1.5.0" }, "onRamp": { - "address": "0x139D4108C23e66745Eda4ab47c25C83494b7C14d", + "address": "0x3e3b4Fba004E7824219e79aE9f676d9D41A216Fa", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "BOLD", "USDC", "USDM"] + }, + "ethereum-mainnet-unichain-1": { + "offRamp": { + "address": "0xC58310a48ED7Ff45141658593a745ba1a0f1Fa39", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x7193D24891b578F3B18af824Cd3c97564D7a5486", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC"] + }, + "ethereum-mainnet-xlayer-1": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-zksync-1": { + "offRamp": { + "address": "0xD2396471B0bfd1C0F713897b3b58d9c040fcde13", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x70C395b29A495dE93713EECe4D60786C0d9dcf75", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDM"] + }, + "etherlink-mainnet": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "everclear-mainnet": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0xE5F21F43937199D4D57876A83077b3923F68EB76", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xe8784c29c583C52FA89144b9e5DD91Df2a1C2587", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BOLD", + "BONE", + "BYTES", + "EmCH", + "GHO", + "LBTC", + "LEASH", + "LEND", + "MYST", + "Memento", + "SDY", + "SHIB", + "SILO", + "SolvBTC", + "TREE", + "USDC", + "USDM", + "YBTC.B", + "avBTC", + "avETH", + "avETHx", + "avUSD", + "avUSDx", + "oXAUT", + "savBTC", + "savETH", + "savUSD", + "tETH", + "wstLINK", + "wstPOL", + "xSILO", + "xSolvBTC" + ] + }, + "matic-mainnet": { + "offRamp": { + "address": "0xFf49E35626Eba28Bee1d251782AB75A6cEd91c45", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x5570a4E979d7460F13b84075ACEF69FAc73914b1", "enforceOutOfOrder": false, "version": "1.5.0" }, + "supportedTokens": ["BETS", "LEND", "Memento", "SolvBTC", "USDC", "USDM", "wstLINK", "wstPOL", "xSolvBTC"] + }, + "megaeth-mainnet": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BYTES": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "GRT": { + "BTC.b": { "rateLimiterConfig": { "in": { - "capacity": "1000000000000000000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "11574074070000000000" + "rate": "462963" }, "out": { - "capacity": "1000000000000000000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "11574074070000000000" + "rate": "462963" } } }, @@ -1053,205 +774,116 @@ "rate": "462963" } } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "MYST": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "ORNG": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } } } }, - "ethereum-mainnet-ink-1": { + "monad-mainnet": { "offRamp": { - "address": "0x43EDFd14D03911c3BddD891b27cb9Af3F8778E36", + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "nexon-mainnet-henesys": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "plasma-mainnet": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["GHO", "savUSD"] + }, + "polygon-mainnet-katana": { + "offRamp": { + "address": "0x6E50242EeF22aaA4FcC6137201DB85273b67B320", "version": "1.5.0" }, "onRamp": { - "address": "0x06d019530F1eECfd8B7fF2b3EaD54206aFb86A93", + "address": "0xCc8E248FB013D9e426a5FBa75732431D0FC6a12f", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "supportedTokens": ["LBTC", "savUSD"] + }, + "sei-mainnet": { + "offRamp": { + "address": "0x519c045d8124Cd46Fc37A6982ffCc735fE70Be12", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x4Ea8D1cfe9e8645f8260AB4628A8aD8Db03056ec", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "VRTX"] + }, + "shibarium-mainnet": { + "offRamp": { + "address": "0xF1b0178BafAF72AE08B863e3eF4F2861401e6389", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x0F8a61187DC2021052873E5574e61Db00e03bAF5", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "ethereum-mainnet-linea-1": { + "solana-mainnet": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["USDC"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0xc8c3E45D29311a51D74D30Dd4019555D7ef59186", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xAfcb54F74C87DF80607a0c3Afc4168AdB0EcF18C", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BOLD", "LBTC", "SILO", "VRTX", "xSILO"] + }, + "stable-mainnet": { + "offRamp": { + "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "tac-mainnet": { "offRamp": { "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", "version": "1.6.0" @@ -1260,9 +892,57 @@ "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", "enforceOutOfOrder": false, "version": "1.6.0" + } + }, + "wemix-mainnet": { + "offRamp": { + "address": "0xFA5CF1bBFe0Ba5c01e60513EF8960945A99B78A4", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x1DA12512f852DAaba7883340A4074FfB73FA8f21", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["una.WEMIX"] + }, + "xdai-mainnet": { + "offRamp": { + "address": "0x1181A59FF0BAEd1E0EA77e919185cB8C3D5D3125", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x38fd0DF16F6fD0a2C3Ec6615c73e50F5d027b8bA", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["GHO"] + } + }, + "berachain-mainnet": { + "aptos-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "avalanche-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" }, "supportedTokens": { - "avETH": { + "savUSD": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -1275,25120 +955,594 @@ "rate": "0" } } - }, - "avETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } } } }, - "ethereum-mainnet-optimism-1": { + "bitcoin-mainnet-bob-1": { "offRamp": { - "address": "0x376C0AFC9E64efE0d9202E1F02c3d7f9Dc15e404", + "address": "0x63D80A193d03Dc976A9097aB37946E49c92150C4", "version": "1.5.0" }, "onRamp": { - "address": "0x3e3b4Fba004E7824219e79aE9f676d9D41A216Fa", + "address": "0x5A139535fCe136590FA39c83CD86E57282a19843", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } + "supportedTokens": ["SolvBTC", "SolvBTC.BERA", "xSolvBTC"] }, - "ethereum-mainnet-unichain-1": { + "bsc-mainnet": { "offRamp": { - "address": "0xC58310a48ED7Ff45141658593a745ba1a0f1Fa39", + "address": "0x77BBC3841A5c06Cc59378719c42ad1A7fe6157e3", "version": "1.5.0" }, "onRamp": { - "address": "0x7193D24891b578F3B18af824Cd3c97564D7a5486", + "address": "0x9519DEF016b11BBeFB617Fe128AaA67680a82A95", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BR", "SolvBTC", "SolvBTC.BERA", "beraBTC", "xSolvBTC"] }, - "ethereum-mainnet-xlayer-1": { + "corn-mainnet": { "offRamp": { - "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", "version": "1.6.0" }, "onRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", "enforceOutOfOrder": false, "version": "1.6.0" } }, - "ethereum-mainnet-zksync-1": { + "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "0xD2396471B0bfd1C0F713897b3b58d9c040fcde13", + "address": "0xc4045aDC60f8431621140Bc50c8014d82369d9B3", "version": "1.5.0" }, "onRamp": { - "address": "0x70C395b29A495dE93713EECe4D60786C0d9dcf75", + "address": "0x25Ec9d8D04A14093bC1B7C220Da86712A4Bd401a", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } + "supportedTokens": ["BOLD", "DOLO", "sDOLA"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x08C3932008456BF7B3ca7031AbF47A0E2a56CE2b", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x150EBAAe68aDFb2A5da849C248F95BF3Cf18f1f0", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BOLD", "BR", "sDOLA"] + }, + "ethereum-mainnet-worldchain-1": { + "offRamp": { + "address": "0x31Def7e6d1e16266eD9e1649ead9be7904c09305", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xd39A96B804Bd0DB9f04350D62e8b755C45e38896", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "everclear-mainnet": { + "etherlink-mainnet": { "offRamp": { - "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", "version": "1.6.0" }, "onRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", "enforceOutOfOrder": false, "version": "1.6.0" } }, + "hyperliquid-mainnet": { + "offRamp": { + "address": "0xfF327Ef3b73346f2AacD6ec02c70440D31fd8319", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x3423C922911956b1Ccbc2b5d4f38216a6f4299b4", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, "mainnet": { "offRamp": { - "address": "0xE5F21F43937199D4D57876A83077b3923F68EB76", + "address": "0x133e59ACf07728755440B0b0A7DC282EBcE04e31", "version": "1.5.0" }, "onRamp": { - "address": "0xe8784c29c583C52FA89144b9e5DD91Df2a1C2587", + "address": "0x2c99dC698745B655d4D0741eF5Ef8623578c45c0", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "avETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "avETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "30000000000000000000000000", - "isEnabled": true, - "rate": "50000000000000000000000" - }, - "out": { - "capacity": "30000000000000000000000000", - "isEnabled": true, - "rate": "50000000000000000000000" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BYTES": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "EmCH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "MYST": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "oXAUT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDY": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "tETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TREE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstPOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0xFf49E35626Eba28Bee1d251782AB75A6cEd91c45", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x5570a4E979d7460F13b84075ACEF69FAc73914b1", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "30000000000000000000000000", - "isEnabled": true, - "rate": "50000000000000000000000" - }, - "out": { - "capacity": "30000000000000000000000000", - "isEnabled": true, - "rate": "50000000000000000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstPOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "monad-mainnet": { - "offRamp": { - "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } - }, - "nexon-mainnet-henesys": { - "offRamp": { - "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "plasma-mainnet": { - "offRamp": { - "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "polygon-mainnet-katana": { - "offRamp": { - "address": "0x6E50242EeF22aaA4FcC6137201DB85273b67B320", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xCc8E248FB013D9e426a5FBa75732431D0FC6a12f", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "sei-mainnet": { - "offRamp": { - "address": "0x519c045d8124Cd46Fc37A6982ffCc735fE70Be12", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x4Ea8D1cfe9e8645f8260AB4628A8aD8Db03056ec", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "shibarium-mainnet": { - "offRamp": { - "address": "0xF1b0178BafAF72AE08B863e3eF4F2861401e6389", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x0F8a61187DC2021052873E5574e61Db00e03bAF5", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0xe72d25aDd538E8ef9CeF85622eA8912a6CB98Be6", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0xc8c3E45D29311a51D74D30Dd4019555D7ef59186", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xAfcb54F74C87DF80607a0c3Afc4168AdB0EcF18C", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "wemix-mainnet": { - "offRamp": { - "address": "0xFA5CF1bBFe0Ba5c01e60513EF8960945A99B78A4", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x1DA12512f852DAaba7883340A4074FfB73FA8f21", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } - } - }, - "xdai-mainnet": { - "offRamp": { - "address": "0x1181A59FF0BAEd1E0EA77e919185cB8C3D5D3125", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x38fd0DF16F6fD0a2C3Ec6615c73e50F5d027b8bA", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } - } - }, - "berachain-mainnet": { - "aptos-mainnet": { - "offRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - }, - "bitcoin-mainnet-bob-1": { - "offRamp": { - "address": "0x63D80A193d03Dc976A9097aB37946E49c92150C4", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x5A139535fCe136590FA39c83CD86E57282a19843", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0x77BBC3841A5c06Cc59378719c42ad1A7fe6157e3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9519DEF016b11BBeFB617Fe128AaA67680a82A95", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "beraBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0xc4045aDC60f8431621140Bc50c8014d82369d9B3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x25Ec9d8D04A14093bC1B7C220Da86712A4Bd401a", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOLO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x08C3932008456BF7B3ca7031AbF47A0E2a56CE2b", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x150EBAAe68aDFb2A5da849C248F95BF3Cf18f1f0", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "1000000000000000000", - "isEnabled": true, - "rate": "100000000000000000" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-worldchain-1": { - "offRamp": { - "address": "0x31Def7e6d1e16266eD9e1649ead9be7904c09305", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xd39A96B804Bd0DB9f04350D62e8b755C45e38896", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "hyperliquid-mainnet": { - "offRamp": { - "address": "0xfF327Ef3b73346f2AacD6ec02c70440D31fd8319", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x3423C922911956b1Ccbc2b5d4f38216a6f4299b4", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0x133e59ACf07728755440B0b0A7DC282EBcE04e31", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x2c99dC698745B655d4D0741eF5Ef8623578c45c0", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "1000000000000000000", - "isEnabled": true, - "rate": "100000000000000000" - } - } - }, - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "DOLO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "pufETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x32cBB0850DBD4AFc72dc8E7eC09fdfb527d3a507", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x8a3712bdcDD829e2B074F1424D1be2F3dFE2EAAC", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "sei-mainnet": { - "offRamp": { - "address": "0x6Da0E306a8AD7B59690bef0d22BB89262C227535", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x3f85FcD7C0fa9f70ceDA58121377B48E42b9A3E5", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - } - }, - "binance-smart-chain-mainnet-opbnb-1": { - "bsc-mainnet": { - "offRamp": { - "address": "0x97D090497861ab69fE637781232BCcf302497D17", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xbDD7a56aeF09C3E8a2Be3C20Bb8c8C054Ea87120", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "THE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0xe89eF171B45c318ee786941c96944CD162187E2A", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x47c94F8540F950B36f0C34Db6977Eb7ADFc8A50B", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "bitcoin-mainnet-bitlayer-1": { - "avalanche-mainnet": { - "offRamp": { - "address": "0x574Da74E87FB182dC96591a223700fA9965919e3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xF398585cDDEB7DD6a947DC394701F761c5F4d1BC", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0xD12F5Dc1a0526FfdBC32CbB174436aA7975a9e1b", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x818c49325b35A86b7B2AD1463c26cE85137fc86e", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0x31A9dc0559F0619275aa034470D464cde2210649", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9db257ae83968F10f6A50009587BdA2fCedFDd5A", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "50000000000", - "isEnabled": true, - "rate": "10000000" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "50000000000", - "isEnabled": true, - "rate": "10000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "18000000000000000000", - "isEnabled": true, - "rate": "5000000000000000" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "18000000000000000000", - "isEnabled": true, - "rate": "5000000000000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "plasma-mainnet": { - "offRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "plume-mainnet": { - "offRamp": { - "address": "0xB8BBE35C3A3cb402f62b4941Eb0D0a7684E101C6", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x95E55753C9b742Cc615E9F527f6FA7b957a92596", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - } - }, - "bitcoin-mainnet-bob-1": { - "avalanche-mainnet": { - "offRamp": { - "address": "0x90e25232A53898f13F9436703dc405b97cD69168", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xAE685F7EE3cc46bD82D379E3747d530ED45b3403", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "berachain-mainnet": { - "offRamp": { - "address": "0x02E8b0fcC265a5ff7659584cF7b46f6460ddb69C", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x4D128E2a1aa4770FE6aF57B9b70C5508d7f59842", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0xa0852f8949752e8d29e2B3883a77994026c30006", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x68EA343954ea576787243F239aE49Aa6ef6C3DBd", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.JUP": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "corn-mainnet": { - "offRamp": { - "address": "0xCb1eE88E522bBE90e5D59166cE794B3c0a472476", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xB4D095a57A7D91a8dA8Bdb928D1e17452125bdd7", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x1AE9FF15C2e678594CCeC6F79F1A33761eE7594a", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x48043178bdBD5A6DE2972440ca6c946F2Ba2c77A", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x14CeB5F5b5A78D9017AFf9ab262b0d6Ab7c4D419", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9b896C2ac58BC0e5606f3AB553dC7d49dab5642a", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-ink-1": { - "offRamp": { - "address": "0xc8C08F48B9C9d03B64AE7d44695c436Ec398a555", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x25c6de3917AE4B527552e76Af7cAE0BC5759299C", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0xF193db0E32048Ad5808616Dc31702E9F3439B1A8", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x75edD666a263DA7074c86F41797787b71DeA39Ad", - "enforceOutOfOrder": true, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-zksync-1": { - "offRamp": { - "address": "0xDd48df19774C82Dbbdd1d58990d23B7B2d92dBC8", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xc7a5Ac793527B36A798d420871B8B271200E6Ddc", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0xbD064591d0789e9d66DDa2f4432aCB78232dDE1A", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x00E64619Bb29f7E1d4E1CC9f21ecEA05189fd8ab", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x9ec62973052Fa97b218aBce0d953ce4aD09587cf", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x358E3847a9c21EbBFb22925B99DFA4f7DfADAD28", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "sei-mainnet": { - "offRamp": { - "address": "0xaABE2E880C2061FbCc6598521A3152003657883b", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xa2c757629a6A9832dB37A032dc92684a3d1Bb027", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "soneium-mainnet": { - "offRamp": { - "address": "0x5Caa8BdA53306D15C170B3a8fa59F9748C169Df2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xBF9789236E73085A81925a8B549CEdF7e2825131", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.JUP": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0x54992b4DB694d12FF413AEb530d87428C53DfB63", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x501AE86DA029F0D2D1788cdd824f943E0Bc8A38C", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - } - }, - "bitcoin-mainnet-botanix": { - "mainnet": { - "offRamp": { - "address": "0x9ec4DEB066a72BCd0DE1698d9C88277DdF6F94eF", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x44Db2B9ee78228b6d88ff89b8ebf99685ede2786", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - } - }, - "bitcoin-mainnet-bsquared-1": { - "bsc-mainnet": { - "offRamp": { - "address": "0xE6ef0aD5eC1eedD70416Ee00F108c494dF0bE0d6", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x79328C1247A3568C609C0e6cf8fa23aF5199F5b9", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "stBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0xaa8bA928903C08417f2F4FC21D1378d90A960BDe", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xB1C908A7CF6f5FB1ed18a73aD60ffF9CC8276eC1", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "11574" - } - } - } - } - }, - "soneium-mainnet": { - "offRamp": { - "address": "0x3f55F2fA9B0A7b927A094294eF14b85D0979DC83", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6F7EC920478A7d1d236282AeC7F1d1B3a1fAf49E", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "bitcoin-merlin-mainnet": { - "mainnet": { - "offRamp": { - "address": "0x894C22E2A9f243ee4788643642CdED439Cc868C2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x3D25ff4cBaf29373B9Ec1784Bb5C8DC5e15347D8", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "bittensor-mainnet": { - "bsc-mainnet": { - "offRamp": { - "address": "0x51a6150400ed9F0Ae240F5D1b15E3b45Fc4339C7", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x345Cc465BCB9a902B420320B8793C9A5d6064404", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x51a6150400ed9F0Ae240F5D1b15E3b45Fc4339C7", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x345Cc465BCB9a902B420320B8793C9A5d6064404", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0x51a6150400ed9F0Ae240F5D1b15E3b45Fc4339C7", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x345Cc465BCB9a902B420320B8793C9A5d6064404", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - } - }, - "bsc-mainnet": { - "0g-mainnet": { - "offRamp": { - "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "aptos-mainnet": { - "offRamp": { - "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "avalanche-mainnet": { - "offRamp": { - "address": "0xc69a550470bEbC5c3Be98A4C3dD26C6AdD90C64b", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x43F00dBf0Aa61A099c674A74FBdCb93786564950", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "NXPC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "berachain-mainnet": { - "offRamp": { - "address": "0xe7EcE831c683B4eCd01B895f7310b0bb17aD64ef", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x004405d927caD243358A270c2dD3D51c8303A390", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "beraBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "binance-smart-chain-mainnet-opbnb-1": { - "offRamp": { - "address": "0xA94106fd5c5be306c14Ccb8Ec9f2422bA24E4ea6", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x2e75695a0a580E120B387CCcADAf7FfdC217a427", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "THE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "bitcoin-mainnet-bitlayer-1": { - "offRamp": { - "address": "0xD7B436696b869e0C0241DC44d047F257504F7616", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x00A4234078f73FA9479A6ee14d4EEaCC9B8dcb9c", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "bitcoin-mainnet-bob-1": { - "offRamp": { - "address": "0x7B9739889617a87aB3DE8B5C70Bb549500F38645", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xa837B3076a8BBE7A3B1F98073E4F46B968042fbE", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.JUP": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bitcoin-mainnet-bsquared-1": { - "offRamp": { - "address": "0x8a564880a05e2C101Dd339CE7590e830193287A8", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x2f43fEFC5C7ec5Fff64eC5Cac96447Edb7d17993", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "stBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "bittensor-mainnet": { - "offRamp": { - "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x2A9C65afF39758CeAa24dBD1ACd1BeB3618e6780", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x5577c19bD183e39a007ce4CE236f1D91e9132D5c", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CKP": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "28000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "28000000000000000000" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LAND": { - "rateLimiterConfig": { - "in": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - }, - "out": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "RDP": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "580000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "580000000000000000" - } - } - }, - "SDT": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABLE": { - "rateLimiterConfig": { - "in": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - }, - "out": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - } - } - }, - "STBU": { - "rateLimiterConfig": { - "in": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDFI": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - } - } - }, - "VSN": { - "rateLimiterConfig": { - "in": { - "capacity": "82500000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - }, - "out": { - "capacity": "75000000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x133672C0F0067573254dd7C8C9818a37d6208610", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xdABb6De5eC48dd2fcF28ac85CbEFe3F19E03F1BD", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "$PAAL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BKN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "CHEX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SAS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SNOW": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "UNIO": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000000", - "isEnabled": true, - "rate": "13888880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000000", - "isEnabled": true, - "rate": "13888880000000000000000" - } - } - }, - "USDO": { - "rateLimiterConfig": { - "in": { - "capacity": "10500000000000000000000000", - "isEnabled": true, - "rate": "1160000000000000000000" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1160000000000000000000" - } - } - }, - "WHY": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-blast-1": { - "offRamp": { - "address": "0x38cA434FE65D540942A36c84FdFD4B7C7a9a4612", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x0b7Bfe549F26AF4B6aA5246CB3FD96C8a5c23a68", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-hashkey-1": { - "offRamp": { - "address": "0xc188c5Df59aec57cd7a29aDE2a2176fAbbf24b81", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xfE73ed7c00eD640C5991fa8e81Ec3fcA5f8E3cdd", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "enzoBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-ink-1": { - "offRamp": { - "address": "0x12CC5797a842347Dc2D4DAB2aFe22b07fc987E25", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x2Bac5BC6c0a073831a4cf6E0c996140B7A76F296", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0x0c42a007BF89DC2CAfAb3fbd2eC1C1cA5BFe7d7C", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x86768B77C971524D5042631749A59527E8a9604d", - "enforceOutOfOrder": true, - "version": "1.5.0" - }, - "supportedTokens": { - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "TURTLE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-mantle-1": { - "offRamp": { - "address": "0xd19C02763E1C67086fe6B74B7ced9ab9Da30c6A2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x94Cbb3011f87f0A14D19caaEc155D5985E58E259", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-mode-1": { - "offRamp": { - "address": "0xFc2278eBc27B9d205e3DC9F1b88D6D863D71190D", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9d4d125788A548C2f69fAC7f8C3A64FA21d18C9e", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0x3c5E62cdFD08e23a0961ff2A3155CaBb96cbc89D", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x3A3649852A518ab180f41f28288c6c9184563616", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "ethereum-mainnet-unichain-1": { - "offRamp": { - "address": "0x53Ad2747B52B81b4369DF29a2C6A0972a1bd65fb", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x95e84C23D5a5a6Ba24D3A2090E4B88d01F30f1a7", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-xlayer-1": { - "offRamp": { - "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-zksync-1": { - "offRamp": { - "address": "0x67b973aBfd440e33f421b6b157706534295572E7", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9D01e82068a9157976D8c794fbd74cAF395F5A37", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "hyperliquid-mainnet": { - "offRamp": { - "address": "0x50ceF176C2F39080b15Aa4E7f97f6BE6Fa28c5d1", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xfF327Ef3b73346f2AacD6ec02c70440D31fd8319", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0xF616733641D420207b8F30db9C4cE39684768991", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x35C724666ba31632A56Bad4390eb69f206ab60C7", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "$PAAL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "1XMM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BANK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BARD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BKN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "BTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CHEX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "EDEN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FF": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "mwBETH": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000", - "isEnabled": true, - "rate": "46000000000000000" - }, - "out": { - "capacity": "500000000000000000000", - "isEnabled": true, - "rate": "46000000000000000" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SAS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDT": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABLE": { - "rateLimiterConfig": { - "in": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - }, - "out": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - } - } - }, - "sUSD1+": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TREE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TURBO": { - "rateLimiterConfig": { - "in": { - "capacity": "7000000000000000000000000", - "isEnabled": true, - "rate": "1944444400000000000000" - }, - "out": { - "capacity": "7000000000000000000000000", - "isEnabled": true, - "rate": "1944444400000000000000" - } - } - }, - "TURTLE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "UNIO": { - "rateLimiterConfig": { - "in": { - "capacity": "15000000000000000000000000", - "isEnabled": true, - "rate": "520000000000000000000" - }, - "out": { - "capacity": "15000000000000000000000000", - "isEnabled": true, - "rate": "520000000000000000000" - } - } - }, - "USD0": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - } - } - }, - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDf": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDFI": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - } - } - }, - "USDO": { - "rateLimiterConfig": { - "in": { - "capacity": "10500000000000000000000000", - "isEnabled": true, - "rate": "1160000000000000000000" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1160000000000000000000" - } - } - }, - "USUAL": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - } - } - }, - "VOOI": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "VSN": { - "rateLimiterConfig": { - "in": { - "capacity": "82500000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - }, - "out": { - "capacity": "75000000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WHY": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WLFI": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "231500000" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "231500000" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x21159ebdA3E6A2437bCD6ef39853042ACC436D2D", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x1C88e3Fd2B0a8735D1b19A77AA6e2333555BB95c", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "1XMM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LAND": { - "rateLimiterConfig": { - "in": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - }, - "out": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "METO": { - "rateLimiterConfig": { - "in": { - "capacity": "76923077000000000000000000", - "isEnabled": true, - "rate": "21367520000000000000000" - }, - "out": { - "capacity": "76923077000000000000000000", - "isEnabled": true, - "rate": "21367520000000000000000" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "THE": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "417000000000000000000" - }, - "out": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "417000000000000000000" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "mind-mainnet": { - "offRamp": { - "address": "0x160E2CeaB31A5fdcC480506746D1d99fB626Cc5D", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x92884F00d64daf778e3A86173d364A184CA532F6", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "monad-mainnet": { - "offRamp": { - "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } - }, - "plume-mainnet": { - "offRamp": { - "address": "0xAdd62B3cB2D26cE5001784b050A83bB9F1a4fa7f", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xC2f4143E242D0BF0b490DC64D362136c1d068Fb1", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "polygon-mainnet-katana": { - "offRamp": { - "address": "0x1C07Ba64819728c9e48796F7514e1DBF92Ca4774", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x81e8503F5f45f1cBd16ca99c7739D69a07af7C0b", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "sei-mainnet": { - "offRamp": { - "address": "0xB3a0AFcEeb2F19A6f0682558f8B02309c8Be3cB3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x88998f02a6aCacc341fB378F6F5bf9acc0a6eDa3", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "5800000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "elizaOS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "ILMT": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000", - "isEnabled": true, - "rate": "277777777778" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "2777777777780000000000" - } - } - }, - "MEW": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000", - "isEnabled": true, - "rate": "34722" - }, - "out": { - "capacity": "7500000000000000000", - "isEnabled": true, - "rate": "347220000000000" - } - } - }, - "SolvBTC.JUP": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "57870" - }, - "out": { - "capacity": "50000000000000000000", - "isEnabled": true, - "rate": "578700000000000" - } - } - }, - "USELESS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WLFI": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "XLAB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "soneium-mainnet": { - "offRamp": { - "address": "0x39b8519F8871965DB784218DE0d6bcA3A03b2141", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x0390B87B43974b45e3fE21824A008A3cd46605De", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC.JUP": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "1157400000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "1157400000000000" - } - } - } - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0x1Bb241731Fce5A650934b594D9ee6cCE55E39f32", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xF54f6623f1E714985839ac451BFA8B34007487E0", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "tac-mainnet": { - "offRamp": { - "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "wemix-mainnet": { - "offRamp": { - "address": "0x512CA54a0F6447AC41c07Da3336DFcA042D88A7B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9BaFC5E78C0051c7Bcd1EF37FF02fcBd31B37a72", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } - } - }, - "xdai-mainnet": { - "offRamp": { - "address": "0x53AF5cE4534C39582E6a5E3fD77946E0c3BFe870", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x83AC865c2E18f2CDc1d10126987FfC465e11c0DF", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "celo-mainnet": { - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x3980b6e3d2f23AF4D700d12C42af1B92AB8ea933", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xf27b5D3205fEa8aD6Ce8Fbe3b6178867428E5732", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0xF1470F8944f5aA02892Bd621d8bD42F160CB96fd", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xD5cCB283797A708125C807C63a6E944a99EEd288", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "ethereum-mainnet-ink-1": { - "offRamp": { - "address": "0x8B6657F323f5dC8cDB896d08074eA7D31b794609", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x1b531048F438571d3CF6806e55957C361C0b2d75", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-mode-1": { - "offRamp": { - "address": "0xa39CFCB09Ca613ee9f6Fc03c8E0a79566a07b2eB", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x5dA58BF4a86b5B43f302D1Fea8A2DaaCe871A99A", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0xe21C99e57aF6C2B4768442c69445bD181aFCfee5", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x5Cc4b917DfD93E9833cC33BaA38A8B0091d5ade0", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "ethereum-mainnet-unichain-1": { - "offRamp": { - "address": "0x56D7a82869CBA0b3B4e2c7a18b54C705bd9aa0b1", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6cAa43a0D82614a95F8e7D30C358268f464D0B3c", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-worldchain-1": { - "offRamp": { - "address": "0x60dcBAC7CF502bC58524e81f6b558Dc514517f67", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xa841C3aD09133d1d2148b259fe1ceA3bbacbeed8", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-zksync-1": { - "offRamp": { - "address": "0x27f7Af25Ac7482d75207179B42906866A89C6787", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x7171AeF438a34427D255BF323C13416B6a1848F0", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0x1B12D218280DD1767304A00070101a91f7A61470", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xc319484eF6cdA3a7f4D470e660b343FB569e9A1e", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0xd04aF6aB899900D32299e2970457b90Ce8767759", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x42504890DD261Bf17Aa05Dca6C293a6c6225f961", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "soneium-mainnet": { - "offRamp": { - "address": "0x695aAbE79d26FdC309CcFBE594B15094b82CcFd6", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xB3C5D43d6114B99E5Bc79cC340C563DC44A4B2B2", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "core-mainnet": { - "avalanche-mainnet": { - "offRamp": { - "address": "0x35f6c6f50D937A5ec7A1CDe94C5ecaa2843A1E12", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x84500703E377FbfebC7eA8B4568F2156d48eB665", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0xC6C0530f9926B06199861ae6E1c45bCf7391b35E", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xe68e90Cb8c9e7b58c67f7447A45F0E63c5Af6d4a", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x584EA199994799a73F13eA8A2113050a1a96E0e1", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x79b875F8546788c1382EC09D3a22dfF9e50E8d36", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0xD95D3654bE8ae12E073e32F39cd8E9d9144d2Cc8", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xa206130E202592737A72c0C04b324aBC78Ca448E", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0xF0fC17a0cb867c9879d1f4Ea4C23E65D5f4fb890", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x00348860Cb152Aa20617a1265343D1989C976575", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0x093509d6316f347d7a21169F9fbe0A4eed549e1a", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xC2aa1372998A8Aa25DA50737AbFA2C154D6793d1", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "corn-mainnet": { - "bitcoin-mainnet-bob-1": { - "offRamp": { - "address": "0x4e1254caB1BB7a13663709Eb2a0F394054E5097F", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x250F8295A0d285100CD9f5467f8A54aE0b9e3c61", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0x4DC347bE828120E9b59ee45946DD2eFf55E20659", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x0883eC4F32CaDe330c56e51a9131F7443a0a576A", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x6Db08b8507351303236CcB47A4176735fda74f84", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xf01CD02A43DD06403c5316d3D5658B1f91b006B5", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "cronos-mainnet": { - "mainnet": { - "offRamp": { - "address": "0x305763f90CF335FAae061DA6341533D263B1876f", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x5873C4FfD8A3DdB610e5079cebA63a1C04340A29", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "cronos-zkevm-mainnet": { - "mainnet": { - "offRamp": { - "address": "0xe43D992336f286c9a4d6A9Cd9f65C89771cbC52f", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xf1D0D8f9309dD48Ce46110A474C11908e3B49EA3", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "ethereum-mainnet-andromeda-1": { - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0xc6bA5a79991b3775F28259BA551b30eCb0b6D499", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x8d3039fE2400151c06Ae84a18CAf38dD9b6Ce58b", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SDL": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - }, - "out": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0x1fd37Bf813D0723BEF614bC93d9D2Ce1AcB3228f", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xdF5394c57A0570ECe45DE0c0fA2e722A672B9198", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SDL": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - }, - "out": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - } - }, - "ethereum-mainnet-arbitrum-1": { - "0g-mainnet": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "apechain-mainnet": { - "offRamp": { - "address": "0x7c04e5396B774758847f408864c9389C18353275", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xDdb06a5c964d38C0AA2119ea7a805583565988d3", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "aptos-mainnet": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - }, - "avalanche-mainnet": { - "offRamp": { - "address": "0x95095007d5Cc3E7517A1A03c9e228adA5D0bc376", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xe80cC83B895ada027b722b78949b296Bd1fC5639", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "GRT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDY": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1000000000000000000000000" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1000000000000000000000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "berachain-mainnet": { - "offRamp": { - "address": "0xCCeEE160D37eFF0b476dcd8B167CCE9D54359C4b", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xa0792764166C891A1e8033fA6B2786d9a5B197d8", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOLO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "bitcoin-mainnet-bob-1": { - "offRamp": { - "address": "0x0c48652a01DFc023c081143A900555a481918929", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6C2B7ea87A7724f8F6A61217aDf3EaB3CfC13FA3", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0x16B9709F8A23B9EB922E8Dde7EaB1Ede7C79F663", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x14bF7b1Ca6b843f386bfDfa76BFd439919b9378D", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CKP": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "28000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "28000000000000000000" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LAND": { - "rateLimiterConfig": { - "in": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - }, - "out": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "RDP": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "580000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "580000000000000000" - } - } - }, - "SDT": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABLE": { - "rateLimiterConfig": { - "in": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - }, - "out": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - } - } - }, - "STBU": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - } - } - }, - "USDFI": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - } - } - }, - "VSN": { - "rateLimiterConfig": { - "in": { - "capacity": "82500000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - }, - "out": { - "capacity": "75000000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "celo-mainnet": { - "offRamp": { - "address": "0x0eA1070B08757Da69a0762ae38D037cdd08C5e98", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x68647D235262873Be5a30fceaA6CAA318a750773", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "core-mainnet": { - "offRamp": { - "address": "0x1fD156b5aD47627a32583037B11E567823612aE6", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x8315cb1be59c3fd8A66169F26461648Ba952a68c", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-andromeda-1": { - "offRamp": { - "address": "0xF1A4DE22FF792b0457306C39f4CB5822Ab47bdAE", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xF1e73c37CDa8E47768De2246AEf5eFD4d76330ae", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SDL": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - }, - "out": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0xb62178f8198905D0Fa6d640Bdb188E4E8143Ac4b", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xc1b6287A3292d6469F2D8545877E40A2f75CA9a6", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "APU": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DPI": { - "rateLimiterConfig": { - "in": { - "capacity": "741000000000000000000", - "isEnabled": true, - "rate": "50000000000000000" - }, - "out": { - "capacity": "741000000000000000000", - "isEnabled": true, - "rate": "50000000000000000" - } - } - }, - "dsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "13000000000000000000", - "isEnabled": true, - "rate": "900000000000000" - }, - "out": { - "capacity": "13000000000000000000", - "isEnabled": true, - "rate": "900000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - }, - "out": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "GRT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "hyETH": { - "rateLimiterConfig": { - "in": { - "capacity": "28000000000000000000", - "isEnabled": true, - "rate": "2000000000000000" - }, - "out": { - "capacity": "28000000000000000000", - "isEnabled": true, - "rate": "2000000000000000" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LDY": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "MVI": { - "rateLimiterConfig": { - "in": { - "capacity": "1111000000000000000000", - "isEnabled": true, - "rate": "80000000000000000" - }, - "out": { - "capacity": "1111000000000000000000", - "isEnabled": true, - "rate": "80000000000000000" - } - } - }, - "NUON": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "suBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - }, - "out": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - } - } - }, - "suETH": { - "rateLimiterConfig": { - "in": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - }, - "out": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - } - } - }, - "suUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - } - } - }, - "USD+": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - }, - "out": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - } - } - }, - "WHSK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "wOETH": { - "rateLimiterConfig": { - "in": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - }, - "out": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - } - } - }, - "WOLF": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "ethereum-mainnet-blast-1": { - "offRamp": { - "address": "0x40314FeC27C5FCc7AaA05e618802A3fEA8E23Ae3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xc5490997680a39A1b4684ce2b668AE8A2eBEC7ee", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - } - } - } - } - }, - "ethereum-mainnet-hashkey-1": { - "offRamp": { - "address": "0xd85F0a6c57f3c7BE205fbA48DC007eEf4b97514b", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xA560c1E9E74d4Cb6416e99D3F571A9D949047821", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "WHSK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-ink-1": { - "offRamp": { - "address": "0x3f1341710E680c95e9b3a0549FFaf9f492682F32", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xB1883c326458A304219037b7C77Ae2dbc061d034", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xrETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xRPL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-mantle-1": { - "offRamp": { - "address": "0xE62f2AE9ceCbc6688a24602386f6B8FE5336b634", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x8A59Fa6a8ee352E0D0d27B7076C5132f9a34BD00", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - } - } - } - } - }, - "ethereum-mainnet-mode-1": { - "offRamp": { - "address": "0xa964355d8eBa62E9b043Eb27eEe6d999Ecc69429", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xd236ea4DDE7de1e594021764E2f6Cd8e8cD7F047", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0x27a971D482335d0f8d1917451390734f7372A4a3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xAFECc7b67c6a8e606e94ce4e2F70D83C2206C2cb", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "MILO": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "115740000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "115740000000000000000" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SD": { - "rateLimiterConfig": { - "in": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - }, - "out": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "ethereum-mainnet-unichain-1": { - "offRamp": { - "address": "0xbDa25A2450B1295564E8F46aeCe841005CBe2C8A", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x2FBb50dF814A22cb86357C443690CA59965383B5", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-xlayer-1": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-zircuit-1": { - "offRamp": { - "address": "0x858D6988b8A98abC4385d7DeeDa04A7227365cdE", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6E2b1bC5C6E1FcD15D83302E2d49e6Ba478FE0fF", - "enforceOutOfOrder": true, - "version": "1.5.0" - }, - "supportedTokens": { - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - } - } - }, - "ethereum-mainnet-zksync-1": { - "offRamp": { - "address": "0x052CF0c46375287255c71B179b10a7BFFD97502F", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xd67F6713Fa4448548c984a9a7DCFBD13B0fB78D6", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } - }, - "everclear-mainnet": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0x91e46cc5590A4B9182e47f40006140A7077Dec31", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x67761742ac8A21Ec4D76CA18cbd701e5A6F3Bef3", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "APU": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DFX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOLO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DPI": { - "rateLimiterConfig": { - "in": { - "capacity": "2593000000000000000000", - "isEnabled": true, - "rate": "180000000000000000" - }, - "out": { - "capacity": "2593000000000000000000", - "isEnabled": true, - "rate": "180000000000000000" - } - } - }, - "dsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "25000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - }, - "out": { - "capacity": "25000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - }, - "out": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - } - } - }, - "egETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "ETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "56000000000000000" - }, - "out": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "56000000000000000" - } - } - }, - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "hyETH": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000", - "isEnabled": true, - "rate": "34700000000000000" - }, - "out": { - "capacity": "500000000000000000000", - "isEnabled": true, - "rate": "34700000000000000" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LDY": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "mDLP": { - "rateLimiterConfig": { - "in": { - "capacity": "416000000000000000000000", - "isEnabled": true, - "rate": "4810000000000000000" - }, - "out": { - "capacity": "416000000000000000000000", - "isEnabled": true, - "rate": "4810000000000000000" - } - } - }, - "mmETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "mstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "mswETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "MVI": { - "rateLimiterConfig": { - "in": { - "capacity": "3333000000000000000000", - "isEnabled": true, - "rate": "230000000000000000" - }, - "out": { - "capacity": "3333000000000000000000", - "isEnabled": true, - "rate": "230000000000000000" - } - } - }, - "NPC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "NUON": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "pufETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SD": { - "rateLimiterConfig": { - "in": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - }, - "out": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - } - } - }, - "SDL": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - }, - "out": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDT": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "SDY": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABLE": { - "rateLimiterConfig": { - "in": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - }, - "out": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - } - } - }, - "STBU": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "suBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - }, - "out": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - } - } - }, - "suETH": { - "rateLimiterConfig": { - "in": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - }, - "out": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - } - } - }, - "suUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "tETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USD+": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - }, - "out": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDFI": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "VSN": { - "rateLimiterConfig": { - "in": { - "capacity": "82500000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - }, - "out": { - "capacity": "75000000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100830000000000000000", - "isEnabled": true, - "rate": "28008333333333333" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208333333333333" - } - } - }, - "WFRAGSOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "231500000" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "231500000" - } - } - }, - "wOETH": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000", - "isEnabled": true, - "rate": "417000000000000000" - }, - "out": { - "capacity": "1500000000000000000000", - "isEnabled": true, - "rate": "417000000000000000" - } - } - }, - "WOLF": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "15000000000000000000000", - "isEnabled": true, - "rate": "4000000000000000000" - }, - "out": { - "capacity": "15000000000000000000000", - "isEnabled": true, - "rate": "4000000000000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xrETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xRPL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0xcabc2D71dC3172a154A5A34cD706B050e0ef9b6f", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6087d6C33946670232DF09Fe93eECbaEa3D6864d", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DFX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27778000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27778000000000000000000" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LAND": { - "rateLimiterConfig": { - "in": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - }, - "out": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STBU": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "mind-mainnet": { - "offRamp": { - "address": "0xa424E1662ba9fE03b14425287F055D2809e4fd1e", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x12a4b20D69FAe9b55CD5FA20D5f1DBede1D623F3", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "monad-mainnet": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "plasma-mainnet": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } - }, - "sei-mainnet": { - "offRamp": { - "address": "0x017513A8cA43992938e7FA72033Ee29A0E2C029e", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x080a40d9265Cc00604c9759a77fe1B3D67800eb8", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "shibarium-mainnet": { - "offRamp": { - "address": "0xF9b99cD977e97634C61565b13DFf07e06c962236", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xFCdca0011177138b2d9Fd4dE874F2a14d25E6b7D", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787037037037037037" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787037037037037037" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WFRAGSOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - } - } - }, - "soneium-mainnet": { - "offRamp": { - "address": "0xbdda3e069dA6D2D47fe66445AeadBb81fEfaC5d2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xbB7c7AAf81D359C9367d31eDFDBF6C2Af73F17F6", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0xf88166dB9E9B7c59068f2dC9bD5d53A719a41e68", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6cb060f7f8b0F8C58A4032C82dCf917c6d438f46", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1000000000000000000000000" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1000000000000000000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "wemix-mainnet": { - "offRamp": { - "address": "0x893c14bA328A49336a188F972f997C0d7286B8E4", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x52e51f245e600C6A87Ef2090d607D2a0eAedA1a6", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } - } - }, - "xdai-mainnet": { - "offRamp": { - "address": "0xeE53872d1C695933B34cE0a11B58613CBBf37e20", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xc7d6B885d8A4286E6311F79227430b7862311cd3", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "0g-mainnet": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "apechain-mainnet": { - "offRamp": { - "address": "0x03EE839151E48CEE69f5e4e8D28B35CE2Eae0446", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x88cED349C02630b073D9879d30F79D6eD56B9268", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "aptos-mainnet": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - } - } - }, - "avalanche-mainnet": { - "offRamp": { - "address": "0x61C3f6d72c80A3D1790b213c4cB58c3d4aaFccDF", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x4be6E0F97EA849FF80773af7a317356E6c646FD7", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BYTES": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "GRT": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11574074070000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11574074070000000000" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "MYST": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "ORNG": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "berachain-mainnet": { - "offRamp": { - "address": "0x5204a4c69E0551fFd6376C3558efF24f7ecD1af1", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x048F2f9961A93bB87cD5B35a01088343aA85c332", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "1000000000000000000", - "isEnabled": true, - "rate": "100000000000000000" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "bitcoin-mainnet-bob-1": { - "offRamp": { - "address": "0xc18eF0E347cAB790dEBb3BB746511983039F72b6", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xEA20366b66C1FD262Eb600Cb4C721C39AC5D2C68", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bittensor-mainnet": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0x45d524b6Fe99C005C52C65c578dc0e02d9751083", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xE5FD5A0ec3657Ad58E875518e73F6264E00Eb754", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "$PAAL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BKN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "CHEX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SAS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SNOW": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "UNIO": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000000", - "isEnabled": true, - "rate": "13888880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000000", - "isEnabled": true, - "rate": "13888880000000000000000" - } - } - }, - "USDO": { - "rateLimiterConfig": { - "in": { - "capacity": "10500000000000000000000000", - "isEnabled": true, - "rate": "1160000000000000000000" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1160000000000000000000" - } - } - }, - "WHY": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "celo-mainnet": { - "offRamp": { - "address": "0x73A600F80061627dcC68ABc4f33063eB51aA6e96", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xf2Bf69d4A687d2c38DE865eABD611648dAccad93", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "core-mainnet": { - "offRamp": { - "address": "0x260aC27e82166e57e887A497Bb22f829bc90Da7E", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x75d1A886eCc7404321851f6A5B1f936269f044D6", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x7D38c6363d5E4DFD500a691Bc34878b383F58d93", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9D0ffA76C7F82C34Be313b5bFc6d42A72dA8CA69", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "APU": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DPI": { - "rateLimiterConfig": { - "in": { - "capacity": "741000000000000000000", - "isEnabled": true, - "rate": "50000000000000000" - }, - "out": { - "capacity": "741000000000000000000", - "isEnabled": true, - "rate": "50000000000000000" - } - } - }, - "dsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "13000000000000000000", - "isEnabled": true, - "rate": "900000000000000" - }, - "out": { - "capacity": "13000000000000000000", - "isEnabled": true, - "rate": "900000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - }, - "out": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "GRT": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11574074070000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11574074070000000000" - } - } - }, - "hyETH": { - "rateLimiterConfig": { - "in": { - "capacity": "28000000000000000000", - "isEnabled": true, - "rate": "2000000000000000" - }, - "out": { - "capacity": "28000000000000000000", - "isEnabled": true, - "rate": "2000000000000000" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LDY": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "MVI": { - "rateLimiterConfig": { - "in": { - "capacity": "1111000000000000000000", - "isEnabled": true, - "rate": "80000000000000000" - }, - "out": { - "capacity": "1111000000000000000000", - "isEnabled": true, - "rate": "80000000000000000" - } - } - }, - "NUON": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "suBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - }, - "out": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - } - } - }, - "suETH": { - "rateLimiterConfig": { - "in": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - }, - "out": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - } - } - }, - "suUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - } - } - }, - "USD+": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - }, - "out": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - } - } - }, - "WHSK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "wOETH": { - "rateLimiterConfig": { - "in": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - }, - "out": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - } - } - }, - "WOLF": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "ethereum-mainnet-blast-1": { - "offRamp": { - "address": "0x941F0E2E0556aCf60fE0f09972f599d9F8916F01", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9A59832b85217C20b17a990A45BD5d0F3de36266", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - } - } - } - } - }, - "ethereum-mainnet-hashkey-1": { - "offRamp": { - "address": "0xD3680ae2d6b8373C01114D20e2109C3DC657913E", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x588990D1A7a54d23Aa1c2586CB9D6F053814A285", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "WHSK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-ink-1": { - "offRamp": { - "address": "0x53aB03801579793B31eDD3Afc16fc9A25EdDfdAb", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xbe6B55A0D720c4106bfca7beA3908a77ce3C31A2", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-mode-1": { - "offRamp": { - "address": "0x639Dc04368006544eba7CbC959f3e4361bfEAB0d", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xEB50Fc6F57AAc6bf060A2Dfc6479fED592e6e184", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BMX": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27770000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27770000000000000000" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0x18095fbD53184A50C2BB3929a6c62Ca328732062", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x362E6bE957c18e268ad91046CA6b47EB09AD98C1", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CRTV": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "ethereum-mainnet-scroll-1": { - "offRamp": { - "address": "0xAA2805A3B6Fc019B2F00E00F09b42e7273cD18E9", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xc06dc9FA031F7EaCcB08285aAA632730dD700Ce5", - "enforceOutOfOrder": true, - "version": "1.5.0" - } - }, - "ethereum-mainnet-unichain-1": { - "offRamp": { - "address": "0xe4E567386E8DC83E81763466B1d0eC4E1b97a4D7", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x1c179c2C67953478966A6b460AB4873585b2F341", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-xlayer-1": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-zksync-1": { - "offRamp": { - "address": "0x90e04B0871Ba9781DcD869251B7a6A101d08f13D", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x757DaD0B4017fca8E3399B4B3b23e0a6587723D1", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } - }, - "everclear-mainnet": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "hyperliquid-mainnet": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0xCA04169671A81E4fB8768cfaD46c347ae65371F1", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x56b30A0Dcd8dc87Ec08b80FA09502bAB801fa78e", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "$PAAL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "APU": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BKN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "1000000000000000000", - "isEnabled": true, - "rate": "100000000000000000" - } - } - }, - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "BYTES": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CHEX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DIP": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "2778000000000000000000" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "2778000000000000000000" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DPI": { - "rateLimiterConfig": { - "in": { - "capacity": "741000000000000000000", - "isEnabled": true, - "rate": "50000000000000000" - }, - "out": { - "capacity": "741000000000000000000", - "isEnabled": true, - "rate": "50000000000000000" - } - } - }, - "dsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "13000000000000000000", - "isEnabled": true, - "rate": "900000000000000" - }, - "out": { - "capacity": "13000000000000000000", - "isEnabled": true, - "rate": "900000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - }, - "out": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - } - } - }, - "GEN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "hyETH": { - "rateLimiterConfig": { - "in": { - "capacity": "28000000000000000000", - "isEnabled": true, - "rate": "2000000000000000" - }, - "out": { - "capacity": "28000000000000000000", - "isEnabled": true, - "rate": "2000000000000000" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "JASMY": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "1388888800000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "1388888800000000000000" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LDY": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "LsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "MEEM": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "2780000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "2780000000000000000" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "MVI": { - "rateLimiterConfig": { - "in": { - "capacity": "1111000000000000000000", - "isEnabled": true, - "rate": "80000000000000000" - }, - "out": { - "capacity": "1111000000000000000000", - "isEnabled": true, - "rate": "80000000000000000" - } - } - }, - "MYST": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "NEIRO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "NUON": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "oXAUT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SAS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABUL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "suBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - }, - "out": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - } - } - }, - "suETH": { - "rateLimiterConfig": { - "in": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - }, - "out": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - } - } - }, - "suUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - } - } - }, - "SXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "tETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "UNIO": { - "rateLimiterConfig": { - "in": { - "capacity": "15000000000000000000000000", - "isEnabled": true, - "rate": "520000000000000000000" - }, - "out": { - "capacity": "15000000000000000000000000", - "isEnabled": true, - "rate": "520000000000000000000" - } - } - }, - "USD+": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - }, - "out": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - } - } - }, - "USD0": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "USDO": { - "rateLimiterConfig": { - "in": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870400000000000000" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "USUAL": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100830000000000000000", - "isEnabled": true, - "rate": "28008333333333333" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208333333333333" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "wOETH": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "277800000000000000" - }, - "out": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "277800000000000000" - } - } - }, - "WOLF": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "XSWAP": { - "rateLimiterConfig": { - "in": { - "capacity": "20000000000000000000000000", - "isEnabled": true, - "rate": "463000000000000000000" - }, - "out": { - "capacity": "20000000000000000000000000", - "isEnabled": true, - "rate": "463000000000000000000" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - }, - "ZeUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x74d574D11977fC8D40f8590C419504cbE178ADB7", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xd3Bde678BB706Cf727A512515C254BcF021dD203", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BYTES": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CRTV": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27778000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27778000000000000000000" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LYP": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "83333333333300000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "83333333333300000000" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABUL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "XTFBRICK1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "XTFCLOBOND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "memento-mainnet": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "XTFBRICK1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "XTFCLOBOND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "monad-mainnet": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } - }, - "plasma-mainnet": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } - }, - "polygon-mainnet-katana": { - "offRamp": { - "address": "0xeFf089F24BAEd3F84918b6dDb265620B97247D9D", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x7898d0B2EDCF7a79969e2868A708109eB4dB287E", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } - }, - "ronin-mainnet": { - "offRamp": { - "address": "0x0A44Db4366385483cbCc9460fA55a75345553286", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x5dE068a87f081Ea01932769807CA569265E4f622", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - } - } - }, - "sei-mainnet": { - "offRamp": { - "address": "0x6D1EeF3Dfb4e8B6df481a52C8657246942aE1Da9", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xbd852E81D7425c00dA09b2181beC99703b1a27db", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "shibarium-mainnet": { - "offRamp": { - "address": "0x25f8Fc7a0917ea9Bbf72205B18F4f285d2bf1504", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xAC58a3a17D61B5D8233d73300A694F5D7A20Df4B", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "CANNED": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CHIKA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DAMN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FEED": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LUISA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "NEKO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SAS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIPA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SNOW": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USAGI": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WOW": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "elizaOS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787037037037037037" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787037037037037037" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000", - "isEnabled": true, - "rate": "13880000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "MEW": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - } - } - }, - "MICHI": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "78722220" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "78722220" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "YNE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - } - } - }, - "soneium-mainnet": { - "offRamp": { - "address": "0xd8Fc838D5a50F9b56a1c01bb4b78c9945eEC2926", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xD531E3424CED77fE86C78F046508125cA6786D26", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0x9c32DfE3237d280Dc703Ee8D42aae379b7BDea73", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xBc8e6602aEa1FE65Dc5656b77360ddAbBB52f894", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BMX": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27770000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27770000000000000000" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - } - } - }, - "wemix-mainnet": { - "offRamp": { - "address": "0x9001D632834FAf4c6ce717c5CcAd7e0c4b0803c0", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x5D519191f0BC6aC6d8497B41113551d79Aa65c9C", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "xdai-mainnet": { - "offRamp": { - "address": "0x300977dBA924af14E166B31F4926892B1f310661", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xDcFB24AEbcB9Edfb6746a045DDcae402381F984B", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } - } - }, - "ethereum-mainnet-blast-1": { - "bsc-mainnet": { - "offRamp": { - "address": "0x9A9f3714b517231869b97F3b49E2ba1009499d9b", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x01D1A2Ed2053e410177f8E762aF635ee78b7a581", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x8e4E966a3f6b3aB56185800a2afFe75CCf7B4DfD", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x28f7E57cEE31241B4B8B72e6b710c4dC2e9bEb28", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x5837622b622D3c88Faf5491324575f5c0BB40001", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xAbBC1fC0C919ecFb0220e90749111e0619abf79A", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57870000000000000000" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0xFf094AC08B0AA8Ab3d29e034a51199a0ddE3d8C8", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xEa8112530cA10945C2aA976f8F615582Af9B70fa", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - } - }, - "ethereum-mainnet-hashkey-1": { - "bsc-mainnet": { - "offRamp": { - "address": "0xf6E4Ac1362Cdce9DcbE3174436c1d99a0D9DFF8D", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x3eDDAE2d5169e38c45975fBe994c428C3728B915", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "enzoBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x88C4cBeF7685d3bfB68322e85135D14EdD41Be7B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xcd204E694a12488040d83d34D6c1e2b0E9495fDC", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "WHSK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x41c5362418f5629EA3E5c333FD569D64000CdE65", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x13484FB069f074A1584De1724c5c17A94BfD2aa3", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "WHSK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0x83abF9471d636EcB84643b89247546B18C33C6B8", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xb69B49A21f88cCc572684D2a574d7EE8B18C868e", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0xDd31064764B7683Fc38e13759B8050b6c59528d1", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x66e8c5D59E77eEBd8289D5BB76222F04f571BC67", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - } - }, - "ethereum-mainnet-ink-1": { - "aptos-mainnet": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - }, - "avalanche-mainnet": { - "offRamp": { - "address": "0xC44E893cEf294Eff9e56430ceE5C4C0f53a92584", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9411f7e2DBb687F304d95684476744dA79D9bfF2", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bitcoin-mainnet-bob-1": { - "offRamp": { - "address": "0xc9b80FB78375B1571cb517168B68dDEfF45A888A", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xD92bcA767B5EbdF91FE6aF2c6A25B6Fb584BAC9F", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0xdD86Db1e3D27b06aDbF4C449fB66c6ac3C79d74B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x363788B5d323c57fa7469BE8FBbB99e554731e52", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "celo-mainnet": { - "offRamp": { - "address": "0x92329665dD07F897fe1cc38d20e1a86FD6394f23", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6314dFcF1430aF590e388Cb77D963c23406553f6", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x74946257b64f72Ae1126cBBE3cDBB539616FBfA1", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x61F512c264e297E9Cc1517DCfF51ef193c055060", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0xfc960D01fD45A396E7874383580fDe1E3c726490", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x271315a46CD922C6977aC91ba425ed421279B783", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-xlayer-1": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-zksync-1": { - "offRamp": { - "address": "0xeF4D86b49b83Bd2A41CD54ef019A066BB5ADe4D2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xEa54FBd030CbA34a3939d77F3060cA09d1D5e7D8", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0x809E132A7C3A689a7026971be32697B6cD507f63", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x288Ad43143e135C4e350B23162c538E83fF1FCF5", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - }, - "out": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x5b429dEF74a08688C43DFC36F3af703CE265Dd4a", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x022A5Caf1F0437aDE29b28c53D82F6Ad103B323d", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "plasma-mainnet": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - }, - "out": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - } - } - } - } - }, - "sei-mainnet": { - "offRamp": { - "address": "0x496D74c0E33325f370167bF1A4767cbBd9A6a1D3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x77247cB0da96BC02BBb19dD9cAe1505349738b88", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "soneium-mainnet": { - "offRamp": { - "address": "0xCb4bD34201c7306fCA4cC791Ae21a6EE94bF88A2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x1986e0583709e978811b434Ac00ca806529E8D5b", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0x55dfEB67b429A4073b27c49C3Ed7916fbeEF6E4B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9da03ab4d9D126cDCC83fbb84cD2197776302D35", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "xdai-mainnet": { - "offRamp": { - "address": "0xc20FF92f9E5F283192DAc1C19cd66f58eF0525D1", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x94d035286419C98874dCE62B79C077D91716B7c7", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } - } - }, - "ethereum-mainnet-linea-1": { - "aptos-mainnet": { - "offRamp": { - "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - }, - "avalanche-mainnet": { - "offRamp": { - "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "avETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "avETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bitcoin-mainnet-bob-1": { - "offRamp": { - "address": "0x62a61c033c0d86DCd3A14791afcace022eB54471", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x078BDD1462D6418b2b432Ba190531b3AC89EC6eC", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0xa7e7cb9185Ff4A17f54fEDeD3eeb8d09935a879d", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xd0F398854358f8846596C78f8363F3d182e77cC8", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "TURTLE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xrETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xRPL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-ink-1": { - "offRamp": { - "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0x26d57442604D1b2A2196f8c93E6E72BB7FAF93Bd", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xF4F5ddc54aAe8d2489F9Fe82060e44020A152200", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-scroll-1": { - "offRamp": { - "address": "0xa3Ea5eB15711041fd28950438b5a682392b54e6C", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x30ebb71dAa827bEAE71EE325A77Ca47dAED7Ec9B", - "enforceOutOfOrder": true, - "version": "1.5.0" - } - }, - "ethereum-mainnet-xlayer-1": { - "offRamp": { - "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-zircuit-1": { - "offRamp": { - "address": "0xd2803dDE6B53d4F637B2C47F2a27f01Ec299963b", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x0d222d900969e7058Be60318f8A99502560Ed560", - "enforceOutOfOrder": true, - "version": "1.5.0" - }, - "supportedTokens": { - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0x656e2aA127Cb15815a90Ef70c6AA7Ed449D689ce", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x69AbB6043BBEA2467f41CCD0144d1b3b4ECd20f4", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "avETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "avETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "TURTLE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "33300000000000000000", - "isEnabled": true, - "rate": "9250000000000000" - }, - "out": { - "capacity": "30000000000000000000", - "isEnabled": true, - "rate": "8333333333333333" - } - } - }, - "xrETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xRPL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x7990fc4f985520Aa6A2e70C4F0f4583f753eeFf2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x3B89e864ea4b075D36409fE0d3f507afA6198A1d", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "plasma-mainnet": { - "offRamp": { - "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "xdai-mainnet": { - "offRamp": { - "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - } - }, - "ethereum-mainnet-mantle-1": { - "bsc-mainnet": { - "offRamp": { - "address": "0x7dA0421bedd25eb7CbA7eFdB6108Bfc2916De79e", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xB608c110c35f2871c0e1ED30DA1848603bC18694", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x86e769Df2f545d45847D8dA81DA4a25265813d13", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6B074861f43077e537972cc55f0e986849A46095", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0xfFdAbD352FdA50faF773503fe8BF265dFA9f7A01", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xa18BC8b64a863DB34199F7e59F3A3d051ABa413d", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "11574" - } - } - } - } - } - }, - "ethereum-mainnet-mode-1": { - "bsc-mainnet": { - "offRamp": { - "address": "0xdfA601DA2163Ca2C77Eb32126E6B7A97024f6181", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xeb7E8c40E95Cd31666359AaeB1F2CccaAB935643", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "celo-mainnet": { - "offRamp": { - "address": "0xB8A51Bff88c09Aa1a66A7874110FDe970e6cA9A5", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xf81c7385064bBB58a01004E1eEC4D9B0785AECa7", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x0Cb870C12013c2d5743585F85b298e129cE57203", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xb2e694efcDa0aeB81700019c3047F92fC3bb520E", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x30612D8fb7EcD05ECb863560BA8806d88e8BbFAF", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x347A070EA1B04bc2b4A8f14320688C277022C90e", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BMX": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27770000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27770000000000000000" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0x4adcD1FB4ec76A3c9960E048f81C19A51B2eAC49", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x7AB4329D19A0255DA90Ee8dbAA60f8f0cB7950C1", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0xb1caBa234721b8F12C545B3dC25B3F87f6a9c91B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x7d2aF78868993a5a86676BA639eC0412709707D9", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "sDAI": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "69400000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "69400000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0x411ce3551a5be63c3Cb30374Cee336c3b3F84111", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xD5Fa7faca37be1644f88bB17A0E4f0df12279339", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BMX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "aptos-mainnet": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - }, - "avalanche-mainnet": { - "offRamp": { - "address": "0xF8E38B4503418659F791F2135c4912F85BFB7988", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xB9D655Ad5ba80036725d6c753Fa6AF0454cBF630", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0x51f37b538aD2Bcb9Eaf884859BF7C5Ec58AEc885", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xfC51a4CF925f202d86c6092cda879689d2C17201", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "celo-mainnet": { - "offRamp": { - "address": "0xa6ed91b1708fA53895f9b0d7C1435625f1B3C440", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x746ddB61Af7B1516B819F6d81AcD729e4C867a55", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "core-mainnet": { - "offRamp": { - "address": "0xf83EEDD718629e7EC76EccfA8e861E2316930CFa", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x16F9Be2317C358E0b21EF09da8AB1EBCEf298D1B", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0xEB3d6956BCf7b1E29634C8cd182fC9FA740Bce34", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6bA81b83091A23e8F2AA173B2b939fAf9E320DfB", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "MILO": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "115740000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "115740000000000000000" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SD": { - "rateLimiterConfig": { - "in": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - }, - "out": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x519ee6B83f57df95486aeA6E26819cb7b4B8ee99", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xfE11cfC957cCa331192EAC60040b442303CcA0a9", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CRTV": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208330000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "ethereum-mainnet-hashkey-1": { - "offRamp": { - "address": "0xE12102b65CBC13966116cB6Edbd257F967B5c56B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xc404E8e7d26569bEC0e23e4868187f1024494AD7", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0xa3a854E5942273b59A8aba07e929F8a0fbd18447", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x4AE52fD7Eae88fAcD86A3F16C063AB59941a2eeE", - "enforceOutOfOrder": true, - "version": "1.5.0" - }, - "supportedTokens": { - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-mode-1": { - "offRamp": { - "address": "0x5a4BEeafd345264360E6894a6bc5F54a70814E68", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xc6d9Cb39e34D83d21A021504024887A0e96D4e94", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "ethereum-mainnet-unichain-1": { - "offRamp": { - "address": "0xe4770Ce5024f19e76D995cE3b1e7d03aD9540E73", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x80e396e5447805432695eb551B7C9283408aa51A", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-zircuit-1": { - "offRamp": { - "address": "0xccc197F0e5eF2e399F5b9Ab35cc3EA58F15Fd6BA", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xE85fc09997Da4E08Ef7466E7819b2d9477fca035", - "enforceOutOfOrder": true, - "version": "1.5.0" - }, - "supportedTokens": { - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-zksync-1": { - "offRamp": { - "address": "0x8d86CEDE37C93CD48C5d146aaF03f750714Fe127", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x793Aa8C07195C6a07F75C5cbDF17070564e69499", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0x9979c2dfEcA9051Cf7f08274d978984B2dB12C60", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xE4C51Dc01A4E0aB14c7a7a2ed1655E9CF8A3E698", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "ETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "56000000000000000" - }, - "out": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "56000000000000000" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SD": { - "rateLimiterConfig": { - "in": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - }, - "out": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "11574" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100830000000000000000", - "isEnabled": true, - "rate": "28008333333333333" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208333333333333" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x4BA0A3bD1E2b70b2fe165A53219e7eF6376849a4", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9c725164b60E3f6d4d5b7A2841C63E9FD0988805", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CRTV": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } - }, - "monad-mainnet": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "sei-mainnet": { - "offRamp": { - "address": "0x3d6b220C9e3498b9062716339599b741F9c3D1E2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xC5d7B7806ace4590655D14fC503079e4956Bc243", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "shibarium-mainnet": { - "offRamp": { - "address": "0xBe811105E3BAc916F339E3079F687e2BFe72E51d", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x7f2340EAFC71bd92cb99638Fd55032BdB31d9300", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0xd2e7b4e9dA1a969C160524Ca27E4AdB5d26e36d0", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xED13113a043C823d550d2505aa9a97e40766Dc49", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "wemix-mainnet": { - "offRamp": { - "address": "0x2f40dCCb74d8B2dd7af065232a06778f2D019375", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6Dbc8D4e5556FD0B82bB0D67c94D0fA1cd288AbD", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } - } - }, - "xdai-mainnet": { - "offRamp": { - "address": "0x01449040D92D75c58FaDc9Bc1c0eadc70C550484", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x604a9dda2e27D56cfCe457E437a61f4ED0De9dE6", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "ethereum-mainnet-polygon-zkevm-1": { - "mainnet": { - "offRamp": { - "address": "0xF89685b62ac1FB22Cc0f9bFBB3015954A3751744", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xD2a9F49Aa973fDd42Edbb24E01Baa8163ac3141c", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "ethereum-mainnet-scroll-1": { - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x9fdD3015f049F32188C2AB1EA28a9f96a6f23596", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x86Add4b1A0c32CeF910B76816FACb9beC5912a70", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0x5834e1C639418A4973391126576f550A6996836a", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x05d472b114D57E6035089A58Fa997A7940D29a23", - "enforceOutOfOrder": true, - "version": "1.5.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0x77601F272dd2d6481Ac3a13942075388097245Fb", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x28cCF73F7982c1786b84e243FFbD47F4fB8ae43d", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - } - }, - "ethereum-mainnet-taiko-1": { - "mainnet": { - "offRamp": { - "address": "0xe9e7943cd76B34fB90eEdfDFa7E15921a956906f", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x861c7816Ebd335319eB66cb047707C95e9AA0cdC", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - } - }, - "ethereum-mainnet-unichain-1": { - "avalanche-mainnet": { - "offRamp": { - "address": "0xC487bE5D3A0f19f4034804221A3Ab53d752f0eb2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x0cb33060FDF6C63f47922b20dA1bA36F26c8B85C", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0xf5D0d2C5E34142cd666DDBef39857dF02B57327B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xb673646BF3CACdD3D7a7f7EB53051A675922E369", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "celo-mainnet": { - "offRamp": { - "address": "0x06D1A3C7dA103AaD2bbDDC4C34643932b549Bee4", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xc4F901dDF548c689C3D072F0507EAAb763AB5589", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x1233Bf363497E7624299d6d76ae36b914C0fAf3D", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xD5877a4E3331c54cbD0B53dA3cD16a5Ce128c731", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x69B29aEf2857adF1D4F9cBE7b002810564cA4699", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x470Bd9B8d5A19f6f9E6A2c707705Bc13F28d075B", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0xCf2bB21F36b66c71650B9E3C032CbdE93A61b8D3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x5b8DD1c02c67d43fBbA0b6d2245eb0833d6f8e29", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0x240D14E6550f1ac8F518C2AEd886c905207bAA9B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x139839036FF1Df22f47427740f40fE300184Fb8a", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x46962f43107c7A248074922fBaac2C3F5a32F4a2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6D343834A43873D9F86Ad3B7E96009837685b88E", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "sonic-mainnet": { - "offRamp": { - "address": "0x357ED60610da18ef5453d2fdA6b71e1c30Bad824", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x68B0c56b4120c3B40ACf6809cE7c3c5458E03daF", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "ethereum-mainnet-worldchain-1": { - "berachain-mainnet": { - "offRamp": { - "address": "0xbB53fa082b28a45f92cb015Cc9c817b9BE0Eab8c", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xa40D3b99113A171F898EF5A0d6809bd985e45DB6", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "celo-mainnet": { - "offRamp": { - "address": "0x97D60eF016feaF3253E2f43262fe638a3060cA9a", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xEc5069dBA6d83E5FD683eeB3b5de06F43893e1a6", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-zksync-1": { - "offRamp": { - "address": "0x44F39eeE704E3D89acD6D019b061592B129185e8", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x3d5ea8Aa2a9515a9c31900E0C9AFE5896C8fD960", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0x6E514bBa9f3bA098d907Ac10D577b2FB7C9F0ac3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x0129211377B414Cad2c624C40c342FAffB3B3F0F", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "oXAUT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "WLD": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27777700000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27777700000000000000" - } - } - } - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0xB2d6c057391d2a3dA572f7B8016440F7A7AD1287", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xABF586910586b8dcbdF92f1C5e2Ae14106f3DD16", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - } - }, - "ethereum-mainnet-xlayer-1": { - "aptos-mainnet": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - }, - "avalanche-mainnet": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-ink-1": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - } - } - }, - "plasma-mainnet": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "xdai-mainnet": { - "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - } - }, - "ethereum-mainnet-zircuit-1": { - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0x2aacae6564e66004fBe2700E12B010eDa82991fA", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x0D24D9567BF373135208Fc00486ee21BF4c6545C", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - } - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0x69D7a7CBb0E03fCb89983391B4A82231A493E008", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x9E6A9088E3152318e1FFaDadb35ebD46879eF243", - "enforceOutOfOrder": true, - "version": "1.5.0" - }, - "supportedTokens": { - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0x9269e4D4aC9aCc39c5A529A276CC6f6c6c30bbF9", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xF12FE0a9F6d2835AEa502cb1a5b7BbC32245BB13", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0xa257EDEB2cA0d42081E1EFb285ac4c974953Cb29", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xD3Bd3D50E3593AFE8B5A50C1B3F83c21D64c10d2", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - } - }, - "ethereum-mainnet-zksync-1": { - "avalanche-mainnet": { - "offRamp": { - "address": "0x8f41aA10C96Be2749dA47fd0d84e507E34e9c930", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x17D9B1FC307cbF16380f2d835e0654Fe6921BE1E", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } - }, - "bitcoin-mainnet-bob-1": { - "offRamp": { - "address": "0x24aFa3596C6682EbFF3D8505745bA441083e484f", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x4Cb8d5b7D4E95673bCb855cb17D79C992dd84782", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0xacE8A9a195d70834e39BD14b4b6973716f545f3a", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x0cEb5972a6BA5Ed57caB94d71179b741b7D69c74", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "celo-mainnet": { - "offRamp": { - "address": "0x9ff0f85AF7BE9526dC99b6ee91f5BCe5b391808A", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x366CE743c19E8cb2966C3DDe2Ae1216EF9A76d6D", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0xd448c815C421fFBd770C2d3B9a9cBa4E33E3885c", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x66EcB7c8c122d74f19Fc28b275f213Ef8991B7AB", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x8d05075F2dc7D8eFFD9171664f78628c18d68F22", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x73B95bd224a9F5054B87577104106cD36237BaDc", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } - }, - "ethereum-mainnet-ink-1": { - "offRamp": { - "address": "0x4308CD2D9FE580A123C5915b24307EE10650BDAF", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xf3840012905833c8F1A39a51697ADB2F0faC0B2c", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0x906e63ff31558eE1DAf6C1404e153b621CD26996", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xbD9148D567260c4580f00A6dd5a2bB0e626eFd62", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } - } - }, - "ethereum-mainnet-worldchain-1": { - "offRamp": { - "address": "0xA2398c5600FB5c8eAC093ebC9Ef55D34F5Ff4EaA", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x1CaBaF3CDDEf4b53cc53481aCfBc722F225f148E", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0x6BACb854483Ffe310F5Ac08879868E96AE0DC000", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xD1B33FAd3fF7a793EE39473f865630e3b6371086", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1736100000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1736000000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "matic-mainnet": { - "offRamp": { - "address": "0x83ca2A80010CD1Ea1323aFf23d88294327d1Cef3", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x37CbA662E9c373F2166CcA0D9c576dd089D7209a", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - } - }, - "etherlink-mainnet": { - "mainnet": { - "offRamp": { - "address": "0x3f63716b703518ad436F1F3061a56AF52D8de169", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xD4D2841Ac332075833AE86eb49ce7aF9f353cd21", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } - } - }, - "everclear-mainnet": { - "avalanche-mainnet": { - "offRamp": { - "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "tac-mainnet": { - "offRamp": { - "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", - "version": "1.6.0" - }, - "onRamp": { - "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - } - }, - "fraxtal-mainnet": { - "mainnet": { - "offRamp": { - "address": "0x1BE8714ce5E35B38Cd977eadaC1307B9B77Efd0d", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x00D0E4e85ccCaF37F1a10d7738ACFC59803B21fD", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "hedera-mainnet": { - "mainnet": { - "offRamp": { - "address": "0x6e6bA22dd2A558cA00B7799F2771938AfEEE65B9", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6480de6257c3b0Bc249f2653551964693AA914c0", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - } - }, - "hemi-mainnet": { - "mainnet": { - "offRamp": { - "address": "0xC3bE3153C3ad495c381a7Bad4C30701745Ac8b3c", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xBD4ee0f8a4F658D0e7da8811Eb6ec0CC02baA974", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "hyperliquid-mainnet": { - "0g-mainnet": { - "offRamp": { - "address": "0x70003d849A20e33997fea69bBc8a366D6ab0E131", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x72f6000D70B291C67bED898214156d01383274b1", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "berachain-mainnet": { - "offRamp": { - "address": "0xdef8217620734C531D69E0534C9881A1311c5791", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x4122fe199B6e489a89f54c67245Be33bf602935F", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0x50ceF176C2F39080b15Aa4E7f97f6BE6Fa28c5d1", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xfF327Ef3b73346f2AacD6ec02c70440D31fd8319", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x70003d849A20e33997fea69bBc8a366D6ab0E131", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x72f6000D70B291C67bED898214156d01383274b1", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "mainnet": { - "offRamp": { - "address": "0xf69F5e554E6D3D90DC3a221121ffEf1ee8bf5B2A", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x375dDf245FB9951A1D1D4EF516Abd7D2B521238F", - "enforceOutOfOrder": true, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "kHYPE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "VSN": { - "rateLimiterConfig": { - "in": { - "capacity": "82500000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - }, - "out": { - "capacity": "75000000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "solana-mainnet": { - "offRamp": { - "address": "0x70003d849A20e33997fea69bBc8a366D6ab0E131", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x72f6000D70B291C67bED898214156d01383274b1", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "WHLP": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - } - }, - "kaia-mainnet": { - "mainnet": { - "offRamp": { - "address": "0x59a65c7A78A0757b6e27905f9C0e21831b25df51", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x21c04748372cFFB7565328afA8a8B23c8d65Ef9E", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDO": { - "rateLimiterConfig": { - "in": { - "capacity": "21000000000000000000000000", - "isEnabled": true, - "rate": "232000000000000000000" - }, - "out": { - "capacity": "20000000000000000000000000", - "isEnabled": true, - "rate": "232000000000000000000" - } - } - } - } - } - }, - "lens-mainnet": { - "mainnet": { - "offRamp": { - "address": "0x064bDf3699E17e79E56DF65508170339cD73EB7e", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xdaC19bddEf396c222ecDb9109C9E5993a19cd5d5", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "lisk-mainnet": { - "mainnet": { - "offRamp": { - "address": "0x9Efcf5b21969E845A285a9cDB74E7C91F93aBa14", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x1F262f3BB509657D8816f9BfF5Ae58334E8504f5", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - } - }, - "mainnet": { - "0g-mainnet": { - "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - }, - "out": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - } - } - } - } - }, - "ab-mainnet": { - "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", - "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "abstract-mainnet": { - "offRamp": { - "address": "0x9f0E818A8DDDf48C52d5c94D55079E3617d55181", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x266e520E272FCca3cE46A379a06Dc5ba62717b8F", - "enforceOutOfOrder": true, - "version": "1.5.0" - } - }, - "apechain-mainnet": { - "offRamp": { - "address": "0x7115F0fB22e0A85133C06b50aDc3B90b335ea175", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x48F836a7697c0082B2Ecb4B2639f6da79de21980", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "aptos-mainnet": { - "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", - "enforceOutOfOrder": true, - "version": "1.6.0" - }, - "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "avalanche-mainnet": { - "offRamp": { - "address": "0xd98E80C79a15E4dbaF4C40B6cCDF690fe619BFBb", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xaFd31C0C78785aDF53E4c185670bfd5376249d8A", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "avETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "avETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BYTES": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "EmCH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "MYST": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "oXAUT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDY": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "tETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TREE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstPOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "berachain-mainnet": { - "offRamp": { - "address": "0xA627F208c5c32e5638c64147d0aC98bb40F758f0", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xBeFfEF56Cd6FA063d2e04E126cF1b93269886c42", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "1000000000000000000", - "isEnabled": true, - "rate": "100000000000000000" - } - } - }, - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "DOLO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "pufETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "binance-smart-chain-mainnet-opbnb-1": { - "offRamp": { - "address": "0xe79705E9f6842223C9b07B70119f3468E2962162", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xffbEC42C001f0E54924078C6D36412128bBC4330", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "bitcoin-mainnet-bitlayer-1": { - "offRamp": { - "address": "0x3B45dd27E0cF84F1af98DEaBDc8f96303475ef58", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x4FB5407d6911DaA0B8bde58A754E7D01CB8b05c5", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - }, - "out": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - }, - "out": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - }, - "out": { - "capacity": "114000000000000000000", - "isEnabled": true, - "rate": "32000000000000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "bitcoin-mainnet-bob-1": { - "offRamp": { - "address": "0xdE81f1627ef2F6E23A2C0f338623C78c10EA57AC", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x1B960560324c03db5565545B353198fdd07A195d", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BOB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "bitcoin-mainnet-botanix": { - "offRamp": { - "address": "0x64A5c64945c72bc46DF52c82Cfce9161b888578B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x86768e4e4B2E3C1CF812D5C8A7c7becFA4c8D486", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "bitcoin-mainnet-bsquared-1": { - "offRamp": { - "address": "0xF3AC96642F9BA5De3BBc864d609E3F534dD3b7F9", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xddF4b4aF7A9603869C90189EFa8826683D0D234b", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - } - } - }, - "bitcoin-merlin-mainnet": { - "offRamp": { - "address": "0x5B6D2998EEF5cBBa7e8345B08Dd41AecEC5EACA5", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x20fD5ab74D519df395f41c958D982BecB6b64432", - "enforceOutOfOrder": true, - "version": "1.5.0" - } - }, - "bittensor-mainnet": { - "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "bsc-mainnet": { - "offRamp": { - "address": "0x66d84fedED0e51aeB47ceD1BB2fc0221Ae8D7C12", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x948306C220Ac325fa9392A6E601042A3CD0b480d", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "$PAAL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "1XMM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BANK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BARD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BKN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "BTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CHEX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "EDEN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FF": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "mwBETH": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000", - "isEnabled": true, - "rate": "46000000000000000" - }, - "out": { - "capacity": "500000000000000000000", - "isEnabled": true, - "rate": "46000000000000000" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SAS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDT": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.BERA": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABLE": { - "rateLimiterConfig": { - "in": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - }, - "out": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - } - } - }, - "sUSD1+": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TREE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TURBO": { - "rateLimiterConfig": { - "in": { - "capacity": "7000000000000000000000000", - "isEnabled": true, - "rate": "1944444400000000000000" - }, - "out": { - "capacity": "7000000000000000000000000", - "isEnabled": true, - "rate": "1944444400000000000000" - } - } - }, - "TURTLE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "UNIO": { - "rateLimiterConfig": { - "in": { - "capacity": "15000000000000000000000000", - "isEnabled": true, - "rate": "520000000000000000000" - }, - "out": { - "capacity": "15000000000000000000000000", - "isEnabled": true, - "rate": "520000000000000000000" - } - } - }, - "USD0": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - } - } - }, - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDf": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDFI": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - } - } - }, - "USDO": { - "rateLimiterConfig": { - "in": { - "capacity": "10500000000000000000000000", - "isEnabled": true, - "rate": "1160000000000000000000" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1160000000000000000000" - } - } - }, - "USUAL": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - } - } - }, - "VOOI": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "VSN": { - "rateLimiterConfig": { - "in": { - "capacity": "82500000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - }, - "out": { - "capacity": "75000000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WHY": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WLFI": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "231500000" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "231500000" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "celo-mainnet": { - "offRamp": { - "address": "0x794aE32b63b8a82a6e2Ec5017bbC6bfbddA5ce96", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x741599d9a5a1bfC40A22f530fbCd85E2718e9F90", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "core-mainnet": { - "offRamp": { - "address": "0xdE66080eABE390198b8918cb3F61e1869dbC8079", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xa6D806e4EB8726542cf536518fC47f39d68cCb48", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "corn-mainnet": { - "offRamp": { - "address": "0xb0F5b6DB1157719795eCCd9C6023C66bB2ec414F", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x7B78f8D16C4ae6E51c29295D58f05dCC67180A2b", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - }, - "out": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - } - } - } - } - }, - "cronos-mainnet": { - "offRamp": { - "address": "0xAe2A2A088A8F85A2DB90A61BD463433985C437F0", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x03CB4C67D01a78F44289541281E57C33E6b834d9", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "cronos-zkevm-mainnet": { - "offRamp": { - "address": "0xcdcA3F3aa3A4df41a3DAF885e3E25666Ee96D7e4", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x8b858ED23502611aB86109717C8842A7A8f117ec", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-andromeda-1": { - "offRamp": { - "address": "0x330349112e13232131Da51f9f3b153d825f65e61", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x75d536eED32f4c8Bb39F4B0c992163f5BA49B84e", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SDL": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - }, - "out": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-arbitrum-1": { - "offRamp": { - "address": "0xdf615eF8D4C64d0ED8Fd7824BBEd2f6a10245aC9", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x69eCC4E2D8ea56E2d0a05bF57f4Fd6aEE7f2c284", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "APU": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DFX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DOLO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DPI": { - "rateLimiterConfig": { - "in": { - "capacity": "2593000000000000000000", - "isEnabled": true, - "rate": "180000000000000000" - }, - "out": { - "capacity": "2593000000000000000000", - "isEnabled": true, - "rate": "180000000000000000" - } - } - }, - "dsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "25000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - }, - "out": { - "capacity": "25000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - }, - "out": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - } - } - }, - "egETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "ETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "56000000000000000" - }, - "out": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "56000000000000000" - } - } - }, - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "hyETH": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000", - "isEnabled": true, - "rate": "34700000000000000" - }, - "out": { - "capacity": "500000000000000000000", - "isEnabled": true, - "rate": "34700000000000000" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LDY": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "mDLP": { - "rateLimiterConfig": { - "in": { - "capacity": "416000000000000000000000", - "isEnabled": true, - "rate": "4810000000000000000" - }, - "out": { - "capacity": "416000000000000000000000", - "isEnabled": true, - "rate": "4810000000000000000" - } - } - }, - "mmETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "mstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "mswETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "MVI": { - "rateLimiterConfig": { - "in": { - "capacity": "3333000000000000000000", - "isEnabled": true, - "rate": "230000000000000000" - }, - "out": { - "capacity": "3333000000000000000000", - "isEnabled": true, - "rate": "230000000000000000" - } - } - }, - "NPC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "NUON": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "pufETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SD": { - "rateLimiterConfig": { - "in": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - }, - "out": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - } - } - }, - "SDL": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - }, - "out": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "207500000000000000000" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDT": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "SDY": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "58000000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABLE": { - "rateLimiterConfig": { - "in": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - }, - "out": { - "capacity": "7000000000000000000000", - "isEnabled": true, - "rate": "81000000000000000" - } - } - }, - "STBU": { - "rateLimiterConfig": { - "in": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "suBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - }, - "out": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - } - } - }, - "suETH": { - "rateLimiterConfig": { - "in": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - }, - "out": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - } - } - }, - "suUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "tETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "231428" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "231428" - } - } - }, - "USD+": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - }, - "out": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDFI": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "570000000000000000" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "VSN": { - "rateLimiterConfig": { - "in": { - "capacity": "82500000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - }, - "out": { - "capacity": "75000000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100830000000000000000", - "isEnabled": true, - "rate": "28008333333333333" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208333333333333" - } - } - }, - "WFRAGSOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "231500000" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "231500000" - } - } - }, - "wOETH": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000", - "isEnabled": true, - "rate": "417000000000000000" - }, - "out": { - "capacity": "1500000000000000000000", - "isEnabled": true, - "rate": "417000000000000000" - } - } - }, - "WOLF": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "15000000000000000000000", - "isEnabled": true, - "rate": "4000000000000000000" - }, - "out": { - "capacity": "15000000000000000000000", - "isEnabled": true, - "rate": "4000000000000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xrETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xRPL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0x6B4B6359Dd5B47Cdb030E5921456D2a0625a9EbD", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xb8a882f3B88bd52D1Ff56A873bfDB84b70431937", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "$PAAL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "APU": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27777777700000000000000" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BKN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "1000000000000000000", - "isEnabled": true, - "rate": "100000000000000000" - } - } - }, - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "BYTES": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CHEX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DIP": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "2778000000000000000000" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "2778000000000000000000" - } - } - }, - "DOBO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DPI": { - "rateLimiterConfig": { - "in": { - "capacity": "741000000000000000000", - "isEnabled": true, - "rate": "50000000000000000" - }, - "out": { - "capacity": "741000000000000000000", - "isEnabled": true, - "rate": "50000000000000000" - } - } - }, - "dsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "13000000000000000000", - "isEnabled": true, - "rate": "900000000000000" - }, - "out": { - "capacity": "13000000000000000000", - "isEnabled": true, - "rate": "900000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - }, - "out": { - "capacity": "625000000000000000000000", - "isEnabled": true, - "rate": "173600000000000000000" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148148148148148148" - } - } - }, - "GEN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "hyETH": { - "rateLimiterConfig": { - "in": { - "capacity": "28000000000000000000", - "isEnabled": true, - "rate": "2000000000000000" - }, - "out": { - "capacity": "28000000000000000000", - "isEnabled": true, - "rate": "2000000000000000" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "JASMY": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "1388888800000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "1388888800000000000000" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LDY": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "LsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "MEEM": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "2780000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "2780000000000000000" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "MVI": { - "rateLimiterConfig": { - "in": { - "capacity": "1111000000000000000000", - "isEnabled": true, - "rate": "80000000000000000" - }, - "out": { - "capacity": "1111000000000000000000", - "isEnabled": true, - "rate": "80000000000000000" - } - } - }, - "MYST": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "NEIRO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "NUON": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "oXAUT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SAS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABUL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "suBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - }, - "out": { - "capacity": "8000000000000000000", - "isEnabled": true, - "rate": "92600000000000" - } - } - }, - "suETH": { - "rateLimiterConfig": { - "in": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - }, - "out": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1700000000000000" - } - } - }, - "suUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "2314000000000000000" - } - } - }, - "SXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "tETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "UNIO": { - "rateLimiterConfig": { - "in": { - "capacity": "15000000000000000000000000", - "isEnabled": true, - "rate": "520000000000000000000" - }, - "out": { - "capacity": "15000000000000000000000000", - "isEnabled": true, - "rate": "520000000000000000000" - } - } - }, - "USD+": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - }, - "out": { - "capacity": "200000000000", - "isEnabled": true, - "rate": "55000000" - } - } - }, - "USD0": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "USDO": { - "rateLimiterConfig": { - "in": { - "capacity": "5500000000000000000000000", - "isEnabled": true, - "rate": "63657440000000000000" - }, - "out": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "USUAL": { - "rateLimiterConfig": { - "in": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - }, - "out": { - "capacity": "3000000000000000000000000", - "isEnabled": true, - "rate": "35000000000000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100830000000000000000", - "isEnabled": true, - "rate": "28008333333333333" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208333333333333" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "wOETH": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "277800000000000000" - }, - "out": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "277800000000000000" - } - } - }, - "WOLF": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "XSWAP": { - "rateLimiterConfig": { - "in": { - "capacity": "20000000000000000000000000", - "isEnabled": true, - "rate": "463000000000000000000" - }, - "out": { - "capacity": "20000000000000000000000000", - "isEnabled": true, - "rate": "463000000000000000000" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - }, - "ZeUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } - }, - "ethereum-mainnet-blast-1": { - "offRamp": { - "address": "0xF4468E56179e6EF59d6f5B133D9355AAD91Ea9ae", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6751cA96b769129dFE6eB8E349c310deCEDb4e36", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-hashkey-1": { - "offRamp": { - "address": "0xf2EB4CE854C8C0AAea6080Ef825efA5A84a8656a", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x61B4B85364a2609177D2C498ff864E01a63148a5", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } - }, - "ethereum-mainnet-ink-1": { - "offRamp": { - "address": "0x0F1B1A46AdeadF3C0D583AC86f40bC9e0b2e4Ba2", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xEEe2AE1d0Fa6D1D38BBBa555A7C7B90C8734a8e2", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - }, - "out": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0x418dcbCf229897d0CCf1B8B464Db06C23879FBB4", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x626189C882A80fF0D036d8D9f6447555e81F78E9", - "enforceOutOfOrder": true, - "version": "1.5.0" - }, - "supportedTokens": { - "AISTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "avETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "avETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "TURTLE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "33300000000000000000", - "isEnabled": true, - "rate": "9250000000000000" - }, - "out": { - "capacity": "30000000000000000000", - "isEnabled": true, - "rate": "8333333333333333" - } - } - }, - "xrETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xRPL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } - }, - "ethereum-mainnet-mantle-1": { - "offRamp": { - "address": "0x5B859E596C4285bf489E1bFa222b97dB431da7eC", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x70B2b3430c41bA19E20F57Cae23c3C619CbCA65D", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "11574" - } - } - } - } - }, - "ethereum-mainnet-mode-1": { - "offRamp": { - "address": "0xb57D52F7Cb7BBD19a117585bbaf712108E56dd8f", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xeA6d4a24B262aB3e61a8A62f018A30beCD086f82", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "sDAI": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "69400000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "69400000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0x562a2025E60AA19Aa03Ea41D70ea1FD3286d1D3B", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x3455D8E039736944e66e19eAc77a42e8077B07bf", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "clBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "ETHx": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "56000000000000000" - }, - "out": { - "capacity": "1000000000000000000000", - "isEnabled": true, - "rate": "56000000000000000" - } - } - }, - "IBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - }, - "out": { - "capacity": "450000000", - "isEnabled": true, - "rate": "83300" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "OVER": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SD": { - "rateLimiterConfig": { - "in": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - }, - "out": { - "capacity": "384000000000000000000000", - "isEnabled": true, - "rate": "4444000000000000000" - } - } - }, - "sDOLA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "sINV": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - }, - "out": { - "capacity": "10000000000000000000000", - "isEnabled": true, - "rate": "110000000000000000" - } - } - }, - "stTAO": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - }, - "out": { - "capacity": "400000000000", - "isEnabled": true, - "rate": "41600000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "11574" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100830000000000000000", - "isEnabled": true, - "rate": "28008333333333333" - }, - "out": { - "capacity": "90750000000000000000", - "isEnabled": true, - "rate": "25208333333333333" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "ZUN": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - }, - "out": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23140000000000000000" - } - } - }, - "zunETH": { - "rateLimiterConfig": { - "in": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - }, - "out": { - "capacity": "72000000000000000000", - "isEnabled": true, - "rate": "1666000000000000" - } - } - }, - "zunUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "250000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - } - } + "supportedTokens": [ + "BOLD", + "BR", + "DOLO", + "LBTC", + "SolvBTC", + "SolvBTC.BERA", + "brBTC", + "pufETH", + "sDOLA", + "uniBTC", + "xSolvBTC" + ] }, - "ethereum-mainnet-polygon-zkevm-1": { + "matic-mainnet": { "offRamp": { - "address": "0x0aB48c500AbD8392620c3C4E4fdD5d7063C44554", + "address": "0x32cBB0850DBD4AFc72dc8E7eC09fdfb527d3a507", "version": "1.5.0" }, "onRamp": { - "address": "0x33417f13DFBC2FfB9e1B43051c3737370F3691a4", - "enforceOutOfOrder": true, + "address": "0x8a3712bdcDD829e2B074F1424D1be2F3dFE2EAAC", + "enforceOutOfOrder": false, "version": "1.5.0" } }, - "ethereum-mainnet-scroll-1": { + "monad-mainnet": { "offRamp": { - "address": "0x26a10137A54F4Ea01D20758Ac5AdBf9326340Fc3", + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "polygon-mainnet-katana": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "sei-mainnet": { + "offRamp": { + "address": "0x6Da0E306a8AD7B59690bef0d22BB89262C227535", "version": "1.5.0" }, "onRamp": { - "address": "0x362A221C3cfd7F992DFE221687323F0BA9BA8187", - "enforceOutOfOrder": true, + "address": "0x3f85FcD7C0fa9f70ceDA58121377B48E42b9A3E5", + "enforceOutOfOrder": false, "version": "1.5.0" + } + }, + "solana-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": true, + "version": "1.6.0" } }, - "ethereum-mainnet-taiko-1": { + "sonic-mainnet": { "offRamp": { - "address": "0x720EA8a2662376B89dEe1A7bAcA95b2eb6B6fF81", + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "stable-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "tac-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + } + }, + "binance-smart-chain-mainnet-opbnb-1": { + "bsc-mainnet": { + "offRamp": { + "address": "0x97D090497861ab69fE637781232BCcf302497D17", "version": "1.5.0" }, "onRamp": { - "address": "0x5F6e7707DE5019E13BaFbD2f4569B2453F16eB3e", + "address": "0xbDD7a56aeF09C3E8a2Be3C20Bb8c8C054Ea87120", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "supportedTokens": ["THE"] + }, + "mainnet": { + "offRamp": { + "address": "0xe89eF171B45c318ee786941c96944CD162187E2A", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x47c94F8540F950B36f0C34Db6977Eb7ADFc8A50B", + "enforceOutOfOrder": false, + "version": "1.5.0" } + } + }, + "bitcoin-mainnet-bitlayer-1": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x574Da74E87FB182dC96591a223700fA9965919e3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xF398585cDDEB7DD6a947DC394701F761c5F4d1BC", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["YBTC.B"] }, - "ethereum-mainnet-unichain-1": { + "bsc-mainnet": { "offRamp": { - "address": "0xaA0DA3e06F43a5227abB0eA7D6DF3d1037B1769B", + "address": "0xD12F5Dc1a0526FfdBC32CbB174436aA7975a9e1b", "version": "1.5.0" }, "onRamp": { - "address": "0x5E7397CA539C94185BBD950706F0Dd8628587E04", + "address": "0x818c49325b35A86b7B2AD1463c26cE85137fc86e", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BTR", "YBTC.B"] + }, + "mainnet": { + "offRamp": { + "address": "0x31A9dc0559F0619275aa034470D464cde2210649", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x9db257ae83968F10f6A50009587BdA2fCedFDd5A", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BTR", "USDC", "USDT", "WETH", "YBTC.B", "uniBTC", "wstETH"] }, - "ethereum-mainnet-worldchain-1": { + "plasma-mainnet": { "offRamp": { - "address": "0x5EDa6801dBD2bBdbF0401d34c730fa2C3A97C3F4", + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["YBTC.B"] + }, + "plume-mainnet": { + "offRamp": { + "address": "0xB8BBE35C3A3cb402f62b4941Eb0D0a7684E101C6", "version": "1.5.0" }, "onRamp": { - "address": "0xdB6ebB3ea15595E516dEf4a9875479573a4F19b6", + "address": "0x95E55753C9b742Cc615E9F527f6FA7b957a92596", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "oXAUT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "WLD": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27777700000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "27777700000000000000" - } - } - } - } + "supportedTokens": ["YBTC.B"] }, - "ethereum-mainnet-xlayer-1": { + "solana-mainnet": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", "version": "1.6.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", - "enforceOutOfOrder": false, + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - } - } + "supportedTokens": ["YBTC.B"] + } + }, + "bitcoin-mainnet-bob-1": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x90e25232A53898f13F9436703dc405b97cD69168", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xAE685F7EE3cc46bD82D379E3747d530ED45b3403", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, - "ethereum-mainnet-zircuit-1": { + "berachain-mainnet": { "offRamp": { - "address": "0x4E4003DAFD00eC3B5F17f05950759054051950d6", + "address": "0x02E8b0fcC265a5ff7659584cF7b46f6460ddb69C", "version": "1.5.0" }, "onRamp": { - "address": "0x4Cc3D95d9384D3287724B83099f01BC3025702c0", - "enforceOutOfOrder": true, + "address": "0x4D128E2a1aa4770FE6aF57B9b70C5508d7f59842", + "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "rsETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["SolvBTC", "SolvBTC.BERA", "xSolvBTC"] }, - "ethereum-mainnet-zksync-1": { + "bsc-mainnet": { "offRamp": { - "address": "0x6868FefbEFDc2B2FB75E6ED216dB1BeC02563D69", + "address": "0xa0852f8949752e8d29e2B3883a77994026c30006", "version": "1.5.0" }, "onRamp": { - "address": "0x9B14AE850653dD0E30fBC93ab7f77D0d638a365B", + "address": "0x68EA343954ea576787243F239aE49Aa6ef6C3DBd", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1736000000000000" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "150000000000000000000", - "isEnabled": true, - "rate": "1736000000000000" - } - } - } + "supportedTokens": ["BOB", "SolvBTC", "SolvBTC.BERA", "SolvBTC.JUP", "xSolvBTC"] + }, + "corn-mainnet": { + "offRamp": { + "address": "0xCb1eE88E522bBE90e5D59166cE794B3c0a472476", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xB4D095a57A7D91a8dA8Bdb928D1e17452125bdd7", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "etherlink-mainnet": { + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x1AE9FF15C2e678594CCeC6F79F1A33761eE7594a", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x48043178bdBD5A6DE2972440ca6c946F2Ba2c77A", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", - "version": "1.6.0" + "address": "0x14CeB5F5b5A78D9017AFf9ab262b0d6Ab7c4D419", + "version": "1.5.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0x9b896C2ac58BC0e5606f3AB553dC7d49dab5642a", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } + "supportedTokens": ["SolvBTC", "USDT", "xSolvBTC"] }, - "everclear-mainnet": { + "ethereum-mainnet-ink-1": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", - "version": "1.6.0" + "address": "0xc8C08F48B9C9d03B64AE7d44695c436Ec398a555", + "version": "1.5.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0x25c6de3917AE4B527552e76Af7cAE0BC5759299C", "enforceOutOfOrder": false, - "version": "1.6.0" - } + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, - "fraxtal-mainnet": { + "ethereum-mainnet-linea-1": { "offRamp": { - "address": "0x559c3233aE9A0EcD45a6c45ee3B8c2c6DBa5F48D", + "address": "0xF193db0E32048Ad5808616Dc31702E9F3439B1A8", "version": "1.5.0" }, "onRamp": { - "address": "0x31ee106a4585a796caacC645172B9F7e9c2f8D37", + "address": "0x75edD666a263DA7074c86F41797787b71DeA39Ad", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-zksync-1": { + "offRamp": { + "address": "0xDd48df19774C82Dbbdd1d58990d23B7B2d92dBC8", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc7a5Ac793527B36A798d420871B8B271200E6Ddc", "enforceOutOfOrder": false, "version": "1.5.0" - } + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, - "hedera-mainnet": { + "mainnet": { "offRamp": { - "address": "0x7A82D2d3d824f9BAc136C31ef8086C673d23666D", + "address": "0xbD064591d0789e9d66DDa2f4432aCB78232dDE1A", "version": "1.5.0" }, "onRamp": { - "address": "0x08C798376AfA295C047bDb5c011097865895672d", + "address": "0x00E64619Bb29f7E1d4E1CC9f21ecEA05189fd8ab", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BOB", "SolvBTC", "SolvBTC.BERA", "USDC", "USDT", "uniBTC", "xSolvBTC"] }, - "hemi-mainnet": { + "matic-mainnet": { "offRamp": { - "address": "0x9de971a8449Bc9F31Fe7B0F2Ccdab3873f711988", + "address": "0x9ec62973052Fa97b218aBce0d953ce4aD09587cf", "version": "1.5.0" }, "onRamp": { - "address": "0x7d7C4933f17B414f50C97d1a8862A1ace82557B3", + "address": "0x358E3847a9c21EbBFb22925B99DFA4f7DfADAD28", "enforceOutOfOrder": false, "version": "1.5.0" - } + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, - "hyperliquid-mainnet": { + "sei-mainnet": { "offRamp": { - "address": "0x69c3619326d5DF0d5abB752f2AE629413811ccD1", + "address": "0xaABE2E880C2061FbCc6598521A3152003657883b", "version": "1.5.0" }, "onRamp": { - "address": "0xC4a125BDBeE19Ec8BE02502cff9310FF9395905B", - "enforceOutOfOrder": true, + "address": "0xa2c757629a6A9832dB37A032dc92684a3d1Bb027", + "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "kHYPE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - }, - "out": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - } - } - }, - "VSN": { - "rateLimiterConfig": { - "in": { - "capacity": "82500000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - }, - "out": { - "capacity": "75000000000000000000000000", - "isEnabled": true, - "rate": "69000000000000000000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "soneium-mainnet": { + "offRamp": { + "address": "0x5Caa8BdA53306D15C170B3a8fa59F9748C169Df2", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xBF9789236E73085A81925a8B549CEdF7e2825131", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "SolvBTC.JUP", "xSolvBTC"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x54992b4DB694d12FF413AEb530d87428C53DfB63", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x501AE86DA029F0D2D1788cdd824f943E0Bc8A38C", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + } + }, + "bitcoin-mainnet-botanix": { + "mainnet": { + "offRamp": { + "address": "0x9ec4DEB066a72BCd0DE1698d9C88277DdF6F94eF", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x44Db2B9ee78228b6d88ff89b8ebf99685ede2786", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + } + }, + "bitcoin-mainnet-bsquared-1": { + "bsc-mainnet": { + "offRamp": { + "address": "0xE6ef0aD5eC1eedD70416Ee00F108c494dF0bE0d6", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x79328C1247A3568C609C0e6cf8fa23aF5199F5b9", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["stBTC"] + }, + "mainnet": { + "offRamp": { + "address": "0xaa8bA928903C08417f2F4FC21D1378d90A960BDe", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xB1C908A7CF6f5FB1ed18a73aD60ffF9CC8276eC1", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["uniBTC"] }, - "kaia-mainnet": { + "soneium-mainnet": { "offRamp": { - "address": "0x4676537819a87E9D515D654f8bedf45A744cF214", + "address": "0x3f55F2fA9B0A7b927A094294eF14b85D0979DC83", "version": "1.5.0" }, "onRamp": { - "address": "0x8469b5AbD81987F9347c0bAbd47b9eB11dA7d0dF", + "address": "0x6F7EC920478A7d1d236282AeC7F1d1B3a1fAf49E", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "USDO": { - "rateLimiterConfig": { - "in": { - "capacity": "21000000000000000000000000", - "isEnabled": true, - "rate": "232000000000000000000" - }, - "out": { - "capacity": "20000000000000000000000000", - "isEnabled": true, - "rate": "232000000000000000000" - } - } - } } - }, - "lens-mainnet": { + } + }, + "bitcoin-merlin-mainnet": { + "mainnet": { "offRamp": { - "address": "0x4Bc6027Cd2da6CB7A105D5cE2D039c4892225419", + "address": "0x894C22E2A9f243ee4788643642CdED439Cc868C2", "version": "1.5.0" }, "onRamp": { - "address": "0x6715EA73EcAf1CaE1c736731129637B2E94a6B49", - "enforceOutOfOrder": true, + "address": "0x3D25ff4cBaf29373B9Ec1784Bb5C8DC5e15347D8", + "enforceOutOfOrder": false, "version": "1.5.0" } + } + }, + "bittensor-mainnet": { + "bsc-mainnet": { + "offRamp": { + "address": "0x51a6150400ed9F0Ae240F5D1b15E3b45Fc4339C7", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x345Cc465BCB9a902B420320B8793C9A5d6064404", + "enforceOutOfOrder": false, + "version": "1.6.0" + } }, - "lisk-mainnet": { + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0x82dAe15e45D63f2Ae85B1f0D690685A021D3a0fC", - "version": "1.5.0" + "address": "0x51a6150400ed9F0Ae240F5D1b15E3b45Fc4339C7", + "version": "1.6.0" }, "onRamp": { - "address": "0x74Cb66502D855992137c5dC8A502c396A6E77931", + "address": "0x345Cc465BCB9a902B420320B8793C9A5d6064404", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" } }, - "matic-mainnet": { + "mainnet": { "offRamp": { - "address": "0x718672076D6d51E4c76142B37bC99E4945d704a3", - "version": "1.5.0" + "address": "0x51a6150400ed9F0Ae240F5D1b15E3b45Fc4339C7", + "version": "1.6.0" }, "onRamp": { - "address": "0x15a9D79d6b3485F70bF82bC49dDD1fcB37A7149c", + "address": "0x345Cc465BCB9a902B420320B8793C9A5d6064404", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" + } + } + }, + "bsc-mainnet": { + "0g-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" }, - "supportedTokens": { - "1XMM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DFX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000000", - "isEnabled": true, - "rate": "13889000000000000000000" - }, - "out": { - "capacity": "50000000000000000000000000", - "isEnabled": true, - "rate": "13889000000000000000000" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "OSIS": { - "rateLimiterConfig": { - "in": { - "capacity": "16667000000000000000000", - "isEnabled": true, - "rate": "4600000000000000000" - }, - "out": { - "capacity": "16667000000000000000000", - "isEnabled": true, - "rate": "4600000000000000000" - } - } - }, - "REG": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SOIL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABUL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TRADE": { + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "W0G": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -26401,8 +1555,242 @@ "rate": "0" } } - }, - "USDC": { + } + } + }, + "aptos-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["USD1", "brBTC", "uniBTC"] + }, + "avalanche-mainnet": { + "offRamp": { + "address": "0xc69a550470bEbC5c3Be98A4C3dD26C6AdD90C64b", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x43F00dBf0Aa61A099c674A74FBdCb93786564950", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "LBTC", "LEND", "NXPC", "SHIB", "SolvBTC", "YBTC.B", "savBTC", "xSolvBTC"] + }, + "berachain-mainnet": { + "offRamp": { + "address": "0xe7EcE831c683B4eCd01B895f7310b0bb17aD64ef", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x004405d927caD243358A270c2dD3D51c8303A390", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BR", "SolvBTC", "SolvBTC.BERA", "beraBTC", "xSolvBTC"] + }, + "binance-smart-chain-mainnet-opbnb-1": { + "offRamp": { + "address": "0xA94106fd5c5be306c14Ccb8Ec9f2422bA24E4ea6", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x2e75695a0a580E120B387CCcADAf7FfdC217a427", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["THE"] + }, + "bitcoin-mainnet-bitlayer-1": { + "offRamp": { + "address": "0xD7B436696b869e0C0241DC44d047F257504F7616", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x00A4234078f73FA9479A6ee14d4EEaCC9B8dcb9c", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BTR", "YBTC.B"] + }, + "bitcoin-mainnet-bob-1": { + "offRamp": { + "address": "0x7B9739889617a87aB3DE8B5C70Bb549500F38645", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xa837B3076a8BBE7A3B1F98073E4F46B968042fbE", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BOB", "SolvBTC", "SolvBTC.BERA", "SolvBTC.JUP", "xSolvBTC"] + }, + "bitcoin-mainnet-bsquared-1": { + "offRamp": { + "address": "0x8a564880a05e2C101Dd339CE7590e830193287A8", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x2f43fEFC5C7ec5Fff64eC5Cac96447Edb7d17993", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["stBTC"] + }, + "bittensor-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "corn-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x2A9C65afF39758CeAa24dBD1ACd1BeB3618e6780", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x5577c19bD183e39a007ce4CE236f1D91e9132D5c", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "CKP", + "DOBO", + "IXT", + "LAND", + "LEND", + "RDP", + "SDT", + "STABLE", + "STBU", + "SolvBTC", + "USDFI", + "VSN", + "WECO", + "WMTX", + "WSDM", + "mBTC", + "wUSDx", + "xSolvBTC" + ] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x133672C0F0067573254dd7C8C9818a37d6208610", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xdABb6De5eC48dd2fcF28ac85CbEFe3F19E03F1BD", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "$PAAL", + "AISTR", + "BETS", + "BKN", + "BR", + "CHEX", + "DOBO", + "IXT", + "LBTC", + "LEND", + "RIZE", + "SAS", + "SKYA", + "SNOW", + "SolvBTC", + "TRADE", + "UNIO", + "USDO", + "WHY", + "WMTX", + "wUSDx", + "xGold", + "xSolvBTC" + ] + }, + "ethereum-mainnet-blast-1": { + "offRamp": { + "address": "0x38cA434FE65D540942A36c84FdFD4B7C7a9a4612", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x0b7Bfe549F26AF4B6aA5246CB3FD96C8a5c23a68", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-hashkey-1": { + "offRamp": { + "address": "0xc188c5Df59aec57cd7a29aDE2a2176fAbbf24b81", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xfE73ed7c00eD640C5991fa8e81Ec3fcA5f8E3cdd", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["enzoBTC"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x12CC5797a842347Dc2D4DAB2aFe22b07fc987E25", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x2Bac5BC6c0a073831a4cf6E0c996140B7A76F296", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0x0c42a007BF89DC2CAfAb3fbd2eC1C1cA5BFe7d7C", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x86768B77C971524D5042631749A59527E8a9604d", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": ["AISTR", "SolvBTC", "TURTLE", "savBTC", "savUSD", "xSolvBTC"] + }, + "ethereum-mainnet-mantle-1": { + "offRamp": { + "address": "0xd19C02763E1C67086fe6B74B7ced9ab9Da30c6A2", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x94Cbb3011f87f0A14D19caaEc155D5985E58E259", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": { + "VOOI": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -26415,78 +1803,261 @@ "rate": "0" } } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WSDM": { + } + } + }, + "ethereum-mainnet-mode-1": { + "offRamp": { + "address": "0xFc2278eBc27B9d205e3DC9F1b88D6D863D71190D", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x9d4d125788A548C2f69fAC7f8C3A64FA21d18C9e", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["wUSDx"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x3c5E62cdFD08e23a0961ff2A3155CaBb96cbc89D", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x3A3649852A518ab180f41f28288c6c9184563616", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "wUSDx"] + }, + "ethereum-mainnet-unichain-1": { + "offRamp": { + "address": "0x53Ad2747B52B81b4369DF29a2C6A0972a1bd65fb", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x95e84C23D5a5a6Ba24D3A2090E4B88d01F30f1a7", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS"] + }, + "ethereum-mainnet-xlayer-1": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-zksync-1": { + "offRamp": { + "address": "0x67b973aBfd440e33f421b6b157706534295572E7", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x9D01e82068a9157976D8c794fbd74cAF395F5A37", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "etherlink-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "hyperliquid-mainnet": { + "offRamp": { + "address": "0x50ceF176C2F39080b15Aa4E7f97f6BE6Fa28c5d1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xfF327Ef3b73346f2AacD6ec02c70440D31fd8319", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xGold", "xSolvBTC"] + }, + "kaia-mainnet": { + "offRamp": { + "address": "0xCEC63FD347d053A335B51b68cDeDd08F8563Ab8E", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x77c70012Dc201E89c9E7597D58cD78a73f58dCc3", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0xF616733641D420207b8F30db9C4cE39684768991", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x35C724666ba31632A56Bad4390eb69f206ab60C7", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "$PAAL", + "1XMM", + "AISTR", + "BANK", + "BARD", + "BETS", + "BKN", + "BOB", + "BONE", + "BR", + "BTR", + "CHEX", + "DOBO", + "EDEN", + "FF", + "FHE", + "IXT", + "JCT", + "LBTC", + "LEASH", + "LEND", + "RIZE", + "SAS", + "SDT", + "SHIB", + "SKYA", + "STABLE", + "SolvBTC", + "SolvBTC.BERA", + "TRADE", + "TREE", + "TURBO", + "TURTLE", + "UNIO", + "USD0", + "USD1", + "USDFI", + "USDO", + "USDf", + "USUAL", + "VOOI", + "VSN", + "WECO", + "WHY", + "WLFI", + "WMTX", + "WSDM", + "brBTC", + "mBTC", + "mwBETH", + "sUSD1+", + "savBTC", + "savUSD", + "uniBTC", + "wUSDx", + "xGold", + "xSolvBTC" + ] + }, + "matic-mainnet": { + "offRamp": { + "address": "0x21159ebdA3E6A2437bCD6ef39853042ACC436D2D", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x1C88e3Fd2B0a8735D1b19A77AA6e2333555BB95c", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "1XMM", + "BETS", + "IXT", + "LAND", + "LEND", + "METO", + "RIZE", + "SolvBTC", + "THE", + "TRADE", + "WECO", + "WSDM", + "xGold", + "xSolvBTC" + ] + }, + "megaeth-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "1000000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "12000000" + "rate": "462963" }, "out": { - "capacity": "1000000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "12000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstPOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "rate": "462963" } } - }, - "xGold": { + } + } + }, + "mind-mainnet": { + "offRamp": { + "address": "0x160E2CeaB31A5fdcC480506746D1d99fB626Cc5D", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x92884F00d64daf778e3A86173d364A184CA532F6", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["FHE"] + }, + "monad-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "plume-mainnet": { + "offRamp": { + "address": "0xAdd62B3cB2D26cE5001784b050A83bB9F1a4fa7f", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xC2f4143E242D0BF0b490DC64D362136c1d068Fb1", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": { + "sUSD1+": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -26499,1074 +2070,1014 @@ "rate": "0" } } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } } } }, - "memento-mainnet": { + "polygon-mainnet-katana": { + "offRamp": { + "address": "0x1C07Ba64819728c9e48796F7514e1DBF92Ca4774", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x81e8503F5f45f1cBd16ca99c7739D69a07af7C0b", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LBTC", "savUSD"] + }, + "sei-mainnet": { + "offRamp": { + "address": "0xB3a0AFcEeb2F19A6f0682558f8B02309c8Be3cB3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x88998f02a6aCacc341fB378F6F5bf9acc0a6eDa3", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "solana-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": [ + "BR", + "FHE", + "ILMT", + "KNET", + "MEW", + "SolvBTC", + "SolvBTC.JUP", + "USELESS", + "WLFI", + "WMTX", + "XLAB", + "elizaOS", + "xSolvBTC" + ] + }, + "soneium-mainnet": { + "offRamp": { + "address": "0x39b8519F8871965DB784218DE0d6bcA3A03b2141", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x0390B87B43974b45e3fE21824A008A3cd46605De", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SKYA", "SolvBTC.JUP"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x1Bb241731Fce5A650934b594D9ee6cCE55E39f32", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xF54f6623f1E714985839ac451BFA8B34007487E0", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LBTC", "mBTC", "wUSDx"] + }, + "stable-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "tac-mainnet": { + "offRamp": { + "address": "0xA27056438FfA1f286AB197488808692F0db93F8B", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "wemix-mainnet": { + "offRamp": { + "address": "0x512CA54a0F6447AC41c07Da3336DFcA042D88A7B", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x9BaFC5E78C0051c7Bcd1EF37FF02fcBd31B37a72", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["una.WEMIX"] + }, + "xdai-mainnet": { + "offRamp": { + "address": "0x53AF5cE4534C39582E6a5E3fD77946E0c3BFe870", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x83AC865c2E18f2CDc1d10126987FfC465e11c0DF", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "celo-mainnet": { + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x3980b6e3d2f23AF4D700d12C42af1B92AB8ea933", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xf27b5D3205fEa8aD6Ce8Fbe3b6178867428E5732", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", - "version": "1.6.0" + "address": "0xF1470F8944f5aA02892Bd621d8bD42F160CB96fd", + "version": "1.5.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0xD5cCB283797A708125C807C63a6E944a99EEd288", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x8B6657F323f5dC8cDB896d08074eA7D31b794609", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x1b531048F438571d3CF6806e55957C361C0b2d75", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "metal-mainnet": { + "ethereum-mainnet-mode-1": { "offRamp": { - "address": "0x8693cdA8E6D3Aee7c9fC258c3E7F648c8E6580c1", + "address": "0xa39CFCB09Ca613ee9f6Fc03c8E0a79566a07b2eB", "version": "1.5.0" }, "onRamp": { - "address": "0xDAa386621aB173C4E788ecebC4F8c2E6EB016819", + "address": "0x5dA58BF4a86b5B43f302D1Fea8A2DaaCe871A99A", "enforceOutOfOrder": false, "version": "1.5.0" } }, - "mind-mainnet": { + "ethereum-mainnet-optimism-1": { "offRamp": { - "address": "0x8FEE869eDD935391B4979F8C79560102A8594B28", + "address": "0xe21C99e57aF6C2B4768442c69445bD181aFCfee5", "version": "1.5.0" }, "onRamp": { - "address": "0x9cb0FF2Ea9110dc8831b39F620811a0da09747D3", + "address": "0x5Cc4b917DfD93E9833cC33BaA38A8B0091d5ade0", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "supportedTokens": ["USDT"] + }, + "ethereum-mainnet-unichain-1": { + "offRamp": { + "address": "0x56D7a82869CBA0b3B4e2c7a18b54C705bd9aa0b1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6cAa43a0D82614a95F8e7D30C358268f464D0B3c", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "mint-mainnet": { + "ethereum-mainnet-worldchain-1": { "offRamp": { - "address": "0x49Aac6Fc36F32aC22867Ac0bAa23E6F2551f8edD", + "address": "0x60dcBAC7CF502bC58524e81f6b558Dc514517f67", "version": "1.5.0" }, "onRamp": { - "address": "0x1Fa3aF677DC1b627f8A57e26b2a55d5F7945F06b", + "address": "0xa841C3aD09133d1d2148b259fe1ceA3bbacbeed8", "enforceOutOfOrder": false, "version": "1.5.0" } }, - "monad-mainnet": { + "ethereum-mainnet-zksync-1": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "address": "0x27f7Af25Ac7482d75207179B42906866A89C6787", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x7171AeF438a34427D255BF323C13416B6a1848F0", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "kaia-mainnet": { + "offRamp": { + "address": "0x0CAb90fdE075F29341df7A7FB91b792e8Beea676", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x130E86D0eF4368aF31763925e89eE53d3bd7B1C6", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x1B12D218280DD1767304A00070101a91f7A61470", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc319484eF6cdA3a7f4D470e660b343FB569e9A1e", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "USDT"] + }, + "matic-mainnet": { + "offRamp": { + "address": "0xd04aF6aB899900D32299e2970457b90Ce8767759", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x42504890DD261Bf17Aa05Dca6C293a6c6225f961", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "soneium-mainnet": { + "offRamp": { + "address": "0x695aAbE79d26FdC309CcFBE594B15094b82CcFd6", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xB3C5D43d6114B99E5Bc79cC340C563DC44A4B2B2", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "core-mainnet": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x35f6c6f50D937A5ec7A1CDe94C5ecaa2843A1E12", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x84500703E377FbfebC7eA8B4568F2156d48eB665", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0xC6C0530f9926B06199861ae6E1c45bCf7391b35E", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xe68e90Cb8c9e7b58c67f7447A45F0E63c5Af6d4a", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x584EA199994799a73F13eA8A2113050a1a96E0e1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x79b875F8546788c1382EC09D3a22dfF9e50E8d36", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0xD95D3654bE8ae12E073e32F39cd8E9d9144d2Cc8", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xa206130E202592737A72c0C04b324aBC78Ca448E", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0xF0fC17a0cb867c9879d1f4Ea4C23E65D5f4fb890", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x00348860Cb152Aa20617a1265343D1989C976575", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x093509d6316f347d7a21169F9fbe0A4eed549e1a", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xC2aa1372998A8Aa25DA50737AbFA2C154D6793d1", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "corn-mainnet": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", "version": "1.6.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", "enforceOutOfOrder": false, "version": "1.6.0" + } + }, + "berachain-mainnet": { + "offRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "version": "1.6.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - }, - "out": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - } - } - } + "onRamp": { + "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "bitcoin-mainnet-bob-1": { + "offRamp": { + "address": "0x4e1254caB1BB7a13663709Eb2a0F394054E5097F", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x250F8295A0d285100CD9f5467f8A54aE0b9e3c61", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "nexon-mainnet-henesys": { + "bsc-mainnet": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", "version": "1.6.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", "enforceOutOfOrder": false, "version": "1.6.0" } }, - "plasma-mainnet": { + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", "version": "1.6.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", "enforceOutOfOrder": false, "version": "1.6.0" + } + }, + "etherlink-mainnet": { + "offRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "version": "1.6.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "RETH": { - "rateLimiterConfig": { - "in": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - }, - "out": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "syrupUSDT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - }, - "out": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "onRamp": { + "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "plume-mainnet": { + "mainnet": { "offRamp": { - "address": "0x109c666A021214C96a7ab7cde7E987F4e7dCD9fE", + "address": "0x4DC347bE828120E9b59ee45946DD2eFf55E20659", "version": "1.5.0" }, "onRamp": { - "address": "0x522f82eE3c4F0249D32b09e2F4c9C51B0F150ffF", + "address": "0x0883eC4F32CaDe330c56e51a9131F7443a0a576A", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["LBTC", "uniBTC"] }, - "polkadot-mainnet-astar": { + "matic-mainnet": { "offRamp": { - "address": "0x33276152d082120F5190362e6E5F6783bbCb2B26", + "address": "0x6Db08b8507351303236CcB47A4176735fda74f84", "version": "1.5.0" }, "onRamp": { - "address": "0xD8E8720709a3d9A18a9B281E6148E94149B2E252", + "address": "0xf01CD02A43DD06403c5316d3D5658B1f91b006B5", "enforceOutOfOrder": false, "version": "1.5.0" + } + }, + "polygon-mainnet-katana": { + "offRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "version": "1.6.0" }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WASTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "2778000000000000000000" - } - } - } + "onRamp": { + "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + } + }, + "cronos-mainnet": { + "mainnet": { + "offRamp": { + "address": "0x305763f90CF335FAae061DA6341533D263B1876f", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x5873C4FfD8A3DdB610e5079cebA63a1C04340A29", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "cronos-zkevm-mainnet": { + "mainnet": { + "offRamp": { + "address": "0xe43D992336f286c9a4d6A9Cd9f65C89771cbC52f", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xf1D0D8f9309dD48Ce46110A474C11908e3B49EA3", + "enforceOutOfOrder": false, + "version": "1.5.0" } - }, - "polygon-mainnet-katana": { + } + }, + "ethereum-mainnet-andromeda-1": { + "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "0xa8c12a859225531254dDef7079030f7DD6992A14", + "address": "0xc6bA5a79991b3775F28259BA551b30eCb0b6D499", "version": "1.5.0" }, "onRamp": { - "address": "0xc5Dbe2055Fa233ece44c99432526F3Fc46cA3FC2", + "address": "0x8d3039fE2400151c06Ae84a18CAf38dD9b6Ce58b", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["SDL"] }, - "ronin-mainnet": { + "mainnet": { "offRamp": { - "address": "0x9a3Ed7007809CfD666999e439076B4Ce4120528D", + "address": "0x1fd37Bf813D0723BEF614bC93d9D2Ce1AcB3228f", "version": "1.5.0" }, "onRamp": { - "address": "0xdC5b578ff3AFcC4A4a6E149892b9472390b50844", + "address": "0xdF5394c57A0570ECe45DE0c0fA2e722A672B9198", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "ANIMA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "APRS": { - "rateLimiterConfig": { - "in": { - "capacity": "30000000000000000000000000", - "isEnabled": true, - "rate": "347222200000000000000" - }, - "out": { - "capacity": "27000000000000000000000000", - "isEnabled": true, - "rate": "312500000000000000000" - } - } - }, - "AXS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BANANA": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "17361110000000000000" - }, - "out": { - "capacity": "1350000000000000000000000", - "isEnabled": true, - "rate": "15625000000000000000" - } - } - }, - "CGX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "LUA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LUAUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "PFVS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "PIXEL": { - "rateLimiterConfig": { - "in": { - "capacity": "300000000000000000000000000", - "isEnabled": true, - "rate": "3472222200000000000000" - }, - "out": { - "capacity": "270000000000000000000000000", - "isEnabled": true, - "rate": "3125000000000000000000" - } - } - }, - "RETH": { - "rateLimiterConfig": { - "in": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - }, - "out": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "4200000000", - "isEnabled": true, - "rate": "48610" - }, - "out": { - "capacity": "3780000000", - "isEnabled": true, - "rate": "43750" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "YGG": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000000", - "isEnabled": true, - "rate": "23148100000000000000" - }, - "out": { - "capacity": "1800000000000000000000000", - "isEnabled": true, - "rate": "20833300000000000000" - } - } - }, - "ZENT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "supportedTokens": ["BONE", "LEASH", "LINK", "SDL", "SHIB"] + } + }, + "ethereum-mainnet-arbitrum-1": { + "0g-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["W0G"] + }, + "apechain-mainnet": { + "offRamp": { + "address": "0x7c04e5396B774758847f408864c9389C18353275", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xDdb06a5c964d38C0AA2119ea7a805583565988d3", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "rootstock-mainnet": { + "aptos-mainnet": { "offRamp": { - "address": "0x34eEc7EcA3Ce1e693028255ebE2063728224a604", + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "avalanche-mainnet": { + "offRamp": { + "address": "0x95095007d5Cc3E7517A1A03c9e228adA5D0bc376", "version": "1.5.0" }, "onRamp": { - "address": "0x34748FbeD8fD8468eD66D53A7D102ce793cB4094", + "address": "0xe80cC83B895ada027b722b78949b296Bd1fC5639", "enforceOutOfOrder": false, "version": "1.5.0" - } + }, + "supportedTokens": [ + "BETS", + "BOLD", + "GHO", + "GRT", + "LEND", + "SDY", + "SHIB", + "SILO", + "SolvBTC", + "USDC", + "USDM", + "VRTX", + "wstLINK", + "xSILO", + "xSolvBTC" + ] }, - "sei-mainnet": { + "berachain-mainnet": { "offRamp": { - "address": "0xc876D50A0Ecc147FC0cEd194cD2b66210d482f9c", + "address": "0xCCeEE160D37eFF0b476dcd8B167CCE9D54359C4b", "version": "1.5.0" }, "onRamp": { - "address": "0x5739E5376702AAc79a53B375ca160EE3C12025E0", + "address": "0xa0792764166C891A1e8033fA6B2786d9a5B197d8", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "supportedTokens": ["BOLD", "DOLO", "sDOLA"] + }, + "bitcoin-mainnet-bob-1": { + "offRamp": { + "address": "0x0c48652a01DFc023c081143A900555a481918929", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6C2B7ea87A7724f8F6A61217aDf3EaB3CfC13FA3", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "bsc-mainnet": { + "offRamp": { + "address": "0x16B9709F8A23B9EB922E8Dde7EaB1Ede7C79F663", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x14bF7b1Ca6b843f386bfDfa76BFd439919b9378D", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "CKP", + "DOBO", + "IXT", + "LAND", + "LEND", + "RDP", + "SDT", + "STABLE", + "STBU", + "SolvBTC", + "USDFI", + "VSN", + "WECO", + "WMTX", + "WSDM", + "mBTC", + "wUSDx", + "xSolvBTC" + ] + }, + "celo-mainnet": { + "offRamp": { + "address": "0x0eA1070B08757Da69a0762ae38D037cdd08C5e98", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x68647D235262873Be5a30fceaA6CAA318a750773", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "shibarium-mainnet": { + "core-mainnet": { "offRamp": { - "address": "0x8B3eEed4948684c3ec1bb60967820f40285018B8", + "address": "0x1fD156b5aD47627a32583037B11E567823612aE6", "version": "1.5.0" }, "onRamp": { - "address": "0x3Ac0D8fe5b4e8d0a95C507CCd83F6A8d73A8c6b1", + "address": "0x8315cb1be59c3fd8A66169F26461648Ba952a68c", "enforceOutOfOrder": false, "version": "1.5.0" + } + }, + "ethereum-mainnet-andromeda-1": { + "offRamp": { + "address": "0xF1A4DE22FF792b0457306C39f4CB5822Ab47bdAE", + "version": "1.5.0" }, - "supportedTokens": { - "SAS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIRO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "onRamp": { + "address": "0xF1e73c37CDa8E47768De2246AEf5eFD4d76330ae", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SDL"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0xb62178f8198905D0Fa6d640Bdb188E4E8143Ac4b", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc1b6287A3292d6469F2D8545877E40A2f75CA9a6", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "APU", + "BETS", + "BOLD", + "DOBO", + "DPI", + "EARNM", + "FLUID", + "GHO", + "GRT", + "IBTC", + "IXT", + "LDY", + "LEND", + "MVI", + "NUON", + "OVER", + "SolvBTC", + "USD+", + "USDC", + "USDM", + "VRTX", + "W0G", + "WETH", + "WHSK", + "WMTX", + "WOLF", + "ZUN", + "clBTC", + "dsETH", + "hyETH", + "sDOLA", + "sINV", + "stTAO", + "suBTC", + "suETH", + "suUSD", + "wOETH", + "wUSDx", + "wstLINK", + "xSolvBTC", + "zunETH", + "zunUSD" + ] + }, + "ethereum-mainnet-blast-1": { + "offRamp": { + "address": "0x40314FeC27C5FCc7AaA05e618802A3fEA8E23Ae3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc5490997680a39A1b4684ce2b668AE8A2eBEC7ee", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["VRTX"] + }, + "ethereum-mainnet-hashkey-1": { + "offRamp": { + "address": "0xd85F0a6c57f3c7BE205fbA48DC007eEf4b97514b", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xA560c1E9E74d4Cb6416e99D3F571A9D949047821", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["WHSK"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x3f1341710E680c95e9b3a0549FFaf9f492682F32", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xB1883c326458A304219037b7C77Ae2dbc061d034", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["GHO", "SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["SolvBTC", "xRPL", "xSolvBTC", "xrETH"] + }, + "ethereum-mainnet-mantle-1": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["VRTX"] + }, + "ethereum-mainnet-mode-1": { + "offRamp": { + "address": "0xa964355d8eBa62E9b043Eb27eEe6d999Ecc69429", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xd236ea4DDE7de1e594021764E2f6Cd8e8cD7F047", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["wUSDx"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x27a971D482335d0f8d1917451390734f7372A4a3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xAFECc7b67c6a8e606e94ce4e2F70D83C2206C2cb", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BOLD", + "IBTC", + "MILO", + "OVER", + "SD", + "USDC", + "USDM", + "WETH", + "ZUN", + "clBTC", + "sDOLA", + "stTAO", + "wUSDx", + "zunETH", + "zunUSD" + ] + }, + "ethereum-mainnet-unichain-1": { + "offRamp": { + "address": "0xbDa25A2450B1295564E8F46aeCe841005CBe2C8A", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x2FBb50dF814A22cb86357C443690CA59965383B5", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC"] + }, + "ethereum-mainnet-xlayer-1": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "solana-mainnet": { + "ethereum-mainnet-zircuit-1": { + "offRamp": { + "address": "0x858D6988b8A98abC4385d7DeeDa04A7227365cdE", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6E2b1bC5C6E1FcD15D83302E2d49e6Ba478FE0fF", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": ["mBTC"] + }, + "ethereum-mainnet-zksync-1": { + "offRamp": { + "address": "0x052CF0c46375287255c71B179b10a7BFFD97502F", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xd67F6713Fa4448548c984a9a7DCFBD13B0fB78D6", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDM"] + }, + "everclear-mainnet": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", "version": "1.6.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", - "enforceOutOfOrder": true, + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, "version": "1.6.0" + } + }, + "kaia-mainnet": { + "offRamp": { + "address": "0xC1657856cfcb4ecC99Ae263f80550F06D1Ece3f9", + "version": "1.5.0" }, - "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "elizaOS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787037037037037037" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787037037037037037" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000", - "isEnabled": true, - "rate": "13880000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "MEW": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - } - } - }, - "OHM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "PEPE": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000", - "isEnabled": true, - "rate": "13888888888888890" - }, - "out": { - "capacity": "50000000000000000000000000000", - "isEnabled": true, - "rate": "13888888888888890000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WFRAGSOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WLFI": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - } + "onRamp": { + "address": "0x1Fe0f6bd28dc2b342D79D95BD7A3b4dc6a3Bf1E4", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "soneium-mainnet": { + "mainnet": { "offRamp": { - "address": "0xdFD8C353044aB175cC96FD4261c2Af3E3AB768a4", + "address": "0x91e46cc5590A4B9182e47f40006140A7077Dec31", "version": "1.5.0" }, "onRamp": { - "address": "0x093844Bd4b26792791cD4038e94Bec70f88CaD63", + "address": "0x67761742ac8A21Ec4D76CA18cbd701e5A6F3Bef3", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "DEGEN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "pufETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SKYA": { + "supportedTokens": [ + "APU", + "BETS", + "BOLD", + "BONE", + "DFX", + "DOBO", + "DOLO", + "DPI", + "EARNM", + "ETHx", + "FHE", + "FLUID", + "GHO", + "IBTC", + "IXT", + "LDY", + "LEASH", + "LEND", + "MVI", + "NPC", + "NUON", + "OVER", + "SD", + "SDL", + "SDT", + "SDY", + "SHIB", + "SILO", + "STABLE", + "STBU", + "SolvBTC", + "USD+", + "USDC", + "USDFI", + "USDM", + "VSN", + "W0G", + "WECO", + "WETH", + "WFRAGSOL", + "WMTX", + "WOLF", + "WSDM", + "ZUN", + "clBTC", + "dsETH", + "egETH", + "hyETH", + "mBTC", + "mDLP", + "mmETH", + "mstETH", + "mswETH", + "pufETH", + "sDOLA", + "sINV", + "stTAO", + "suBTC", + "suETH", + "suUSD", + "syrupUSDC", + "tETH", + "uniBTC", + "wOETH", + "wUSDx", + "wstLINK", + "xRPL", + "xSILO", + "xSolvBTC", + "xrETH", + "zunETH", + "zunUSD" + ] + }, + "matic-mainnet": { + "offRamp": { + "address": "0xcabc2D71dC3172a154A5A34cD706B050e0ef9b6f", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6087d6C33946670232DF09Fe93eECbaEa3D6864d", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "DFX", + "EARNM", + "IXT", + "LAND", + "LEND", + "SDM", + "STBU", + "SolvBTC", + "USDC", + "USDM", + "WECO", + "WSDM", + "wstLINK", + "xSolvBTC" + ] + }, + "mind-mainnet": { + "offRamp": { + "address": "0xa424E1662ba9fE03b14425287F055D2809e4fd1e", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x12a4b20D69FAe9b55CD5FA20D5f1DBede1D623F3", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "monad-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "W0G": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -27579,490 +3090,400 @@ "rate": "0" } } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "60000000000000000000", - "isEnabled": true, - "rate": "694440000000000" - } - } - }, - "WASTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "2778000000000000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "60000000000000000000", - "isEnabled": true, - "rate": "694440000000000" - } - } } } }, - "sonic-mainnet": { + "plasma-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["BOLD", "FLUID", "GHO"] + }, + "sei-mainnet": { + "offRamp": { + "address": "0x017513A8cA43992938e7FA72033Ee29A0E2C029e", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x080a40d9265Cc00604c9759a77fe1B3D67800eb8", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["VRTX"] + }, + "shibarium-mainnet": { + "offRamp": { + "address": "0xF9b99cD977e97634C61565b13DFf07e06c962236", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xFCdca0011177138b2d9Fd4dE874F2a14d25E6b7D", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "solana-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["FLUID", "USDC", "WFRAGSOL", "WMTX"] + }, + "soneium-mainnet": { + "offRamp": { + "address": "0xbdda3e069dA6D2D47fe66445AeadBb81fEfaC5d2", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xbB7c7AAf81D359C9367d31eDFDBF6C2Af73F17F6", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "sonic-mainnet": { + "offRamp": { + "address": "0xf88166dB9E9B7c59068f2dC9bD5d53A719a41e68", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6cb060f7f8b0F8C58A4032C82dCf917c6d438f46", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BOLD", "SILO", "VRTX", "mBTC", "wUSDx", "xSILO"] + }, + "stable-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "wemix-mainnet": { + "offRamp": { + "address": "0x893c14bA328A49336a188F972f997C0d7286B8E4", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x52e51f245e600C6A87Ef2090d607D2a0eAedA1a6", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["una.WEMIX"] + }, + "xdai-mainnet": { + "offRamp": { + "address": "0xeE53872d1C695933B34cE0a11B58613CBBf37e20", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc7d6B885d8A4286E6311F79227430b7862311cd3", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["GHO"] + } + }, + "ethereum-mainnet-base-1": { + "0g-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["W0G"] + }, + "apechain-mainnet": { + "offRamp": { + "address": "0x03EE839151E48CEE69f5e4e8D28B35CE2Eae0446", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x88cED349C02630b073D9879d30F79D6eD56B9268", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "aptos-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["LINK"] + }, + "avalanche-mainnet": { + "offRamp": { + "address": "0x61C3f6d72c80A3D1790b213c4cB58c3d4aaFccDF", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x4be6E0F97EA849FF80773af7a317356E6c646FD7", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BOLD", + "BYTES", + "GHO", + "GRT", + "LBTC", + "LEND", + "MYST", + "Memento", + "ORNG", + "SHIB", + "SolvBTC", + "USDC", + "USDM", + "VRTX", + "wstLINK", + "xSolvBTC" + ] + }, + "berachain-mainnet": { + "offRamp": { + "address": "0x5204a4c69E0551fFd6376C3558efF24f7ecD1af1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x048F2f9961A93bB87cD5B35a01088343aA85c332", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BOLD", "BR", "sDOLA"] + }, + "bitcoin-mainnet-bob-1": { + "offRamp": { + "address": "0xc18eF0E347cAB790dEBb3BB746511983039F72b6", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xEA20366b66C1FD262Eb600Cb4C721C39AC5D2C68", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "USDT", "xSolvBTC"] + }, + "bittensor-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "bsc-mainnet": { + "offRamp": { + "address": "0x45d524b6Fe99C005C52C65c578dc0e02d9751083", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xE5FD5A0ec3657Ad58E875518e73F6264E00Eb754", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "$PAAL", + "AISTR", + "BETS", + "BKN", + "BR", + "CHEX", + "DOBO", + "IXT", + "LBTC", + "LEND", + "RIZE", + "SAS", + "SKYA", + "SNOW", + "SolvBTC", + "TRADE", + "UNIO", + "USDO", + "WHY", + "WMTX", + "wUSDx", + "xGold", + "xSolvBTC" + ] + }, + "celo-mainnet": { + "offRamp": { + "address": "0x73A600F80061627dcC68ABc4f33063eB51aA6e96", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xf2Bf69d4A687d2c38DE865eABD611648dAccad93", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + }, + "core-mainnet": { + "offRamp": { + "address": "0x260aC27e82166e57e887A497Bb22f829bc90Da7E", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x75d1A886eCc7404321851f6A5B1f936269f044D6", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "corn-mainnet": { "offRamp": { - "address": "0xB45cF8df3AAa50199B7AaabD345119BAd1b8d977", + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x7D38c6363d5E4DFD500a691Bc34878b383F58d93", "version": "1.5.0" }, "onRamp": { - "address": "0x4fdAaDe22bd05537EeaB204cF7319589CE595D6a", + "address": "0x9D0ffA76C7F82C34Be313b5bFc6d42A72dA8CA69", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "egETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "mstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - }, - "out": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - } - } + "supportedTokens": [ + "APU", + "BETS", + "BOLD", + "DOBO", + "DPI", + "EARNM", + "FLUID", + "GHO", + "GRT", + "IBTC", + "IXT", + "LDY", + "LEND", + "MVI", + "NUON", + "OVER", + "SolvBTC", + "USD+", + "USDC", + "USDM", + "VRTX", + "W0G", + "WETH", + "WHSK", + "WMTX", + "WOLF", + "ZUN", + "clBTC", + "dsETH", + "hyETH", + "sDOLA", + "sINV", + "stTAO", + "suBTC", + "suETH", + "suUSD", + "wOETH", + "wUSDx", + "wstLINK", + "xSolvBTC", + "zunETH", + "zunUSD" + ] }, - "superseed-mainnet": { + "ethereum-mainnet-blast-1": { "offRamp": { - "address": "0x3c5990484D4D7b728Ae875d001E97469284210C1", + "address": "0x941F0E2E0556aCf60fE0f09972f599d9F8916F01", "version": "1.5.0" }, "onRamp": { - "address": "0x486170Bca7fE5126AFeaF171d3a60A211bF2C44C", + "address": "0x9A59832b85217C20b17a990A45BD5d0F3de36266", "enforceOutOfOrder": false, "version": "1.5.0" - } + }, + "supportedTokens": ["LINK", "VRTX"] }, - "tac-mainnet": { + "ethereum-mainnet-hashkey-1": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", - "version": "1.6.0" + "address": "0xD3680ae2d6b8373C01114D20e2109C3DC657913E", + "version": "1.5.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0x588990D1A7a54d23Aa1c2586CB9D6F053814A285", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "RETH": { - "rateLimiterConfig": { - "in": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - }, - "out": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - } - } - }, - "tETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - } - } + "supportedTokens": ["USDT", "WHSK"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x53aB03801579793B31eDD3Afc16fc9A25EdDfdAb", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xbe6B55A0D720c4106bfca7beA3908a77ce3C31A2", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["GHO", "SolvBTC", "xSolvBTC"] }, - "wemix-mainnet": { + "ethereum-mainnet-linea-1": { "offRamp": { - "address": "0xc1EcCE580B2C96f4fd202fB7c2a259ECe19a1bF2", - "version": "1.5.0" + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" }, "onRamp": { - "address": "0xdEFeADd30D5BFD403d86245b43e39a73d76423cC", + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "una.USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "300000000000", - "isEnabled": true, - "rate": "83330000" - }, - "out": { - "capacity": "300000000000", - "isEnabled": true, - "rate": "83330000" - } - } - }, - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["AISTR", "LsETH", "SolvBTC", "xSolvBTC"] }, - "xdai-mainnet": { + "ethereum-mainnet-mantle-1": { "offRamp": { - "address": "0x70C705ff3eCAA04c8c61d581a59a168a1c49c2ec", - "version": "1.5.0" + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" }, "onRamp": { - "address": "0xf50B9A46C394bD98491ce163d420222d8030F6F0", + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" }, "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, "GHO": { "rateLimiterConfig": { "in": { @@ -28077,7 +3498,7 @@ } } }, - "LEASH": { + "VRTX": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -28090,1495 +3511,1079 @@ "rate": "0" } } - }, - "REG": { + } + } + }, + "ethereum-mainnet-mode-1": { + "offRamp": { + "address": "0x639Dc04368006544eba7CbC959f3e4361bfEAB0d", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xEB50Fc6F57AAc6bf060A2Dfc6479fED592e6e184", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BMX", "LINK", "wUSDx"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x18095fbD53184A50C2BB3929a6c62Ca328732062", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x362E6bE957c18e268ad91046CA6b47EB09AD98C1", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BOLD", + "CRTV", + "IBTC", + "OVER", + "USDC", + "USDM", + "USDT", + "WETH", + "ZUN", + "clBTC", + "sDOLA", + "sINV", + "stTAO", + "wUSDx", + "zunETH", + "zunUSD" + ] + }, + "ethereum-mainnet-scroll-1": { + "offRamp": { + "address": "0xAA2805A3B6Fc019B2F00E00F09b42e7273cD18E9", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc06dc9FA031F7EaCcB08285aAA632730dD700Ce5", + "enforceOutOfOrder": true, + "version": "1.5.0" + } + }, + "ethereum-mainnet-unichain-1": { + "offRamp": { + "address": "0xe4E567386E8DC83E81763466B1d0eC4E1b97a4D7", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x1c179c2C67953478966A6b460AB4873585b2F341", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC"] + }, + "ethereum-mainnet-xlayer-1": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-zksync-1": { + "offRamp": { + "address": "0x90e04B0871Ba9781DcD869251B7a6A101d08f13D", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x757DaD0B4017fca8E3399B4B3b23e0a6587723D1", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDM"] + }, + "etherlink-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "everclear-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "hyperliquid-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "kaia-mainnet": { + "offRamp": { + "address": "0xD4736362efd058b0d48359bAD2034E945A5a907C", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x31389D2162B5829EE73ecf5F00299d95534eAC52", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0xCA04169671A81E4fB8768cfaD46c347ae65371F1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x56b30A0Dcd8dc87Ec08b80FA09502bAB801fa78e", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "$PAAL", + "AISTR", + "APU", + "BETS", + "BKN", + "BOLD", + "BONE", + "BR", + "BYTES", + "CHEX", + "DIP", + "DOBO", + "DPI", + "EARNM", + "FLUID", + "GEN", + "GHO", + "IBTC", + "IXT", + "JASMY", + "LBTC", + "LDY", + "LEASH", + "LEND", + "LINK", + "LsETH", + "MEEM", + "MVI", + "MYST", + "Memento", + "NEIRO", + "NUON", + "OVER", + "RIZE", + "SAS", + "SHIB", + "SKYA", + "STABUL", + "SXT", + "SolvBTC", + "TRADE", + "UNIO", + "USD+", + "USD0", + "USDC", + "USDM", + "USDO", + "USDT", + "USUAL", + "W0G", + "WETH", + "WMTX", + "WOLF", + "XSWAP", + "ZUN", + "ZeUSD", + "brBTC", + "clBTC", + "dsETH", + "hyETH", + "oXAUT", + "sDOLA", + "sINV", + "stTAO", + "suBTC", + "suETH", + "suUSD", + "syrupUSDC", + "tETH", + "uniBTC", + "wOETH", + "wUSDx", + "wstLINK", + "xGold", + "xSolvBTC", + "zBTC", + "zunETH", + "zunUSD" + ] + }, + "matic-mainnet": { + "offRamp": { + "address": "0x74d574D11977fC8D40f8590C419504cbE178ADB7", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xd3Bde678BB706Cf727A512515C254BcF021dD203", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BYTES", + "CRTV", + "EARNM", + "IXT", + "LEND", + "LYP", + "Memento", + "RIZE", + "STABUL", + "SolvBTC", + "TRADE", + "USDC", + "USDM", + "XTFBRICK1", + "XTFCLOBOND", + "wstLINK", + "xGold", + "xSolvBTC" + ] + }, + "megaeth-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "50000000000000000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "14000000000000000000" + "rate": "462963" }, "out": { - "capacity": "50000000000000000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "14000000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "rate": "462963" } } } } }, - "xdc-mainnet": { + "memento-mainnet": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", "version": "1.6.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDf": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["XTFBRICK1", "XTFCLOBOND"] }, - "zora-mainnet": { + "monad-mainnet": { "offRamp": { - "address": "0x5e24de8F7Ccb3E1e204707573a672823d88C559F", + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "plasma-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["BOLD", "FLUID", "GHO"] + }, + "polygon-mainnet-katana": { + "offRamp": { + "address": "0xeFf089F24BAEd3F84918b6dDb265620B97247D9D", "version": "1.5.0" }, "onRamp": { - "address": "0xc46e2F17c04f2C880Ea56a0c69c4520AdB4aBF88", + "address": "0x7898d0B2EDCF7a79969e2868A708109eB4dB287E", "enforceOutOfOrder": false, "version": "1.5.0" - } - } - }, - "matic-mainnet": { - "apechain-mainnet": { + }, + "supportedTokens": ["LBTC"] + }, + "ronin-mainnet": { "offRamp": { - "address": "0xBb331Ac82A67d28b05386ea8762eECd014433dc9", + "address": "0x0A44Db4366385483cbCc9460fA55a75345553286", "version": "1.5.0" }, "onRamp": { - "address": "0xb9494347a3D13Fb499a72e95b9DAbF6F20C18768", + "address": "0x5dE068a87f081Ea01932769807CA569265E4f622", "enforceOutOfOrder": false, "version": "1.5.0" - } + }, + "supportedTokens": ["LINK"] }, - "avalanche-mainnet": { + "sei-mainnet": { "offRamp": { - "address": "0x35c1Bb5A9c2F3fa8f8dFF470a6bE7d362CeA1ef3", + "address": "0x6D1EeF3Dfb4e8B6df481a52C8657246942aE1Da9", "version": "1.5.0" }, "onRamp": { - "address": "0x56cb9Cd82553Bd8157e6504020c38f6DA4971717", + "address": "0xbd852E81D7425c00dA09b2181beC99703b1a27db", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstPOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "supportedTokens": ["VRTX"] + }, + "shibarium-mainnet": { + "offRamp": { + "address": "0x25f8Fc7a0917ea9Bbf72205B18F4f285d2bf1504", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xAC58a3a17D61B5D8233d73300A694F5D7A20Df4B", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["CANNED", "CHIKA", "DAMN", "FEED", "LUISA", "NEKO", "SAS", "SHIPA", "SNOW", "USAGI", "WOW"] + }, + "solana-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["FLUID", "LINK", "MEW", "MICHI", "USDC", "WMTX", "YNE", "elizaOS", "pippin", "zBTC"] + }, + "soneium-mainnet": { + "offRamp": { + "address": "0xd8Fc838D5a50F9b56a1c01bb4b78c9945eEC2926", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xD531E3424CED77fE86C78F046508125cA6786D26", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SKYA"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x9c32DfE3237d280Dc703Ee8D42aae379b7BDea73", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xBc8e6602aEa1FE65Dc5656b77360ddAbBB52f894", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BMX", "BOLD", "LBTC", "USDT", "VRTX", "wUSDx", "zBTC"] + }, + "stable-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "tac-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "berachain-mainnet": { + "wemix-mainnet": { "offRamp": { - "address": "0xb572AF6Ee0199079a1a253E3a8dC71ace13c8C14", + "address": "0x9001D632834FAf4c6ce717c5CcAd7e0c4b0803c0", "version": "1.5.0" }, "onRamp": { - "address": "0x1203DE1eA440B9acBbe2Fc76784fB5916F4B21AF", + "address": "0x5D519191f0BC6aC6d8497B41113551d79Aa65c9C", "enforceOutOfOrder": false, "version": "1.5.0" } }, - "bitcoin-mainnet-bob-1": { + "xdai-mainnet": { "offRamp": { - "address": "0x2a612eDAa990918518Ba3cC59EeBF898CB1e501A", + "address": "0x300977dBA924af14E166B31F4926892B1f310661", "version": "1.5.0" }, "onRamp": { - "address": "0xf9d899fe9B0D785B88D7FD9EAc368B34bFbF6f3f", + "address": "0xDcFB24AEbcB9Edfb6746a045DDcae402381F984B", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } + "supportedTokens": ["GHO"] }, + "xdc-mainnet": { + "offRamp": { + "address": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + } + }, + "ethereum-mainnet-blast-1": { "bsc-mainnet": { "offRamp": { - "address": "0xE58074f8F56E23836f088Ac8b4f3882c1b4CAcbb", + "address": "0x9A9f3714b517231869b97F3b49E2ba1009499d9b", "version": "1.5.0" }, "onRamp": { - "address": "0x164507757F7d5Ab35C6af44EeEB099F5be29Da57", + "address": "0x01D1A2Ed2053e410177f8E762aF635ee78b7a581", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "1XMM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LAND": { - "rateLimiterConfig": { - "in": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - }, - "out": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "METO": { - "rateLimiterConfig": { - "in": { - "capacity": "76923077000000000000000000", - "isEnabled": true, - "rate": "21367520000000000000000" - }, - "out": { - "capacity": "76923077000000000000000000", - "isEnabled": true, - "rate": "21367520000000000000000" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "THE": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "417000000000000000000" - }, - "out": { - "capacity": "750000000000000000000000", - "isEnabled": true, - "rate": "417000000000000000000" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } } }, - "celo-mainnet": { + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x8e4E966a3f6b3aB56185800a2afFe75CCf7B4DfD", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x28f7E57cEE31241B4B8B72e6b710c4dC2e9bEb28", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["VRTX"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x5837622b622D3c88Faf5491324575f5c0BB40001", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xAbBC1fC0C919ecFb0220e90749111e0619abf79A", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LINK", "VRTX"] + }, + "mainnet": { + "offRamp": { + "address": "0xFf094AC08B0AA8Ab3d29e034a51199a0ddE3d8C8", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xEa8112530cA10945C2aA976f8F615582Af9B70fa", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB"] + } + }, + "ethereum-mainnet-hashkey-1": { + "bsc-mainnet": { + "offRamp": { + "address": "0xf6E4Ac1362Cdce9DcbE3174436c1d99a0D9DFF8D", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x3eDDAE2d5169e38c45975fBe994c428C3728B915", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["enzoBTC"] + }, + "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "0xDf1F2a04c0e572D68E3E0D14d6ed3864921FE3f3", + "address": "0x88C4cBeF7685d3bfB68322e85135D14EdD41Be7B", "version": "1.5.0" }, "onRamp": { - "address": "0x608e3993854607dE4FC8f7926ab6b7c5AB3cA8Fc", + "address": "0xcd204E694a12488040d83d34D6c1e2b0E9495fDC", "enforceOutOfOrder": false, "version": "1.5.0" - } + }, + "supportedTokens": ["WHSK"] }, - "corn-mainnet": { + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0x1C8902998ceaf082C14b60610a7c383c4C58Dc99", + "address": "0x41c5362418f5629EA3E5c333FD569D64000CdE65", "version": "1.5.0" }, "onRamp": { - "address": "0xdD131De9C7dE71e1859cF5e8153EfCc2fB93E554", + "address": "0x13484FB069f074A1584De1724c5c17A94BfD2aa3", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDT", "WHSK"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x83abF9471d636EcB84643b89247546B18C33C6B8", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xb69B49A21f88cCc572684D2a574d7EE8B18C868e", "enforceOutOfOrder": false, "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + }, + "mainnet": { + "offRamp": { + "address": "0xDd31064764B7683Fc38e13759B8050b6c59528d1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x66e8c5D59E77eEBd8289D5BB76222F04f571BC67", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + } + }, + "ethereum-mainnet-ink-1": { + "aptos-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": true, + "version": "1.6.0" } }, - "ethereum-mainnet-arbitrum-1": { + "avalanche-mainnet": { "offRamp": { - "address": "0x60f2788225CeE4a94f8E7589931d5A14Cbc4367d", + "address": "0xC44E893cEf294Eff9e56430ceE5C4C0f53a92584", "version": "1.5.0" }, "onRamp": { - "address": "0x13263aC754d1e29430930672E3C0019f2BC44Ba2", + "address": "0x9411f7e2DBb687F304d95684476744dA79D9bfF2", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DFX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27778000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27778000000000000000000" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LAND": { - "rateLimiterConfig": { - "in": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - }, - "out": { - "capacity": "20000000000000000000000", - "isEnabled": true, - "rate": "5550000000000000000" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SDM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STBU": { - "rateLimiterConfig": { - "in": { - "capacity": "2", - "isEnabled": true, - "rate": "1" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WSDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "12000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "supportedTokens": ["GHO", "SolvBTC", "xSolvBTC"] + }, + "bitcoin-mainnet-bob-1": { + "offRamp": { + "address": "0xc9b80FB78375B1571cb517168B68dDEfF45A888A", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xD92bcA767B5EbdF91FE6aF2c6A25B6Fb584BAC9F", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "bsc-mainnet": { + "offRamp": { + "address": "0xdD86Db1e3D27b06aDbF4C449fB66c6ac3C79d74B", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x363788B5d323c57fa7469BE8FBbB99e554731e52", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "celo-mainnet": { + "offRamp": { + "address": "0x92329665dD07F897fe1cc38d20e1a86FD6394f23", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6314dFcF1430aF590e388Cb77D963c23406553f6", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "ethereum-mainnet-base-1": { + "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "0xF4a9Dbb7f3FBa02e3a244B464e459C32B63857F1", + "address": "0x74946257b64f72Ae1126cBBE3cDBB539616FBfA1", "version": "1.5.0" }, "onRamp": { - "address": "0xD26A4E0c664E72e3c29E634867191cB1cb9AF570", + "address": "0x61F512c264e297E9Cc1517DCfF51ef193c055060", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BYTES": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CRTV": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27778000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000000", - "isEnabled": true, - "rate": "27778000000000000000000" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LYP": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "83333333333300000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "83333333333300000000" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABUL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "TRADE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "xGold": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "XTFBRICK1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "XTFCLOBOND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["GHO", "SolvBTC", "xSolvBTC"] }, - "ethereum-mainnet-ink-1": { + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0xA2d83fFE785C5733D61540C03f78F0c69c35c5eF", + "address": "0xfc960D01fD45A396E7874383580fDe1E3c726490", "version": "1.5.0" }, "onRamp": { - "address": "0x213Ecb8e4105271817465820909c90c0d33c0C73", + "address": "0x271315a46CD922C6977aC91ba425ed421279B783", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { + "supportedTokens": ["GHO", "SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-mantle-1": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "GHO": { "rateLimiterConfig": { "in": { - "capacity": "2500000000000000000", + "capacity": "1500000000000000000000000", "isEnabled": true, - "rate": "115740000000000" + "rate": "300000000000000000000" }, "out": { - "capacity": "2500000000000000000", + "capacity": "1500000000000000000000000", "isEnabled": true, - "rate": "115740000000000" + "rate": "300000000000000000000" } } } } }, - "ethereum-mainnet-linea-1": { + "ethereum-mainnet-xlayer-1": { "offRamp": { - "address": "0xc195B549f3B7Ee890B5F2C244CEfa88C71adb414", + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-zksync-1": { + "offRamp": { + "address": "0xeF4D86b49b83Bd2A41CD54ef019A066BB5ADe4D2", "version": "1.5.0" }, "onRamp": { - "address": "0x8Eb6d67f4104acb6b7B956D5DE42a34ECe25e07a", - "enforceOutOfOrder": true, + "address": "0xEa54FBd030CbA34a3939d77F3060cA09d1D5e7D8", + "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "mainnet": { + "offRamp": { + "address": "0x809E132A7C3A689a7026971be32697B6cD507f63", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x288Ad43143e135C4e350B23162c538E83fF1FCF5", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["GHO", "SolvBTC", "YBTC.B", "brBTC", "uniBTC", "wstETH", "xSolvBTC"] + }, + "matic-mainnet": { + "offRamp": { + "address": "0x5b429dEF74a08688C43DFC36F3af703CE265Dd4a", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x022A5Caf1F0437aDE29b28c53D82F6Ad103B323d", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "monad-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["wstETH"] + }, + "plasma-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["wstETH"] + }, + "sei-mainnet": { + "offRamp": { + "address": "0x496D74c0E33325f370167bF1A4767cbBd9A6a1D3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x77247cB0da96BC02BBb19dD9cAe1505349738b88", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "soneium-mainnet": { + "offRamp": { + "address": "0xCb4bD34201c7306fCA4cC791Ae21a6EE94bF88A2", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x1986e0583709e978811b434Ac00ca806529E8D5b", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x55dfEB67b429A4073b27c49C3Ed7916fbeEF6E4B", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x9da03ab4d9D126cDCC83fbb84cD2197776302D35", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "ethereum-mainnet-optimism-1": { + "xdai-mainnet": { "offRamp": { - "address": "0x805c292775Be43b10Cc744ea7E81d9939a08cEa4", + "address": "0xc20FF92f9E5F283192DAc1C19cd66f58eF0525D1", "version": "1.5.0" }, "onRamp": { - "address": "0x868B71490B36674B3B9006fa8711C6fA26A26631", + "address": "0x94d035286419C98874dCE62B79C077D91716B7c7", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CRTV": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - } + "supportedTokens": ["GHO"] + } + }, + "ethereum-mainnet-linea-1": { + "aptos-mainnet": { + "offRamp": { + "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", + "enforceOutOfOrder": true, + "version": "1.6.0" } }, - "ethereum-mainnet-unichain-1": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": [ + "SolvBTC", + "avBTC", + "avETH", + "avETHx", + "avUSD", + "avUSDx", + "savBTC", + "savETH", + "savUSD", + "xSolvBTC" + ] + }, + "bitcoin-mainnet-bob-1": { + "offRamp": { + "address": "0x62a61c033c0d86DCd3A14791afcace022eB54471", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x078BDD1462D6418b2b432Ba190531b3AC89EC6eC", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "bsc-mainnet": { + "offRamp": { + "address": "0xa7e7cb9185Ff4A17f54fEDeD3eeb8d09935a879d", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xd0F398854358f8846596C78f8363F3d182e77cC8", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["AISTR", "SolvBTC", "TURTLE", "savBTC", "savUSD", "xSolvBTC"] + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["SolvBTC", "xRPL", "xSolvBTC", "xrETH"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["AISTR", "LsETH", "SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-optimism-1": { "offRamp": { - "address": "0x354B294816C09A5a5a2832a8B61d78EdEF2FD94e", + "address": "0x26d57442604D1b2A2196f8c93E6E72BB7FAF93Bd", "version": "1.5.0" }, "onRamp": { - "address": "0xea602eDf1f43dd8437D31D2EA6D1c68F8f5825d9", + "address": "0xF4F5ddc54aAe8d2489F9Fe82060e44020A152200", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["rsETH"] }, - "ethereum-mainnet-zksync-1": { + "ethereum-mainnet-scroll-1": { "offRamp": { - "address": "0xbd52D1661D195c4311363251ad387E504589971f", + "address": "0xa3Ea5eB15711041fd28950438b5a682392b54e6C", "version": "1.5.0" }, "onRamp": { - "address": "0x2655242E3200b99201f7d62CfF4aF04bBCfCa44C", - "enforceOutOfOrder": false, + "address": "0x30ebb71dAa827bEAE71EE325A77Ca47dAED7Ec9B", + "enforceOutOfOrder": true, "version": "1.5.0" + } + }, + "ethereum-mainnet-xlayer-1": { + "offRamp": { + "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", + "version": "1.6.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "onRamp": { + "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "mainnet": { + "ethereum-mainnet-zircuit-1": { "offRamp": { - "address": "0xa06e68a11d5694316Cc819f2FFD02663e3314C7C", + "address": "0xd2803dDE6B53d4F637B2C47F2a27f01Ec299963b", "version": "1.5.0" }, "onRamp": { - "address": "0x1DAcBae00c779913e6E9fc1A3323FbA4847ba53C", - "enforceOutOfOrder": false, + "address": "0x0d222d900969e7058Be60318f8A99502560Ed560", + "enforceOutOfOrder": true, "version": "1.5.0" }, - "supportedTokens": { - "1XMM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BETS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "DFX": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - }, - "out": { - "capacity": "5000000000000000000000000", - "isEnabled": true, - "rate": "57000000000000000000" - } - } - }, - "EARNM": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000000", - "isEnabled": true, - "rate": "13889000000000000000000" - }, - "out": { - "capacity": "50000000000000000000000000", - "isEnabled": true, - "rate": "13889000000000000000000" - } - } - }, - "IXT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "Memento": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "138880000000000000000" - } - } - }, - "OSIS": { - "rateLimiterConfig": { - "in": { - "capacity": "16667000000000000000000", - "isEnabled": true, - "rate": "4600000000000000000" - }, - "out": { - "capacity": "16667000000000000000000", - "isEnabled": true, - "rate": "4600000000000000000" - } - } - }, - "REG": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - } - } - }, - "RIZE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SOIL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { + "supportedTokens": ["rsETH"] + }, + "mainnet": { + "offRamp": { + "address": "0x656e2aA127Cb15815a90Ef70c6AA7Ed449D689ce", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x69AbB6043BBEA2467f41CCD0144d1b3b4ECd20f4", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "AISTR", + "BONE", + "LEASH", + "LsETH", + "SHIB", + "SolvBTC", + "TURTLE", + "WETH", + "avBTC", + "avETH", + "avETHx", + "avUSD", + "avUSDx", + "rsETH", + "savBTC", + "savETH", + "savUSD", + "xRPL", + "xSolvBTC", + "xrETH" + ] + }, + "matic-mainnet": { + "offRamp": { + "address": "0x7990fc4f985520Aa6A2e70C4F0f4583f753eeFf2", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x3B89e864ea4b075D36409fE0d3f507afA6198A1d", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "plasma-mainnet": { + "offRamp": { + "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "xdai-mainnet": { + "offRamp": { + "address": "0x61b7492A40AE4c403629703a38d24851CAA1e7E4", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x1bADBe95bEe68D3a74EC08621256ddDBe6eAd3F9", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + } + }, + "ethereum-mainnet-mantle-1": { + "aptos-mainnet": { + "offRamp": { + "address": "0x010771998A1F4736BD844939d0bf01ac5cA0f8fa", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "avalanche-mainnet": { + "offRamp": { + "address": "0x010771998A1F4736BD844939d0bf01ac5cA0f8fa", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "GHO": { "rateLimiterConfig": { "in": { - "capacity": "2500000000000000000", + "capacity": "1500000000000000000000000", "isEnabled": true, - "rate": "115740000000000" + "rate": "300000000000000000000" }, "out": { - "capacity": "2500000000000000000", + "capacity": "1500000000000000000000000", "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "STABUL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "rate": "300000000000000000000" } } }, - "TRADE": { + "VRTX": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -29591,8 +4596,21 @@ "rate": "0" } } - }, - "USDC": { + } + } + }, + "bsc-mainnet": { + "offRamp": { + "address": "0x7dA0421bedd25eb7CbA7eFdB6108Bfc2916De79e", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xB608c110c35f2871c0e1ED30DA1848603bC18694", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": { + "VOOI": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -29605,78 +4623,47 @@ "rate": "0" } } - }, - "USDM": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - }, - "out": { - "capacity": "1000000000000000000000000", - "isEnabled": true, - "rate": "11600000000000000000" - } - } - }, - "WECO": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - }, - "out": { - "capacity": "500000000000000000000000000", - "isEnabled": true, - "rate": "34720000000000000000000" - } - } - }, - "WSDM": { + } + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x010771998A1F4736BD844939d0bf01ac5cA0f8fa", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["VRTX"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x010771998A1F4736BD844939d0bf01ac5cA0f8fa", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "GHO": { "rateLimiterConfig": { "in": { - "capacity": "1000000000000", + "capacity": "1500000000000000000000000", "isEnabled": true, - "rate": "12000000" + "rate": "300000000000000000000" }, "out": { - "capacity": "1000000000000", + "capacity": "1500000000000000000000000", "isEnabled": true, - "rate": "12000000" - } - } - }, - "wstLINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstPOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "rate": "300000000000000000000" } } }, - "xGold": { + "VRTX": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -29689,2421 +4676,3412 @@ "rate": "0" } } - }, - "xSolvBTC": { + } + } + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x010771998A1F4736BD844939d0bf01ac5cA0f8fa", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "GHO": { "rateLimiterConfig": { "in": { - "capacity": "2500000000000000000", + "capacity": "1500000000000000000000000", "isEnabled": true, - "rate": "115740000000000" + "rate": "300000000000000000000" }, "out": { - "capacity": "2500000000000000000", + "capacity": "1500000000000000000000000", "isEnabled": true, - "rate": "115740000000000" + "rate": "300000000000000000000" } } } } }, - "memento-mainnet": { + "ethereum-mainnet-xlayer-1": { + "offRamp": { + "address": "0x010771998A1F4736BD844939d0bf01ac5cA0f8fa", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x010771998A1F4736BD844939d0bf01ac5cA0f8fa", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x4e2C866885b65F67E7A2b8382ECF0164BB19Aa00", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["BONE", "LEASH", "SHIB", "USD1", "syrupUSDT", "uniBTC"] + } + }, + "ethereum-mainnet-mode-1": { + "bsc-mainnet": { + "offRamp": { + "address": "0xdfA601DA2163Ca2C77Eb32126E6B7A97024f6181", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xeb7E8c40E95Cd31666359AaeB1F2CccaAB935643", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["wUSDx"] + }, + "celo-mainnet": { + "offRamp": { + "address": "0xB8A51Bff88c09Aa1a66A7874110FDe970e6cA9A5", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xf81c7385064bBB58a01004E1eEC4D9B0785AECa7", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x0Cb870C12013c2d5743585F85b298e129cE57203", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xb2e694efcDa0aeB81700019c3047F92fC3bb520E", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["wUSDx"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x30612D8fb7EcD05ECb863560BA8806d88e8BbFAF", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x347A070EA1B04bc2b4A8f14320688C277022C90e", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BMX", "LINK", "wUSDx"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x4adcD1FB4ec76A3c9960E048f81C19A51B2eAC49", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x7AB4329D19A0255DA90Ee8dbAA60f8f0cB7950C1", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["wUSDx"] + }, + "mainnet": { + "offRamp": { + "address": "0xb1caBa234721b8F12C545B3dC25B3F87f6a9c91B", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x7d2aF78868993a5a86676BA639eC0412709707D9", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "sDAI", "wUSDx"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x411ce3551a5be63c3Cb30374Cee336c3b3F84111", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xD5Fa7faca37be1644f88bB17A0E4f0df12279339", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BMX", "wUSDx"] + } + }, + "ethereum-mainnet-optimism-1": { + "aptos-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "avalanche-mainnet": { + "offRamp": { + "address": "0xF8E38B4503418659F791F2135c4912F85BFB7988", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xB9D655Ad5ba80036725d6c753Fa6AF0454cBF630", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "BOLD", "USDC", "USDM"] + }, + "bsc-mainnet": { + "offRamp": { + "address": "0x51f37b538aD2Bcb9Eaf884859BF7C5Ec58AEc885", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xfC51a4CF925f202d86c6092cda879689d2C17201", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "wUSDx"] + }, + "celo-mainnet": { + "offRamp": { + "address": "0xa6ed91b1708fA53895f9b0d7C1435625f1B3C440", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x746ddB61Af7B1516B819F6d81AcD729e4C867a55", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + }, + "core-mainnet": { + "offRamp": { + "address": "0xf83EEDD718629e7EC76EccfA8e861E2316930CFa", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x16F9Be2317C358E0b21EF09da8AB1EBCEf298D1B", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0xEB3d6956BCf7b1E29634C8cd182fC9FA740Bce34", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6bA81b83091A23e8F2AA173B2b939fAf9E320DfB", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BOLD", + "IBTC", + "MILO", + "OVER", + "SD", + "USDC", + "USDM", + "WETH", + "ZUN", + "clBTC", + "sDOLA", + "stTAO", + "wUSDx", + "zunETH", + "zunUSD" + ] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x519ee6B83f57df95486aeA6E26819cb7b4B8ee99", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xfE11cfC957cCa331192EAC60040b442303CcA0a9", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BOLD", + "CRTV", + "IBTC", + "OVER", + "USDC", + "USDM", + "USDT", + "WETH", + "ZUN", + "clBTC", + "sDOLA", + "sINV", + "stTAO", + "wUSDx", + "zunETH", + "zunUSD" + ] + }, + "ethereum-mainnet-hashkey-1": { + "offRamp": { + "address": "0xE12102b65CBC13966116cB6Edbd257F967B5c56B", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc404E8e7d26569bEC0e23e4868187f1024494AD7", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0xa3a854E5942273b59A8aba07e929F8a0fbd18447", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x4AE52fD7Eae88fAcD86A3F16C063AB59941a2eeE", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": ["rsETH"] + }, + "ethereum-mainnet-mode-1": { + "offRamp": { + "address": "0x5a4BEeafd345264360E6894a6bc5F54a70814E68", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc6d9Cb39e34D83d21A021504024887A0e96D4e94", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["wUSDx"] + }, + "ethereum-mainnet-unichain-1": { + "offRamp": { + "address": "0xe4770Ce5024f19e76D995cE3b1e7d03aD9540E73", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x80e396e5447805432695eb551B7C9283408aa51A", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC"] + }, + "ethereum-mainnet-zircuit-1": { + "offRamp": { + "address": "0xccc197F0e5eF2e399F5b9Ab35cc3EA58F15Fd6BA", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xE85fc09997Da4E08Ef7466E7819b2d9477fca035", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": ["rsETH"] + }, + "ethereum-mainnet-zksync-1": { + "offRamp": { + "address": "0x8d86CEDE37C93CD48C5d146aaF03f750714Fe127", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x793Aa8C07195C6a07F75C5cbDF17070564e69499", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDM"] + }, + "mainnet": { + "offRamp": { + "address": "0x9979c2dfEcA9051Cf7f08274d978984B2dB12C60", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xE4C51Dc01A4E0aB14c7a7a2ed1655E9CF8A3E698", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BOLD", + "BONE", + "ETHx", + "IBTC", + "LEASH", + "OVER", + "SD", + "SHIB", + "USDC", + "USDM", + "USDT", + "WETH", + "ZUN", + "clBTC", + "rsETH", + "sDOLA", + "sINV", + "stTAO", + "uniBTC", + "wUSDx", + "zunETH", + "zunUSD" + ] + }, + "matic-mainnet": { + "offRamp": { + "address": "0x4BA0A3bD1E2b70b2fe165A53219e7eF6376849a4", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x9c725164b60E3f6d4d5b7A2841C63E9FD0988805", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "CRTV", "USDC", "USDM"] + }, + "monad-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "sei-mainnet": { + "offRamp": { + "address": "0x3d6b220C9e3498b9062716339599b741F9c3D1E2", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xC5d7B7806ace4590655D14fC503079e4956Bc243", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "shibarium-mainnet": { + "offRamp": { + "address": "0xBe811105E3BAc916F339E3079F687e2BFe72E51d", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x7f2340EAFC71bd92cb99638Fd55032BdB31d9300", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "solana-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["USDC"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0xd2e7b4e9dA1a969C160524Ca27E4AdB5d26e36d0", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xED13113a043C823d550d2505aa9a97e40766Dc49", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BOLD", "USDT", "wUSDx"] + }, + "wemix-mainnet": { + "offRamp": { + "address": "0x2f40dCCb74d8B2dd7af065232a06778f2D019375", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6Dbc8D4e5556FD0B82bB0D67c94D0fA1cd288AbD", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["una.WEMIX"] + }, + "xdai-mainnet": { + "offRamp": { + "address": "0x01449040D92D75c58FaDc9Bc1c0eadc70C550484", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x604a9dda2e27D56cfCe457E437a61f4ED0De9dE6", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "ethereum-mainnet-polygon-zkevm-1": { + "mainnet": { + "offRamp": { + "address": "0xF89685b62ac1FB22Cc0f9bFBB3015954A3751744", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xD2a9F49Aa973fDd42Edbb24E01Baa8163ac3141c", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "ethereum-mainnet-scroll-1": { + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x9fdD3015f049F32188C2AB1EA28a9f96a6f23596", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x86Add4b1A0c32CeF910B76816FACb9beC5912a70", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0x5834e1C639418A4973391126576f550A6996836a", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x05d472b114D57E6035089A58Fa997A7940D29a23", + "enforceOutOfOrder": true, + "version": "1.5.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x77601F272dd2d6481Ac3a13942075388097245Fb", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x28cCF73F7982c1786b84e243FFbD47F4fB8ae43d", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BOLD", "BONE", "LEASH", "LINK", "SHIB"] + } + }, + "ethereum-mainnet-taiko-1": { + "mainnet": { + "offRamp": { + "address": "0xe9e7943cd76B34fB90eEdfDFa7E15921a956906f", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x861c7816Ebd335319eB66cb047707C95e9AA0cdC", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + } + }, + "ethereum-mainnet-unichain-1": { + "avalanche-mainnet": { + "offRamp": { + "address": "0xC487bE5D3A0f19f4034804221A3Ab53d752f0eb2", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x0cb33060FDF6C63f47922b20dA1bA36F26c8B85C", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC"] + }, + "bsc-mainnet": { + "offRamp": { + "address": "0xf5D0d2C5E34142cd666DDBef39857dF02B57327B", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xb673646BF3CACdD3D7a7f7EB53051A675922E369", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS"] + }, + "celo-mainnet": { + "offRamp": { + "address": "0x06D1A3C7dA103AaD2bbDDC4C34643932b549Bee4", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc4F901dDF548c689C3D072F0507EAAb763AB5589", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x1233Bf363497E7624299d6d76ae36b914C0fAf3D", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xD5877a4E3331c54cbD0B53dA3cD16a5Ce128c731", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x69B29aEf2857adF1D4F9cBE7b002810564cA4699", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x470Bd9B8d5A19f6f9E6A2c707705Bc13F28d075B", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0xCf2bB21F36b66c71650B9E3C032CbdE93A61b8D3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x5b8DD1c02c67d43fBbA0b6d2245eb0833d6f8e29", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC"] + }, + "mainnet": { + "offRamp": { + "address": "0x240D14E6550f1ac8F518C2AEd886c905207bAA9B", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x139839036FF1Df22f47427740f40fE300184Fb8a", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC", "uniBTC"] + }, + "matic-mainnet": { + "offRamp": { + "address": "0x46962f43107c7A248074922fBaac2C3F5a32F4a2", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6D343834A43873D9F86Ad3B7E96009837685b88E", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "USDC"] + }, + "solana-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["USDC"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x357ED60610da18ef5453d2fdA6b71e1c30Bad824", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x68B0c56b4120c3B40ACf6809cE7c3c5458E03daF", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "ethereum-mainnet-worldchain-1": { + "berachain-mainnet": { + "offRamp": { + "address": "0xbB53fa082b28a45f92cb015Cc9c817b9BE0Eab8c", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xa40D3b99113A171F898EF5A0d6809bd985e45DB6", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "celo-mainnet": { + "offRamp": { + "address": "0x97D60eF016feaF3253E2f43262fe638a3060cA9a", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xEc5069dBA6d83E5FD683eeB3b5de06F43893e1a6", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-zksync-1": { + "offRamp": { + "address": "0x44F39eeE704E3D89acD6D019b061592B129185e8", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x3d5ea8Aa2a9515a9c31900E0C9AFE5896C8fD960", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x6E514bBa9f3bA098d907Ac10D577b2FB7C9F0ac3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x0129211377B414Cad2c624C40c342FAffB3B3F0F", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["WLD", "oXAUT"] + }, + "solana-mainnet": { + "offRamp": { + "address": "0xB2d6c057391d2a3dA572f7B8016440F7A7AD1287", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xABF586910586b8dcbdF92f1C5e2Ae14106f3DD16", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + } + }, + "ethereum-mainnet-xlayer-1": { + "aptos-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "avalanche-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "bsc-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-mantle-1": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["brBTC", "uniBTC"] + }, + "plasma-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "xdai-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + } + }, + "ethereum-mainnet-zircuit-1": { + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x2aacae6564e66004fBe2700E12B010eDa82991fA", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x0D24D9567BF373135208Fc00486ee21BF4c6545C", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["mBTC"] + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0x69D7a7CBb0E03fCb89983391B4A82231A493E008", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x9E6A9088E3152318e1FFaDadb35ebD46879eF243", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": ["rsETH"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x9269e4D4aC9aCc39c5A529A276CC6f6c6c30bbF9", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xF12FE0a9F6d2835AEa502cb1a5b7BbC32245BB13", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["rsETH"] + }, + "mainnet": { + "offRamp": { + "address": "0xa257EDEB2cA0d42081E1EFb285ac4c974953Cb29", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xD3Bd3D50E3593AFE8B5A50C1B3F83c21D64c10d2", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "LEASH", "SHIB", "mBTC", "rsETH"] + } + }, + "ethereum-mainnet-zksync-1": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x8f41aA10C96Be2749dA47fd0d84e507E34e9c930", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x17D9B1FC307cbF16380f2d835e0654Fe6921BE1E", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDM"] + }, + "bitcoin-mainnet-bob-1": { + "offRamp": { + "address": "0x24aFa3596C6682EbFF3D8505745bA441083e484f", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x4Cb8d5b7D4E95673bCb855cb17D79C992dd84782", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "bsc-mainnet": { + "offRamp": { + "address": "0xacE8A9a195d70834e39BD14b4b6973716f545f3a", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x0cEb5972a6BA5Ed57caB94d71179b741b7D69c74", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "celo-mainnet": { + "offRamp": { + "address": "0x9ff0f85AF7BE9526dC99b6ee91f5BCe5b391808A", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x366CE743c19E8cb2966C3DDe2Ae1216EF9A76d6D", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0xd448c815C421fFBd770C2d3B9a9cBa4E33E3885c", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x66EcB7c8c122d74f19Fc28b275f213Ef8991B7AB", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDM"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x8d05075F2dc7D8eFFD9171664f78628c18d68F22", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x73B95bd224a9F5054B87577104106cD36237BaDc", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDM"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x4308CD2D9FE580A123C5915b24307EE10650BDAF", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xf3840012905833c8F1A39a51697ADB2F0faC0B2c", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x906e63ff31558eE1DAf6C1404e153b621CD26996", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xbD9148D567260c4580f00A6dd5a2bB0e626eFd62", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDM"] + }, + "ethereum-mainnet-worldchain-1": { + "offRamp": { + "address": "0xA2398c5600FB5c8eAC093ebC9Ef55D34F5Ff4EaA", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x1CaBaF3CDDEf4b53cc53481aCfBc722F225f148E", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "mainnet": { "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "address": "0x6BACb854483Ffe310F5Ac08879868E96AE0DC000", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xD1B33FAd3fF7a793EE39473f865630e3b6371086", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "SolvBTC", "USDM", "xSolvBTC"] + }, + "matic-mainnet": { + "offRamp": { + "address": "0x83ca2A80010CD1Ea1323aFf23d88294327d1Cef3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x37CbA662E9c373F2166CcA0D9c576dd089D7209a", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "USDM", "xSolvBTC"] + } + }, + "etherlink-mainnet": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x3f63716b703518ad436F1F3061a56AF52D8de169", "version": "1.6.0" }, "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "address": "0xD4D2841Ac332075833AE86eb49ce7aF9f353cd21", "enforceOutOfOrder": false, "version": "1.6.0" + } + }, + "berachain-mainnet": { + "offRamp": { + "address": "0x3f63716b703518ad436F1F3061a56AF52D8de169", + "version": "1.6.0" }, - "supportedTokens": { - "XTFBRICK1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "XTFCLOBOND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "onRamp": { + "address": "0xD4D2841Ac332075833AE86eb49ce7aF9f353cd21", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "plume-mainnet": { + "bsc-mainnet": { "offRamp": { - "address": "0xB2651Fe276fbA4A6F14F4094272929A6125255a3", - "version": "1.5.0" + "address": "0x3f63716b703518ad436F1F3061a56AF52D8de169", + "version": "1.6.0" }, "onRamp": { - "address": "0x6581f896c3B8BFAb9d5ba01d7Cfd50568959FF82", + "address": "0xD4D2841Ac332075833AE86eb49ce7aF9f353cd21", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" } }, - "sei-mainnet": { + "corn-mainnet": { "offRamp": { - "address": "0x814f5bB435F8ad9437D5ac0d8aBCd97E095f9879", - "version": "1.5.0" + "address": "0x3f63716b703518ad436F1F3061a56AF52D8de169", + "version": "1.6.0" }, "onRamp": { - "address": "0x020ec1e27a46822bC0a2DEdc48793958fDAfC185", + "address": "0xD4D2841Ac332075833AE86eb49ce7aF9f353cd21", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" + } + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x3f63716b703518ad436F1F3061a56AF52D8de169", + "version": "1.6.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "onRamp": { + "address": "0xD4D2841Ac332075833AE86eb49ce7aF9f353cd21", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x3f63716b703518ad436F1F3061a56AF52D8de169", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD4D2841Ac332075833AE86eb49ce7aF9f353cd21", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + } + }, + "everclear-mainnet": { + "avalanche-mainnet": { + "offRamp": { + "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, "solana-mainnet": { "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", "version": "1.6.0" }, "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", "enforceOutOfOrder": true, "version": "1.6.0" + } + }, + "tac-mainnet": { + "offRamp": { + "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", + "version": "1.6.0" }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "onRamp": { + "address": "0xdd8aF6046349EDFD40123E0b616286cEC08010ed", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + } + }, + "fraxtal-mainnet": { + "mainnet": { + "offRamp": { + "address": "0x1BE8714ce5E35B38Cd977eadaC1307B9B77Efd0d", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x00D0E4e85ccCaF37F1a10d7738ACFC59803B21fD", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "hedera-mainnet": { + "mainnet": { + "offRamp": { + "address": "0x6e6bA22dd2A558cA00B7799F2771938AfEEE65B9", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6480de6257c3b0Bc249f2653551964693AA914c0", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["xGold"] + } + }, + "hemi-mainnet": { + "mainnet": { + "offRamp": { + "address": "0xC3bE3153C3ad495c381a7Bad4C30701745Ac8b3c", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xBD4ee0f8a4F658D0e7da8811Eb6ec0CC02baA974", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "hyperliquid-mainnet": { + "0g-mainnet": { + "offRamp": { + "address": "0x70003d849A20e33997fea69bBc8a366D6ab0E131", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x72f6000D70B291C67bED898214156d01383274b1", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "soneium-mainnet": { + "berachain-mainnet": { "offRamp": { - "address": "0x1bE40B0e51cC5C353842b94e2E3d2D99c7760865", + "address": "0xdef8217620734C531D69E0534C9881A1311c5791", "version": "1.5.0" }, "onRamp": { - "address": "0xf0D403fF3f04C479929A8412ae244B42Bbe070F4", + "address": "0x4122fe199B6e489a89f54c67245Be33bf602935F", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } } }, - "sonic-mainnet": { + "bsc-mainnet": { "offRamp": { - "address": "0x6dF61364fD9335063f975eF4917a703891CcA45C", + "address": "0x50ceF176C2F39080b15Aa4E7f97f6BE6Fa28c5d1", "version": "1.5.0" }, "onRamp": { - "address": "0x126441fEA96cC466E31fc46957ca4e675D0700f9", + "address": "0xfF327Ef3b73346f2AacD6ec02c70440D31fd8319", "enforceOutOfOrder": false, "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xGold", "xSolvBTC"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x70003d849A20e33997fea69bBc8a366D6ab0E131", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x72f6000D70B291C67bED898214156d01383274b1", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "wemix-mainnet": { + "kaia-mainnet": { "offRamp": { - "address": "0xd357Bee1Ff4B1cce7dc0d953a9E5613476781732", + "address": "0x69699AAB9aDB591e1c5024Fda290E3650761ab9d", "version": "1.5.0" }, "onRamp": { - "address": "0x9363330c6d807a1393c1fd35893c64d26931CDe6", + "address": "0xD5A4260733a802e64Cf3A642410fFaED4468907e", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } } }, - "xdai-mainnet": { + "mainnet": { "offRamp": { - "address": "0x9e2e4e397226f347d11D3fF8469d0c3FFa750C3B", + "address": "0xf69F5e554E6D3D90DC3a221121ffEf1ee8bf5B2A", "version": "1.5.0" }, "onRamp": { - "address": "0xcc4A8CFd756895d91B476Dd5461286b300914aBf", - "enforceOutOfOrder": false, + "address": "0x375dDf245FB9951A1D1D4EF516Abd7D2B521238F", + "enforceOutOfOrder": true, "version": "1.5.0" }, - "supportedTokens": { - "REG": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - } - } - } - } - } - }, - "memento-mainnet": { - "ethereum-mainnet-base-1": { + "supportedTokens": ["BOLD", "SolvBTC", "VSN", "brBTC", "kHYPE", "syrupUSDC", "uniBTC", "xGold", "xSolvBTC"] + }, + "solana-mainnet": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "address": "0x70003d849A20e33997fea69bBc8a366D6ab0E131", "version": "1.6.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", - "enforceOutOfOrder": false, + "address": "0x72f6000D70B291C67bED898214156d01383274b1", + "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "XTFBRICK1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "XTFCLOBOND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, + "supportedTokens": ["WHLP"] + } + }, + "jovay-mainnet": { "mainnet": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", "version": "1.6.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0x9b04018b5285FF16F3967Af108Bdc72423d547cC", "enforceOutOfOrder": false, "version": "1.6.0" - } + }, + "supportedTokens": ["LINK"] }, "matic-mainnet": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", "version": "1.6.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "address": "0x9b04018b5285FF16F3967Af108Bdc72423d547cC", "enforceOutOfOrder": false, "version": "1.6.0" + } + } + }, + "kaia-mainnet": { + "bsc-mainnet": { + "offRamp": { + "address": "0x55b2d9272511Efe642fA3Fd5Bc0F5aAE21852f56", + "version": "1.5.0" }, - "supportedTokens": { - "XTFBRICK1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "XTFCLOBOND": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "onRamp": { + "address": "0x014353cCf0C2932F3Fee5A65fa92368b3BFD36ed", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "solana-mainnet": { + "celo-mainnet": { "offRamp": { - "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", - "version": "1.6.0" + "address": "0x6A849EDe87fd30B89ca88c02ec4705A78Ae46584", + "version": "1.5.0" }, "onRamp": { - "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", - "enforceOutOfOrder": true, - "version": "1.6.0" + "address": "0x1D1F8987e77bfe15B0803C6c1667f04E003F8771", + "enforceOutOfOrder": false, + "version": "1.5.0" } - } - }, - "metal-mainnet": { - "mainnet": { + }, + "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "0xd41A38a8372D1Ac745B54aE0bE09b7e0076b6A45", + "address": "0x07a0E5E6782B60aD2b0Be9ab6ca44670526Fe217", "version": "1.5.0" }, "onRamp": { - "address": "0x512c58F427BEFE54BF8dcB0579119DDE43e1929B", + "address": "0x92f05d54E4500f432F26F52aB30F87B6b39F9e26", "enforceOutOfOrder": false, "version": "1.5.0" } - } - }, - "mind-mainnet": { - "bsc-mainnet": { + }, + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0x92a7A4b2E2c242661f88be40788A7cfA8F0dd7F4", + "address": "0x48C28947b4b4b3231304e1F0D1c96e2bc8de41cd", "version": "1.5.0" }, "onRamp": { - "address": "0x7d9CA4bF88c0567c65186810Cf62f55504a5D086", + "address": "0xDdf18F563455001791fC3E0a512B417431672a47", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } } }, - "ethereum-mainnet-arbitrum-1": { + "hyperliquid-mainnet": { "offRamp": { - "address": "0x1011d2CA716fDf9cCb358c118164e887048a3B5C", + "address": "0x09D12E3aC4Ac49c778C0da6a9F2536413cd378b1", "version": "1.5.0" }, "onRamp": { - "address": "0x7edb203cde6ba240e2a8f14E07875C86239c36aF", + "address": "0x63098bAF7AFa14C6351AAF739Da193ff599727Df", "enforceOutOfOrder": false, "version": "1.5.0" } }, "mainnet": { "offRamp": { - "address": "0x50fF86d32A0774f0370848A1B4583fc83FdA0070", + "address": "0x59a65c7A78A0757b6e27905f9C0e21831b25df51", "version": "1.5.0" }, "onRamp": { - "address": "0xe69a1e9c2A0931D31593B201BD0CD5Bd39692e70", + "address": "0x21c04748372cFFB7565328afA8a8B23c8d65Ef9E", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "supportedTokens": ["USDO"] + } + }, + "lens-mainnet": { + "mainnet": { + "offRamp": { + "address": "0x064bDf3699E17e79E56DF65508170339cD73EB7e", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xdaC19bddEf396c222ecDb9109C9E5993a19cd5d5", + "enforceOutOfOrder": false, + "version": "1.5.0" } } }, - "mint-mainnet": { + "lisk-mainnet": { "mainnet": { "offRamp": { - "address": "0xE646B92d6239ec4B11348EB516dbd1b336cb13dE", + "address": "0x9Efcf5b21969E845A285a9cDB74E7C91F93aBa14", "version": "1.5.0" }, "onRamp": { - "address": "0x6e05AfFFD2D44e1703e1ff5c0A24bee10f0781b6", + "address": "0x1F262f3BB509657D8816f9BfF5Ae58334E8504f5", "enforceOutOfOrder": false, "version": "1.5.0" } } }, - "monad-mainnet": { - "avalanche-mainnet": { + "mainnet": { + "0g-mainnet": { "offRamp": { - "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", "version": "1.6.0" }, "onRamp": { - "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } + "supportedTokens": ["LINK", "USDC", "USDT", "W0G", "wstETH"] }, - "bsc-mainnet": { + "ab-mainnet": { "offRamp": { - "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", "version": "1.6.0" }, "onRamp": { - "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", "enforceOutOfOrder": false, "version": "1.6.0" }, + "supportedTokens": ["LINK", "USD1"] + }, + "abstract-mainnet": { + "offRamp": { + "address": "0x9f0E818A8DDDf48C52d5c94D55079E3617d55181", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x266e520E272FCca3cE46A379a06Dc5ba62717b8F", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, "supportedTokens": { - "LBTC": { + "wstETH": { "rateLimiterConfig": { "in": { - "capacity": "5000000000", + "capacity": "300000000000000000000", "isEnabled": true, - "rate": "462963" + "rate": "3472000000000000" }, "out": { - "capacity": "5000000000", + "capacity": "500000000000000000000", "isEnabled": true, - "rate": "462963" + "rate": "5787000000000000" } } } } }, - "ethereum-mainnet-arbitrum-1": { + "apechain-mainnet": { "offRamp": { - "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", - "version": "1.6.0" + "address": "0x7115F0fB22e0A85133C06b50aDc3B90b335ea175", + "version": "1.5.0" }, "onRamp": { - "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "address": "0x48F836a7697c0082B2Ecb4B2639f6da79de21980", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" } }, - "ethereum-mainnet-base-1": { + "aptos-mainnet": { "offRamp": { - "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", "version": "1.6.0" }, "onRamp": { - "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", - "enforceOutOfOrder": false, + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } + "supportedTokens": ["LINK", "USD1", "brBTC", "uniBTC"] }, - "ethereum-mainnet-optimism-1": { + "avalanche-mainnet": { "offRamp": { - "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", - "version": "1.6.0" + "address": "0xd98E80C79a15E4dbaF4C40B6cCDF690fe619BFBb", + "version": "1.5.0" }, "onRamp": { - "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "address": "0xaFd31C0C78785aDF53E4c185670bfd5376249d8A", "enforceOutOfOrder": false, - "version": "1.6.0" - } + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BOLD", + "BONE", + "BYTES", + "EmCH", + "GHO", + "LBTC", + "LEASH", + "LEND", + "MYST", + "Memento", + "SDY", + "SHIB", + "SILO", + "SolvBTC", + "TREE", + "USDC", + "USDM", + "YBTC.B", + "avBTC", + "avETH", + "avETHx", + "avUSD", + "avUSDx", + "oXAUT", + "savBTC", + "savETH", + "savUSD", + "tETH", + "wstLINK", + "wstPOL", + "xSILO", + "xSolvBTC" + ] }, - "mainnet": { + "berachain-mainnet": { "offRamp": { - "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", - "version": "1.6.0" + "address": "0xA627F208c5c32e5638c64147d0aC98bb40F758f0", + "version": "1.5.0" }, "onRamp": { - "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "address": "0xBeFfEF56Cd6FA063d2e04E126cF1b93269886c42", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - }, - "out": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - } - } - } + "supportedTokens": [ + "BOLD", + "BR", + "DOLO", + "LBTC", + "SolvBTC", + "SolvBTC.BERA", + "brBTC", + "pufETH", + "sDOLA", + "uniBTC", + "xSolvBTC" + ] + }, + "binance-smart-chain-mainnet-opbnb-1": { + "offRamp": { + "address": "0xe79705E9f6842223C9b07B70119f3468E2962162", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xffbEC42C001f0E54924078C6D36412128bBC4330", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "polygon-mainnet-katana": { + "bitcoin-mainnet-bitlayer-1": { "offRamp": { - "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", - "version": "1.6.0" + "address": "0x3B45dd27E0cF84F1af98DEaBDc8f96303475ef58", + "version": "1.5.0" }, "onRamp": { - "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "address": "0x4FB5407d6911DaA0B8bde58A754E7D01CB8b05c5", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } + "supportedTokens": ["BTR", "USDC", "USDT", "WETH", "YBTC.B", "uniBTC", "wstETH"] }, - "solana-mainnet": { + "bitcoin-mainnet-bob-1": { "offRamp": { - "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", - "version": "1.6.0" + "address": "0xdE81f1627ef2F6E23A2C0f338623C78c10EA57AC", + "version": "1.5.0" }, "onRamp": { - "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "address": "0x1B960560324c03db5565545B353198fdd07A195d", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BOB", "SolvBTC", "SolvBTC.BERA", "USDC", "USDT", "uniBTC", "xSolvBTC"] + }, + "bitcoin-mainnet-botanix": { + "offRamp": { + "address": "0x64A5c64945c72bc46DF52c82Cfce9161b888578B", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x86768e4e4B2E3C1CF812D5C8A7c7becFA4c8D486", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + }, + "bitcoin-mainnet-bsquared-1": { + "offRamp": { + "address": "0xF3AC96642F9BA5De3BBc864d609E3F534dD3b7F9", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xddF4b4aF7A9603869C90189EFa8826683D0D234b", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["uniBTC"] + }, + "bitcoin-merlin-mainnet": { + "offRamp": { + "address": "0x5B6D2998EEF5cBBa7e8345B08Dd41AecEC5EACA5", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x20fD5ab74D519df395f41c958D982BecB6b64432", "enforceOutOfOrder": true, - "version": "1.6.0" + "version": "1.5.0" } }, - "sonic-mainnet": { + "bittensor-mainnet": { "offRamp": { - "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", "version": "1.6.0" }, "onRamp": { - "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", "enforceOutOfOrder": false, "version": "1.6.0" + } + }, + "bsc-mainnet": { + "offRamp": { + "address": "0x66d84fedED0e51aeB47ceD1BB2fc0221Ae8D7C12", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x948306C220Ac325fa9392A6E601042A3CD0b480d", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "$PAAL", + "1XMM", + "AISTR", + "BANK", + "BARD", + "BETS", + "BKN", + "BOB", + "BONE", + "BR", + "BTR", + "CHEX", + "DOBO", + "EDEN", + "FF", + "FHE", + "IXT", + "JCT", + "LBTC", + "LEASH", + "LEND", + "RIZE", + "SAS", + "SDT", + "SHIB", + "SKYA", + "STABLE", + "SolvBTC", + "SolvBTC.BERA", + "TRADE", + "TREE", + "TURBO", + "TURTLE", + "UNIO", + "USD0", + "USD1", + "USDFI", + "USDO", + "USDf", + "USUAL", + "VOOI", + "VSN", + "WECO", + "WHY", + "WLFI", + "WMTX", + "WSDM", + "brBTC", + "mBTC", + "mwBETH", + "sUSD1+", + "savBTC", + "savUSD", + "uniBTC", + "wUSDx", + "xGold", + "xSolvBTC" + ] + }, + "celo-mainnet": { + "offRamp": { + "address": "0x794aE32b63b8a82a6e2Ec5017bbC6bfbddA5ce96", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x741599d9a5a1bfC40A22f530fbCd85E2718e9F90", + "enforceOutOfOrder": false, + "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } - } - }, - "nexon-mainnet-henesys": { - "avalanche-mainnet": { + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "USDT"] + }, + "core-mainnet": { "offRamp": { - "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", - "version": "1.6.0" + "address": "0xdE66080eABE390198b8918cb3F61e1869dbC8079", + "version": "1.5.0" }, "onRamp": { - "address": "0x9b04018b5285FF16F3967Af108Bdc72423d547cC", + "address": "0xa6D806e4EB8726542cf536518fC47f39d68cCb48", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" } }, - "mainnet": { + "corn-mainnet": { "offRamp": { - "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", - "version": "1.6.0" + "address": "0xb0F5b6DB1157719795eCCd9C6023C66bB2ec414F", + "version": "1.5.0" }, "onRamp": { - "address": "0x9b04018b5285FF16F3967Af108Bdc72423d547cC", + "address": "0x7B78f8D16C4ae6E51c29295D58f05dCC67180A2b", "enforceOutOfOrder": false, - "version": "1.6.0" - } - } - }, - "plasma-mainnet": { - "aptos-mainnet": { + "version": "1.5.0" + }, + "supportedTokens": ["LBTC", "uniBTC"] + }, + "cronos-mainnet": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0xAe2A2A088A8F85A2DB90A61BD463433985C437F0", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", - "enforceOutOfOrder": true, - "version": "1.6.0" + "address": "0x03CB4C67D01a78F44289541281E57C33E6b834d9", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "avalanche-mainnet": { + "cronos-zkevm-mainnet": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0xcdcA3F3aa3A4df41a3DAF885e3E25666Ee96D7e4", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "address": "0x8b858ED23502611aB86109717C8842A7A8f117ec", "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "version": "1.5.0" } }, - "bitcoin-mainnet-bitlayer-1": { + "ethereum-mainnet-andromeda-1": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0x330349112e13232131Da51f9f3b153d825f65e61", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "address": "0x75d536eED32f4c8Bb39F4B0c992163f5BA49B84e", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" }, - "supportedTokens": { - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BONE", "LEASH", "LINK", "SDL", "SHIB"] }, "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0xdf615eF8D4C64d0ED8Fd7824BBEd2f6a10245aC9", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "address": "0x69eCC4E2D8ea56E2d0a05bF57f4Fd6aEE7f2c284", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } + "supportedTokens": [ + "APU", + "BETS", + "BOLD", + "BONE", + "DFX", + "DOBO", + "DOLO", + "DPI", + "EARNM", + "ETHx", + "FHE", + "FLUID", + "GHO", + "IBTC", + "IXT", + "LDY", + "LEASH", + "LEND", + "MVI", + "NPC", + "NUON", + "OVER", + "SD", + "SDL", + "SDT", + "SDY", + "SHIB", + "SILO", + "STABLE", + "STBU", + "SolvBTC", + "USD+", + "USDC", + "USDFI", + "USDM", + "VSN", + "W0G", + "WECO", + "WETH", + "WFRAGSOL", + "WMTX", + "WOLF", + "WSDM", + "ZUN", + "clBTC", + "dsETH", + "egETH", + "hyETH", + "mBTC", + "mDLP", + "mmETH", + "mstETH", + "mswETH", + "pufETH", + "sDOLA", + "sINV", + "stTAO", + "suBTC", + "suETH", + "suUSD", + "syrupUSDC", + "tETH", + "uniBTC", + "wOETH", + "wUSDx", + "wstLINK", + "xRPL", + "xSILO", + "xSolvBTC", + "xrETH", + "zunETH", + "zunUSD" + ] }, "ethereum-mainnet-base-1": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0x6B4B6359Dd5B47Cdb030E5921456D2a0625a9EbD", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "address": "0xb8a882f3B88bd52D1Ff56A873bfDB84b70431937", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } + "supportedTokens": [ + "$PAAL", + "AISTR", + "APU", + "BETS", + "BKN", + "BOLD", + "BONE", + "BR", + "BYTES", + "CHEX", + "DIP", + "DOBO", + "DPI", + "EARNM", + "FLUID", + "GEN", + "GHO", + "IBTC", + "IXT", + "JASMY", + "LBTC", + "LDY", + "LEASH", + "LEND", + "LINK", + "LsETH", + "MEEM", + "MVI", + "MYST", + "Memento", + "NEIRO", + "NUON", + "OVER", + "RIZE", + "SAS", + "SHIB", + "SKYA", + "STABUL", + "SXT", + "SolvBTC", + "TRADE", + "UNIO", + "USD+", + "USD0", + "USDC", + "USDM", + "USDO", + "USDT", + "USUAL", + "W0G", + "WETH", + "WMTX", + "WOLF", + "XSWAP", + "ZUN", + "ZeUSD", + "brBTC", + "clBTC", + "dsETH", + "hyETH", + "oXAUT", + "sDOLA", + "sINV", + "stTAO", + "suBTC", + "suETH", + "suUSD", + "syrupUSDC", + "tETH", + "uniBTC", + "wOETH", + "wUSDx", + "wstLINK", + "xGold", + "xSolvBTC", + "zBTC", + "zunETH", + "zunUSD" + ] }, - "ethereum-mainnet-ink-1": { + "ethereum-mainnet-blast-1": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0xF4468E56179e6EF59d6f5B133D9355AAD91Ea9ae", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "address": "0x6751cA96b769129dFE6eB8E349c310deCEDb4e36", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" }, - "supportedTokens": { - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - }, - "out": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - } - } - } - } + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB"] }, - "ethereum-mainnet-linea-1": { + "ethereum-mainnet-hashkey-1": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0xf2EB4CE854C8C0AAea6080Ef825efA5A84a8656a", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x61B4B85364a2609177D2C498ff864E01a63148a5", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USDT"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x0F1B1A46AdeadF3C0D583AC86f40bC9e0b2e4Ba2", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "address": "0xEEe2AE1d0Fa6D1D38BBBa555A7C7B90C8734a8e2", "enforceOutOfOrder": false, - "version": "1.6.0" - } + "version": "1.5.0" + }, + "supportedTokens": ["GHO", "SolvBTC", "YBTC.B", "brBTC", "uniBTC", "wstETH", "xSolvBTC"] }, - "ethereum-mainnet-xlayer-1": { + "ethereum-mainnet-linea-1": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0x418dcbCf229897d0CCf1B8B464Db06C23879FBB4", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", - "enforceOutOfOrder": false, - "version": "1.6.0" - } + "address": "0x626189C882A80fF0D036d8D9f6447555e81F78E9", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": [ + "AISTR", + "BONE", + "LEASH", + "LsETH", + "SHIB", + "SolvBTC", + "TURTLE", + "WETH", + "avBTC", + "avETH", + "avETHx", + "avUSD", + "avUSDx", + "rsETH", + "savBTC", + "savETH", + "savUSD", + "xRPL", + "xSolvBTC", + "xrETH" + ] }, - "mainnet": { + "ethereum-mainnet-mantle-1": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", "version": "1.6.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "RETH": { - "rateLimiterConfig": { - "in": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - }, - "out": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "syrupUSDT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - }, - "out": { - "capacity": "2000000000000000000000", - "isEnabled": true, - "rate": "23148148140000000" - } - } - }, - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BONE", "LEASH", "SHIB", "USD1", "syrupUSDT", "uniBTC"] }, - "solana-mainnet": { + "ethereum-mainnet-mode-1": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0xb57D52F7Cb7BBD19a117585bbaf712108E56dd8f", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", - "enforceOutOfOrder": true, - "version": "1.6.0" + "address": "0xeA6d4a24B262aB3e61a8A62f018A30beCD086f82", + "enforceOutOfOrder": false, + "version": "1.5.0" }, - "supportedTokens": { - "eUSX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "5787000000" - }, - "out": { - "capacity": "500000000000000000000000", - "isEnabled": true, - "rate": "5787000000000000000" - } - } - }, - "USX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "sDAI", "wUSDx"] }, - "xdai-mainnet": { + "ethereum-mainnet-optimism-1": { "offRamp": { - "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", - "version": "1.6.0" + "address": "0x562a2025E60AA19Aa03Ea41D70ea1FD3286d1D3B", + "version": "1.5.0" }, "onRamp": { - "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "address": "0x3455D8E039736944e66e19eAc77a42e8077B07bf", "enforceOutOfOrder": false, - "version": "1.6.0" + "version": "1.5.0" }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } - } - }, - "plume-mainnet": { - "bitcoin-mainnet-bitlayer-1": { + "supportedTokens": [ + "BETS", + "BOLD", + "BONE", + "ETHx", + "IBTC", + "LEASH", + "OVER", + "SD", + "SHIB", + "USDC", + "USDM", + "USDT", + "WETH", + "ZUN", + "clBTC", + "rsETH", + "sDOLA", + "sINV", + "stTAO", + "uniBTC", + "wUSDx", + "zunETH", + "zunUSD" + ] + }, + "ethereum-mainnet-polygon-zkevm-1": { "offRamp": { - "address": "0xa5F858A09e7d9ED78EE46b76FbE49F4BDb8C1070", + "address": "0x0aB48c500AbD8392620c3C4E4fdD5d7063C44554", "version": "1.5.0" }, "onRamp": { - "address": "0x07367c806463482198b5CB97d7046E5f03681b3F", - "enforceOutOfOrder": false, + "address": "0x33417f13DFBC2FfB9e1B43051c3737370F3691a4", + "enforceOutOfOrder": true, "version": "1.5.0" - }, - "supportedTokens": { - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } } }, - "bsc-mainnet": { + "ethereum-mainnet-scroll-1": { + "offRamp": { + "address": "0x26a10137A54F4Ea01D20758Ac5AdBf9326340Fc3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x362A221C3cfd7F992DFE221687323F0BA9BA8187", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": ["BOLD", "BONE", "LEASH", "LINK", "SHIB"] + }, + "ethereum-mainnet-taiko-1": { "offRamp": { - "address": "0xA676892CB48Edfb04Cd1703FA676cb4d2CA26f10", + "address": "0x720EA8a2662376B89dEe1A7bAcA95b2eb6B6fF81", "version": "1.5.0" }, "onRamp": { - "address": "0xE7E32FB6B2942E0e98462e0dc0A10730b17B3094", + "address": "0x5F6e7707DE5019E13BaFbD2f4569B2453F16eB3e", "enforceOutOfOrder": false, "version": "1.5.0" - } + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, - "mainnet": { + "ethereum-mainnet-unichain-1": { "offRamp": { - "address": "0x470f7Ff1f9dd96DF02142Ef1F40E89204Ee7E4c1", + "address": "0xaA0DA3e06F43a5227abB0eA7D6DF3d1037B1769B", "version": "1.5.0" }, "onRamp": { - "address": "0x22eD7b77E07066d742412934CeeefA33B242609D", + "address": "0x5E7397CA539C94185BBD950706F0Dd8628587E04", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "USD1": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BETS", "USDC", "uniBTC"] }, - "matic-mainnet": { + "ethereum-mainnet-worldchain-1": { "offRamp": { - "address": "0x18626335F4266A1fE67C0d711FBE5f6813271F9c", + "address": "0x5EDa6801dBD2bBdbF0401d34c730fa2C3A97C3F4", "version": "1.5.0" }, "onRamp": { - "address": "0x0c6d3f214F2e8b9C2Fb551bcE4458F3DB5F89bFc", + "address": "0xdB6ebB3ea15595E516dEf4a9875479573a4F19b6", "enforceOutOfOrder": false, "version": "1.5.0" - } - } - }, - "polkadot-mainnet-astar": { - "mainnet": { + }, + "supportedTokens": ["WLD", "oXAUT"] + }, + "ethereum-mainnet-xlayer-1": { "offRamp": { - "address": "0x9a063F3267BD6F6935385F92A769Fb310691553E", - "version": "1.5.0" + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" }, "onRamp": { - "address": "0xc422a9AE3341dDDa7296F55D42C954B2faA03013", + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WASTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "2778000000000000000000" - } - } - } - } + "supportedTokens": ["brBTC", "uniBTC"] }, - "soneium-mainnet": { + "ethereum-mainnet-zircuit-1": { "offRamp": { - "address": "0x6105B3d708240844dad3c42A47Ec97b7c5bd693E", + "address": "0x4E4003DAFD00eC3B5F17f05950759054051950d6", "version": "1.5.0" }, "onRamp": { - "address": "0xbbBAf55ae2c821baeC7F0A0dC8cCf9B9AEC45Baf", - "enforceOutOfOrder": false, + "address": "0x4Cc3D95d9384D3287724B83099f01BC3025702c0", + "enforceOutOfOrder": true, "version": "1.5.0" }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "WASTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "20000000000000000000000000", - "isEnabled": true, - "rate": "5556000000000000000000" - } - } - } - } - } - }, - "polygon-mainnet-katana": { - "avalanche-mainnet": { + "supportedTokens": ["BONE", "LEASH", "SHIB", "mBTC", "rsETH"] + }, + "ethereum-mainnet-zksync-1": { "offRamp": { - "address": "0x0DF8De124f3dD573Bd466d8742a191f0c14E3D99", + "address": "0x6868FefbEFDc2B2FB75E6ED216dB1BeC02563D69", "version": "1.5.0" }, "onRamp": { - "address": "0xa84ea3De8201392E80492792e2D0A5FB88174a4e", + "address": "0x9B14AE850653dD0E30fBC93ab7f77D0d638a365B", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "SolvBTC", "USDM", "xSolvBTC"] }, - "bsc-mainnet": { + "etherlink-mainnet": { "offRamp": { - "address": "0xfE773489039eE69CbD520cf843F6FE4b19802163", - "version": "1.5.0" + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" }, "onRamp": { - "address": "0xa4d7Fe7D6F3409fBC4dD196c12D6C639665af915", + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "supportedTokens": ["LBTC"] + }, + "everclear-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "ethereum-mainnet-base-1": { + "fraxtal-mainnet": { "offRamp": { - "address": "0x2cf1822Ca5a0b7c82254187e40642A74aE7fe052", + "address": "0x559c3233aE9A0EcD45a6c45ee3B8c2c6DBa5F48D", "version": "1.5.0" }, "onRamp": { - "address": "0x84cbEF4469bF2A180885C37CCF333E4e95CE6FA9", + "address": "0x31ee106a4585a796caacC645172B9F7e9c2f8D37", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } } }, - "mainnet": { + "hedera-mainnet": { "offRamp": { - "address": "0x2FA4962EbaeB7b1dC066FA3f8Fc07489Fd34DA63", + "address": "0x7A82D2d3d824f9BAc136C31ef8086C673d23666D", "version": "1.5.0" }, "onRamp": { - "address": "0xc9CBE4D5ca717CB2EE6048E39D096D7c8839b5e7", + "address": "0x08C798376AfA295C047bDb5c011097865895672d", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "savUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["xGold"] }, - "monad-mainnet": { + "hemi-mainnet": { "offRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "version": "1.6.0" + "address": "0x9de971a8449Bc9F31Fe7B0F2Ccdab3873f711988", + "version": "1.5.0" }, "onRamp": { - "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "address": "0x7d7C4933f17B414f50C97d1a8862A1ace82557B3", "enforceOutOfOrder": false, - "version": "1.6.0" - }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } + "version": "1.5.0" } }, - "solana-mainnet": { + "hyperliquid-mainnet": { "offRamp": { - "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", - "version": "1.6.0" + "address": "0x69c3619326d5DF0d5abB752f2AE629413811ccD1", + "version": "1.5.0" }, "onRamp": { - "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "address": "0xC4a125BDBeE19Ec8BE02502cff9310FF9395905B", "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": ["BOLD", "SolvBTC", "VSN", "brBTC", "kHYPE", "syrupUSDC", "uniBTC", "xGold", "xSolvBTC"] + }, + "jovay-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", "version": "1.6.0" - } + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LINK"] }, - "sonic-mainnet": { + "kaia-mainnet": { "offRamp": { - "address": "0xB081ce3581CE89e873F1F9d0a2EcD8bFc4b26BF5", + "address": "0x4676537819a87E9D515D654f8bedf45A744cF214", "version": "1.5.0" }, "onRamp": { - "address": "0xE9dace1e7611E23627e6d0326E084fa08A42eA2f", + "address": "0x8469b5AbD81987F9347c0bAbd47b9eB11dA7d0dF", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } + "supportedTokens": ["USDO"] + }, + "lens-mainnet": { + "offRamp": { + "address": "0x4Bc6027Cd2da6CB7A105D5cE2D039c4892225419", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6715EA73EcAf1CaE1c736731129637B2E94a6B49", + "enforceOutOfOrder": true, + "version": "1.5.0" } - } - }, - "ronin-mainnet": { - "ethereum-mainnet-base-1": { + }, + "lisk-mainnet": { "offRamp": { - "address": "0x79Dd7DB8AdEbf6622852a5ACe471a78EDc6C0883", + "address": "0x82dAe15e45D63f2Ae85B1f0D690685A021D3a0fC", "version": "1.5.0" }, "onRamp": { - "address": "0x261fE8A0C492a1Ede8cf966AED16619C772198F5", + "address": "0x74Cb66502D855992137c5dC8A502c396A6E77931", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - } } }, - "mainnet": { + "matic-mainnet": { "offRamp": { - "address": "0x320A10449556388503Fd71D74A16AB52e0BD1dEb", + "address": "0x718672076D6d51E4c76142B37bC99E4945d704a3", "version": "1.5.0" }, "onRamp": { - "address": "0x02b60267bceeaFDC45005e0Fa0dd783eFeBc9F1b", + "address": "0x15a9D79d6b3485F70bF82bC49dDD1fcB37A7149c", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "ANIMA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "APRS": { - "rateLimiterConfig": { - "in": { - "capacity": "30000000000000000000000000", - "isEnabled": true, - "rate": "347222200000000000000" - }, - "out": { - "capacity": "27000000000000000000000000", - "isEnabled": true, - "rate": "312500000000000000000" - } - } - }, - "AXS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BANANA": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "17361110000000000000" - }, - "out": { - "capacity": "1350000000000000000000000", - "isEnabled": true, - "rate": "15625000000000000000" - } - } - }, - "CGX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "LUA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LUAUSD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "PFVS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "PIXEL": { - "rateLimiterConfig": { - "in": { - "capacity": "300000000000000000000000000", - "isEnabled": true, - "rate": "3472222200000000000000" - }, - "out": { - "capacity": "270000000000000000000000000", - "isEnabled": true, - "rate": "3125000000000000000000" - } - } - }, - "RETH": { + "supportedTokens": [ + "1XMM", + "BETS", + "BONE", + "DFX", + "EARNM", + "IXT", + "LEASH", + "LEND", + "Memento", + "OSIS", + "REG", + "RIZE", + "SHIB", + "SOIL", + "STABUL", + "SolvBTC", + "TRADE", + "USDC", + "USDM", + "WECO", + "WSDM", + "wstLINK", + "wstPOL", + "xGold", + "xSolvBTC" + ] + }, + "megaeth-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "BTC.b": { "rateLimiterConfig": { "in": { - "capacity": "1800000000000000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "5787000000000000" + "rate": "462963" }, "out": { - "capacity": "1800000000000000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "5787000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "rate": "462963" } } }, - "WBTC": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "4200000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "48610" + "rate": "462963" }, "out": { - "capacity": "3780000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "43750" - } - } - }, - "WETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "rate": "462963" } } }, - "YGG": { + "wstETH": { "rateLimiterConfig": { "in": { - "capacity": "2000000000000000000000000", + "capacity": "2000000000000000000000", "isEnabled": true, - "rate": "23148100000000000000" + "rate": "23148148140000000" }, "out": { - "capacity": "1800000000000000000000000", + "capacity": "2000000000000000000000", "isEnabled": true, - "rate": "20833300000000000000" - } - } - }, - "ZENT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "rate": "23148148140000000" } } } } - } - }, - "rootstock-mainnet": { - "mainnet": { + }, + "memento-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "metal-mainnet": { + "offRamp": { + "address": "0x8693cdA8E6D3Aee7c9fC258c3E7F648c8E6580c1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xDAa386621aB173C4E788ecebC4F8c2E6EB016819", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "mind-mainnet": { + "offRamp": { + "address": "0x8FEE869eDD935391B4979F8C79560102A8594B28", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x9cb0FF2Ea9110dc8831b39F620811a0da09747D3", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["FHE"] + }, + "mint-mainnet": { + "offRamp": { + "address": "0x49Aac6Fc36F32aC22867Ac0bAa23E6F2551f8edD", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x1Fa3aF677DC1b627f8A57e26b2a55d5F7945F06b", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "monad-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC", "SolvBTC", "USD1", "wstETH", "xSolvBTC"] + }, + "morph-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LINK", "USD1"] + }, + "nexon-mainnet-henesys": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "plasma-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["BOLD", "FLUID", "GHO", "LINK", "RETH", "YBTC.B", "savUSD", "syrupUSDT", "wstETH"] + }, + "plume-mainnet": { + "offRamp": { + "address": "0x109c666A021214C96a7ab7cde7E987F4e7dCD9fE", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x522f82eE3c4F0249D32b09e2F4c9C51B0F150ffF", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USD1"] + }, + "polkadot-mainnet-astar": { + "offRamp": { + "address": "0x33276152d082120F5190362e6E5F6783bbCb2B26", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xD8E8720709a3d9A18a9B281E6148E94149B2E252", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "WASTR"] + }, + "polygon-mainnet-katana": { + "offRamp": { + "address": "0xa8c12a859225531254dDef7079030f7DD6992A14", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc5Dbe2055Fa233ece44c99432526F3Fc46cA3FC2", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LBTC", "savUSD"] + }, + "ronin-mainnet": { + "offRamp": { + "address": "0x9a3Ed7007809CfD666999e439076B4Ce4120528D", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xdC5b578ff3AFcC4A4a6E149892b9472390b50844", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "ANIMA", + "APRS", + "AXS", + "BANANA", + "CGX", + "LINK", + "LUA", + "LUAUSD", + "PFVS", + "PIXEL", + "RETH", + "USDC", + "WBTC", + "WETH", + "YGG", + "ZENT" + ] + }, + "rootstock-mainnet": { + "offRamp": { + "address": "0x34eEc7EcA3Ce1e693028255ebE2063728224a604", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x34748FbeD8fD8468eD66D53A7D102ce793cB4094", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "sei-mainnet": { + "offRamp": { + "address": "0xc876D50A0Ecc147FC0cEd194cD2b66210d482f9c", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x5739E5376702AAc79a53B375ca160EE3C12025E0", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "shibarium-mainnet": { + "offRamp": { + "address": "0x8B3eEed4948684c3ec1bb60967820f40285018B8", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x3Ac0D8fe5b4e8d0a95C507CCd83F6A8d73A8c6b1", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SAS", "SHIRO"] + }, + "solana-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": [ + "FHE", + "FLUID", + "LINK", + "MEW", + "OHM", + "PEPE", + "PTsUSDE", + "SolvBTC", + "USD1", + "USDC", + "WFRAGSOL", + "WLFI", + "WMTX", + "brBTC", + "elizaOS", + "syrupUSDC", + "uniBTC", + "xSolvBTC", + "zBTC" + ] + }, + "soneium-mainnet": { + "offRamp": { + "address": "0xdFD8C353044aB175cC96FD4261c2Af3E3AB768a4", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x093844Bd4b26792791cD4038e94Bec70f88CaD63", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["DEGEN", "LINK", "SKYA", "SolvBTC", "WASTR", "pufETH", "xSolvBTC"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0xB45cF8df3AAa50199B7AaabD345119BAd1b8d977", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x4fdAaDe22bd05537EeaB204cF7319589CE595D6a", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BOLD", + "LBTC", + "LINK", + "SILO", + "SolvBTC", + "USDT", + "egETH", + "mBTC", + "mstETH", + "uniBTC", + "wUSDx", + "xSILO", + "xSolvBTC", + "zBTC" + ] + }, + "stable-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC", "LINK"] + }, + "superseed-mainnet": { + "offRamp": { + "address": "0x3c5990484D4D7b728Ae875d001E97469284210C1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x486170Bca7fE5126AFeaF171d3a60A211bF2C44C", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "tac-mainnet": { "offRamp": { - "address": "0x60FcDf09B8689B138f98a5f483E0dE6Ee0AD3A05", + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC", "LINK", "RETH", "tETH", "uniBTC"] + }, + "wemix-mainnet": { + "offRamp": { + "address": "0xc1EcCE580B2C96f4fd202fB7c2a259ECe19a1bF2", "version": "1.5.0" }, "onRamp": { - "address": "0x85a6Dc1E19EA051C0DA93290d030F3eDBD99B159", + "address": "0xdEFeADd30D5BFD403d86245b43e39a73d76423cC", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "USDC", "una.USDC", "una.WEMIX"] + }, + "xdai-mainnet": { + "offRamp": { + "address": "0x70C705ff3eCAA04c8c61d581a59a168a1c49c2ec", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xf50B9A46C394bD98491ce163d420222d8030F6F0", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "GHO", "LEASH", "REG", "SHIB"] + }, + "xdc-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LINK", "USDf"] + }, + "zora-mainnet": { + "offRamp": { + "address": "0x5e24de8F7Ccb3E1e204707573a672823d88C559F", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc46e2F17c04f2C880Ea56a0c69c4520AdB4aBF88", "enforceOutOfOrder": false, "version": "1.5.0" } } }, - "sei-mainnet": { + "matic-mainnet": { + "apechain-mainnet": { + "offRamp": { + "address": "0xBb331Ac82A67d28b05386ea8762eECd014433dc9", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xb9494347a3D13Fb499a72e95b9DAbF6F20C18768", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, "avalanche-mainnet": { "offRamp": { - "address": "0x5b5Ee660e8D36B46857597D4ed97f73D0384cf1e", + "address": "0x35c1Bb5A9c2F3fa8f8dFF470a6bE7d362CeA1ef3", "version": "1.5.0" }, "onRamp": { - "address": "0x2026bF3E3465adb50a48D050B521A2087E1cD3Cc", + "address": "0x56cb9Cd82553Bd8157e6504020c38f6DA4971717", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BETS", "LEND", "Memento", "SolvBTC", "USDC", "USDM", "wstLINK", "wstPOL", "xSolvBTC"] }, "berachain-mainnet": { "offRamp": { - "address": "0x8C022299ba2D2B261Bd68Bb7161E1c03BB1F5525", + "address": "0xb572AF6Ee0199079a1a253E3a8dC71ace13c8C14", "version": "1.5.0" }, "onRamp": { - "address": "0x7B989002296ed4269618CD1B28c31df48842fe7F", + "address": "0x1203DE1eA440B9acBbe2Fc76784fB5916F4B21AF", "enforceOutOfOrder": false, "version": "1.5.0" } }, "bitcoin-mainnet-bob-1": { "offRamp": { - "address": "0x9be3182D082A2c27daDa35A8069059A167d3EA3E", + "address": "0x2a612eDAa990918518Ba3cC59EeBF898CB1e501A", "version": "1.5.0" }, "onRamp": { - "address": "0x6052F14312D81B4A47241dB104D7a8dB4913481C", + "address": "0xf9d899fe9B0D785B88D7FD9EAc368B34bFbF6f3f", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, "bsc-mainnet": { "offRamp": { - "address": "0xE1ea14c3C1c2443b1Cd9144c735eA67D9822F5E4", + "address": "0xE58074f8F56E23836f088Ac8b4f3882c1b4CAcbb", "version": "1.5.0" }, "onRamp": { - "address": "0x9008BbDB87183243a8A20BE55247f194d601640C", + "address": "0x164507757F7d5Ab35C6af44EeEB099F5be29Da57", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "supportedTokens": [ + "1XMM", + "BETS", + "IXT", + "LAND", + "LEND", + "METO", + "RIZE", + "SolvBTC", + "THE", + "TRADE", + "WECO", + "WSDM", + "xGold", + "xSolvBTC" + ] + }, + "celo-mainnet": { + "offRamp": { + "address": "0xDf1F2a04c0e572D68E3E0D14d6ed3864921FE3f3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x608e3993854607dE4FC8f7926ab6b7c5AB3cA8Fc", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "corn-mainnet": { + "offRamp": { + "address": "0x1C8902998ceaf082C14b60610a7c383c4C58Dc99", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xdD131De9C7dE71e1859cF5e8153EfCc2fB93E554", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "0xB608ED315A2D582759c5B464439356C5e9c62932", + "address": "0x60f2788225CeE4a94f8E7589931d5A14Cbc4367d", "version": "1.5.0" }, "onRamp": { - "address": "0x3c5f420381395be6f7FA5cd50E72c9B4b82b24E5", + "address": "0x13263aC754d1e29430930672E3C0019f2BC44Ba2", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": [ + "BETS", + "DFX", + "EARNM", + "IXT", + "LAND", + "LEND", + "SDM", + "STBU", + "SolvBTC", + "USDC", + "USDM", + "WECO", + "WSDM", + "wstLINK", + "xSolvBTC" + ] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0xF4a9Dbb7f3FBa02e3a244B464e459C32B63857F1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xD26A4E0c664E72e3c29E634867191cB1cb9AF570", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BETS", + "BYTES", + "CRTV", + "EARNM", + "IXT", + "LEND", + "LYP", + "Memento", + "RIZE", + "STABUL", + "SolvBTC", + "TRADE", + "USDC", + "USDM", + "XTFBRICK1", + "XTFCLOBOND", + "wstLINK", + "xGold", + "xSolvBTC" + ] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0xA2d83fFE785C5733D61540C03f78F0c69c35c5eF", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x213Ecb8e4105271817465820909c90c0d33c0C73", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0xc195B549f3B7Ee890B5F2C244CEfa88C71adb414", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x8Eb6d67f4104acb6b7B956D5DE42a34ECe25e07a", + "enforceOutOfOrder": true, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x805c292775Be43b10Cc744ea7E81d9939a08cEa4", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x868B71490B36674B3B9006fa8711C6fA26A26631", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BETS", "CRTV", "USDC", "USDM"] }, - "ethereum-mainnet-base-1": { + "ethereum-mainnet-unichain-1": { "offRamp": { - "address": "0xfB465888BAe202216cDD673d5a5512A488c8395f", + "address": "0x354B294816C09A5a5a2832a8B61d78EdEF2FD94e", "version": "1.5.0" }, "onRamp": { - "address": "0x1BFe9EdAA897cC730F1E18dbd82706df5fD8E75D", + "address": "0xea602eDf1f43dd8437D31D2EA6D1c68F8f5825d9", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BETS", "USDC"] }, - "ethereum-mainnet-ink-1": { + "ethereum-mainnet-zksync-1": { "offRamp": { - "address": "0x96A1d8dB2f830bC4c7641a827c1B3Ee16505bD30", + "address": "0xbd52D1661D195c4311363251ad387E504589971f", "version": "1.5.0" }, "onRamp": { - "address": "0xF4EBbd1B57a62eC6Fc70E2be47ba91ac8224C53E", + "address": "0x2655242E3200b99201f7d62CfF4aF04bBCfCa44C", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } + "supportedTokens": ["SolvBTC", "USDM", "xSolvBTC"] }, - "ethereum-mainnet-optimism-1": { + "jovay-mainnet": { "offRamp": { - "address": "0x1EfBD277FF1E0353A633ee4B944daD7A46Ce0aAB", - "version": "1.5.0" + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" }, "onRamp": { - "address": "0x346A744A508BdE3C6Dac722104305F143D789AdE", + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" } }, "mainnet": { "offRamp": { - "address": "0x737563c69D9D84CE16D175f6b17bbC823ba5Afd5", + "address": "0xa06e68a11d5694316Cc819f2FFD02663e3314C7C", "version": "1.5.0" }, "onRamp": { - "address": "0x47bA87120CA9047268A68d5B3b40f70a8a59a2B7", + "address": "0x1DAcBae00c779913e6E9fc1A3323FbA4847ba53C", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "supportedTokens": [ + "1XMM", + "BETS", + "BONE", + "DFX", + "EARNM", + "IXT", + "LEASH", + "LEND", + "Memento", + "OSIS", + "REG", + "RIZE", + "SHIB", + "SOIL", + "STABUL", + "SolvBTC", + "TRADE", + "USDC", + "USDM", + "WECO", + "WSDM", + "wstLINK", + "wstPOL", + "xGold", + "xSolvBTC" + ] + }, + "memento-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["XTFBRICK1", "XTFCLOBOND"] + }, + "plume-mainnet": { + "offRamp": { + "address": "0xB2651Fe276fbA4A6F14F4094272929A6125255a3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6581f896c3B8BFAb9d5ba01d7Cfd50568959FF82", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "matic-mainnet": { + "sei-mainnet": { "offRamp": { - "address": "0x704a014C7235a7f48CF9Db6Bf7047e540Bf38788", + "address": "0x814f5bB435F8ad9437D5ac0d8aBCd97E095f9879", "version": "1.5.0" }, "onRamp": { - "address": "0x6c5d72C4Afe7Df5502D84C1F06725361F3Db0d3d", + "address": "0x020ec1e27a46822bC0a2DEdc48793958fDAfC185", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, "solana-mainnet": { "offRamp": { - "address": "0x3eC62564F66874f619640cBb7Fd42A157f21A442", + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", "version": "1.6.0" }, "onRamp": { - "address": "0x4E76D19073eF8c0CE63C2A0034e52745a94db284", + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", "enforceOutOfOrder": true, "version": "1.6.0" - } - } - }, - "shibarium-mainnet": { - "avalanche-mainnet": { + }, + "supportedTokens": ["USDC"] + }, + "soneium-mainnet": { "offRamp": { - "address": "0xa4125E03add87C6F68929D5F5FFB0217F92d1E3e", + "address": "0x1bE40B0e51cC5C353842b94e2E3d2D99c7760865", "version": "1.5.0" }, "onRamp": { - "address": "0x08e963E41875f03A6e04Cd22FC7F452A87cFb00F", + "address": "0xf0D403fF3f04C479929A8412ae244B42Bbe070F4", "enforceOutOfOrder": false, "version": "1.5.0" - } + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, - "ethereum-mainnet-arbitrum-1": { + "sonic-mainnet": { "offRamp": { - "address": "0x86895bbe0914b00f481108b97281b4c717254E1c", + "address": "0x6dF61364fD9335063f975eF4917a703891CcA45C", "version": "1.5.0" }, "onRamp": { - "address": "0x4E800ECC5976182ad27107e24b5EfF1A06f59a32", + "address": "0x126441fEA96cC466E31fc46957ca4e675D0700f9", "enforceOutOfOrder": false, "version": "1.5.0" } }, - "ethereum-mainnet-base-1": { + "wemix-mainnet": { "offRamp": { - "address": "0xaB681D4f5498B23312B7C7f33d32318dc7E9F7Bb", + "address": "0xd357Bee1Ff4B1cce7dc0d953a9E5613476781732", "version": "1.5.0" }, "onRamp": { - "address": "0x39BFf297296f19257Dd999cb2b301137e2cD41D2", + "address": "0x9363330c6d807a1393c1fd35893c64d26931CDe6", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["una.WEMIX"] + }, + "xdai-mainnet": { + "offRamp": { + "address": "0x9e2e4e397226f347d11D3fF8469d0c3FFa750C3B", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xcc4A8CFd756895d91B476Dd5461286b300914aBf", "enforceOutOfOrder": false, "version": "1.5.0" }, + "supportedTokens": ["REG"] + } + }, + "megaeth-mainnet": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x1ba9bE96A5c21dcdB9D22bEC3f00abCb6336fd65", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, "supportedTokens": { - "CANNED": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "CHIKA": { + "BTC.b": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" } } }, - "DAMN": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" } } - }, - "FEED": { + } + } + }, + "bsc-mainnet": { + "offRamp": { + "address": "0x1ba9bE96A5c21dcdB9D22bEC3f00abCb6336fd65", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" } } - }, - "LUISA": { + } + } + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x1ba9bE96A5c21dcdB9D22bEC3f00abCb6336fd65", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" } } - }, - "NEKO": { + } + } + }, + "mainnet": { + "offRamp": { + "address": "0x1ba9bE96A5c21dcdB9D22bEC3f00abCb6336fd65", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "BTC.b": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" } } }, - "SAS": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" } } }, - "SHIPA": { + "wstETH": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "2000000000000000000000", + "isEnabled": true, + "rate": "23148148140000000" } } - }, - "SNOW": { + } + } + }, + "polygon-mainnet-katana": { + "offRamp": { + "address": "0x1ba9bE96A5c21dcdB9D22bEC3f00abCb6336fd65", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "BTC.b": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" } } }, - "USAGI": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" } } - }, - "WOW": { + } + } + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x1ba9bE96A5c21dcdB9D22bEC3f00abCb6336fd65", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" + "capacity": "5000000000", + "isEnabled": true, + "rate": "462963" } } } } + } + }, + "memento-mainnet": { + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["XTFBRICK1", "XTFCLOBOND"] }, - "ethereum-mainnet-optimism-1": { + "mainnet": { "offRamp": { - "address": "0x1819949117E7BA13d3B23869b200D8BB60Aab831", + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "matic-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["XTFBRICK1", "XTFCLOBOND"] + }, + "solana-mainnet": { + "offRamp": { + "address": "0x26d3681DfC9E4c8C79cfbf461adec8A21d5d73C5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x913814782144864e523C3FdB78E3ca25D2c2aeCa", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + } + }, + "metal-mainnet": { + "mainnet": { + "offRamp": { + "address": "0xd41A38a8372D1Ac745B54aE0bE09b7e0076b6A45", "version": "1.5.0" }, "onRamp": { - "address": "0xc8E545ebE0AD4e7A119e607C7671F0bc0C1eB2A3", + "address": "0x512c58F427BEFE54BF8dcB0579119DDE43e1929B", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "mind-mainnet": { + "bsc-mainnet": { + "offRamp": { + "address": "0x92a7A4b2E2c242661f88be40788A7cfA8F0dd7F4", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x7d9CA4bF88c0567c65186810Cf62f55504a5D086", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["FHE"] + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x1011d2CA716fDf9cCb358c118164e887048a3B5C", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x7edb203cde6ba240e2a8f14E07875C86239c36aF", "enforceOutOfOrder": false, "version": "1.5.0" } }, "mainnet": { "offRamp": { - "address": "0x7422809f8625Ec2b98a1DDd39db4C99F75EE118F", + "address": "0x50fF86d32A0774f0370848A1B4583fc83FdA0070", "version": "1.5.0" }, "onRamp": { - "address": "0x750BFfccf99D1Ad1C38b5FE4Ad83010bbb82E7DF", + "address": "0xe69a1e9c2A0931D31593B201BD0CD5Bd39692e70", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SAS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SHIRO": { + "supportedTokens": ["FHE"] + } + }, + "mint-mainnet": { + "mainnet": { + "offRamp": { + "address": "0xE646B92d6239ec4B11348EB516dbd1b336cb13dE", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6e05AfFFD2D44e1703e1ff5c0A24bee10f0781b6", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "monad-mainnet": { + "0g-mainnet": { + "offRamp": { + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "W0G": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -32119,42 +8097,53 @@ } } }, - "solana-mainnet": { + "avalanche-mainnet": { "offRamp": { - "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", "version": "1.6.0" }, "onRamp": { - "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", - "enforceOutOfOrder": true, + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, "version": "1.6.0" - } - } - }, - "solana-mainnet": { - "0g-mainnet": { + }, + "supportedTokens": ["LBTC"] + }, + "berachain-mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, "version": "1.6.0" } }, - "avalanche-mainnet": { + "bsc-mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, "version": "1.6.0" }, "supportedTokens": { - "USDC": { + "W0G": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -32170,265 +8159,100 @@ } } }, - "berachain-mainnet": { + "ethereum-mainnet-base-1": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, "version": "1.6.0" - } + }, + "supportedTokens": ["LBTC"] }, - "bitcoin-mainnet-bitlayer-1": { + "ethereum-mainnet-ink-1": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "YBTC.B": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["wstETH"] }, - "bsc-mainnet": { + "ethereum-mainnet-optimism-1": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "etherlink-mainnet": { + "offRamp": { + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", "version": "1.6.0" }, - "supportedTokens": { - "BR": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "5800000000" - }, - "out": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "5800000000" - } - } - }, - "elizaOS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "ILMT": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000000", - "isEnabled": true, - "rate": "277777777778" - }, - "out": { - "capacity": "1000000000000000", - "isEnabled": true, - "rate": "277777777778" - } - } - }, - "MEW": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "750000000", - "isEnabled": true, - "rate": "34722" - }, - "out": { - "capacity": "750000000", - "isEnabled": true, - "rate": "34722" - } - } - }, - "SolvBTC.JUP": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "57870" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "57870" - } - } - }, - "USELESS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WLFI": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "XLAB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "250000000", - "isEnabled": true, - "rate": "11574" - } - } - } + "onRamp": { + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "ethereum-mainnet-arbitrum-1": { + "mainnet": { + "offRamp": { + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC", "SolvBTC", "USD1", "wstETH", "xSolvBTC"] + }, + "plasma-mainnet": { + "offRamp": { + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["wstETH"] + }, + "polygon-mainnet-katana": { + "offRamp": { + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "solana-mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", "enforceOutOfOrder": true, "version": "1.6.0" }, "supportedTokens": { - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "23148100000" - }, - "out": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "23148100000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WFRAGSOL": { + "W0G": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -32441,448 +8265,223 @@ "rate": "0" } } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } } } }, - "ethereum-mainnet-base-1": { + "sonic-mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xdCc981e12Fd132d9172eb03E8373BE68032588e8", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "address": "0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + } + }, + "morph-mainnet": { + "mainnet": { + "offRamp": { + "address": "0x76159c2b43ff6F630193e37EC68452169914C1Bb", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x318Ec96df83AccC18B5EAD5D23e0F022F7Eb5503", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LINK", "USD1"] + } + }, + "nexon-mainnet-henesys": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x9b04018b5285FF16F3967Af108Bdc72423d547cC", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x59d32e5Fa8EeD1Fd1510f7E583a2b6e6142DD49F", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x9b04018b5285FF16F3967Af108Bdc72423d547cC", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + } + }, + "plasma-mainnet": { + "aptos-mainnet": { + "offRamp": { + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", "enforceOutOfOrder": true, "version": "1.6.0" + } + }, + "avalanche-mainnet": { + "offRamp": { + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", + "version": "1.6.0" }, - "supportedTokens": { - "elizaOS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "23148100000" - }, - "out": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "23148100000" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000", - "isEnabled": true, - "rate": "13880000000" - }, - "out": { - "capacity": "50000000000000", - "isEnabled": true, - "rate": "13880000000" - } - } - }, - "MEW": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - } - } - }, - "MICHI": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "78722220" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "78722220" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - } - } - }, - "YNE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - } + "onRamp": { + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["GHO", "savUSD"] + }, + "bitcoin-mainnet-bitlayer-1": { + "offRamp": { + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["YBTC.B"] + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["BOLD", "FLUID", "GHO"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["BOLD", "FLUID", "GHO"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", + "version": "1.6.0" + }, + "supportedTokens": ["wstETH"] + }, + "ethereum-mainnet-xlayer-1": { + "offRamp": { + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "ethereum-mainnet-optimism-1": { + "mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BOLD", "FLUID", "GHO", "LINK", "RETH", "YBTC.B", "savUSD", "syrupUSDT", "wstETH"] }, - "ethereum-mainnet-unichain-1": { + "monad-mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["wstETH"] }, - "ethereum-mainnet-worldchain-1": { + "solana-mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", "enforceOutOfOrder": true, "version": "1.6.0" - } + }, + "supportedTokens": ["FLUID", "USX", "eUSX"] }, - "hyperliquid-mainnet": { + "xdai-mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, + "address": "0x8FE3B17E6B0863aeEA3D38DF063AEa39D4Ab1602", + "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "WHLP": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["GHO"] + } + }, + "plume-mainnet": { + "bitcoin-mainnet-bitlayer-1": { + "offRamp": { + "address": "0xa5F858A09e7d9ED78EE46b76FbE49F4BDb8C1070", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x07367c806463482198b5CB97d7046E5f03681b3F", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["YBTC.B"] }, - "mainnet": { + "bsc-mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", - "version": "1.6.0" + "address": "0xA676892CB48Edfb04Cd1703FA676cb4d2CA26f10", + "version": "1.5.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, - "version": "1.6.0" + "address": "0xE7E32FB6B2942E0e98462e0dc0A10730b17B3094", + "enforceOutOfOrder": false, + "version": "1.5.0" }, "supportedTokens": { - "brBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "elizaOS": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FHE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "23148100000" - }, - "out": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "23148100000" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000", - "isEnabled": true, - "rate": "13880000000" - }, - "out": { - "capacity": "50000000000000", - "isEnabled": true, - "rate": "13880000000" - } - } - }, - "MEW": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - } - } - }, - "OHM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "PEPE": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "138888888889" - }, - "out": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "138888888889" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "250000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "250000000", - "isEnabled": true, - "rate": "11574" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WFRAGSOL": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WLFI": { + "sUSD1+": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -32890,106 +8489,494 @@ "rate": "0" }, "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "WMTX": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" - }, - "out": { - "capacity": "1000000000000", - "isEnabled": true, - "rate": "277770000" + "capacity": "0", + "isEnabled": false, + "rate": "0" } } - }, - "xSolvBTC": { + } + } + }, + "mainnet": { + "offRamp": { + "address": "0x470f7Ff1f9dd96DF02142Ef1F40E89204Ee7E4c1", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x22eD7b77E07066d742412934CeeefA33B242609D", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["USD1"] + }, + "matic-mainnet": { + "offRamp": { + "address": "0x18626335F4266A1fE67C0d711FBE5f6813271F9c", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x0c6d3f214F2e8b9C2Fb551bcE4458F3DB5F89bFc", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "polkadot-mainnet-astar": { + "mainnet": { + "offRamp": { + "address": "0x9a063F3267BD6F6935385F92A769Fb310691553E", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc422a9AE3341dDDa7296F55D42C954B2faA03013", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "WASTR"] + }, + "soneium-mainnet": { + "offRamp": { + "address": "0x6105B3d708240844dad3c42A47Ec97b7c5bd693E", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xbbBAf55ae2c821baeC7F0A0dC8cCf9B9AEC45Baf", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LINK", "WASTR"] + } + }, + "polygon-mainnet-katana": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x0DF8De124f3dD573Bd466d8742a191f0c14E3D99", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xa84ea3De8201392E80492792e2D0A5FB88174a4e", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LBTC", "savUSD"] + }, + "berachain-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "bsc-mainnet": { + "offRamp": { + "address": "0xfE773489039eE69CbD520cf843F6FE4b19802163", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xa4d7Fe7D6F3409fBC4dD196c12D6C639665af915", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LBTC", "savUSD"] + }, + "corn-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x2cf1822Ca5a0b7c82254187e40642A74aE7fe052", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x84cbEF4469bF2A180885C37CCF333E4e95CE6FA9", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LBTC"] + }, + "etherlink-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x2FA4962EbaeB7b1dC066FA3f8Fc07489Fd34DA63", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc9CBE4D5ca717CB2EE6048E39D096D7c8839b5e7", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LBTC", "savUSD"] + }, + "megaeth-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": { + "BTC.b": { "rateLimiterConfig": { "in": { - "capacity": "250000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "11574" + "rate": "462963" }, "out": { - "capacity": "250000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "11574" + "rate": "462963" } } }, - "zBTC": { + "LBTC": { "rateLimiterConfig": { "in": { - "capacity": "1000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "11574" + "rate": "462963" }, "out": { - "capacity": "1000000000", + "capacity": "5000000000", "isEnabled": true, - "rate": "11574" + "rate": "462963" } } } } }, + "monad-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "solana-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "sonic-mainnet": { + "offRamp": { + "address": "0xB081ce3581CE89e873F1F9d0a2EcD8bFc4b26BF5", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xE9dace1e7611E23627e6d0326E084fa08A42eA2f", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LBTC"] + }, + "stable-mainnet": { + "offRamp": { + "address": "0x02A4D69cFfeC00Fbf7F3B60c93e3529Dfc58894d", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xc23071a8AE83671f37bdA1DaDBC745a9780f632A", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + } + }, + "ronin-mainnet": { + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x79Dd7DB8AdEbf6622852a5ACe471a78EDc6C0883", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x261fE8A0C492a1Ede8cf966AED16619C772198F5", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LINK"] + }, + "mainnet": { + "offRamp": { + "address": "0x320A10449556388503Fd71D74A16AB52e0BD1dEb", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x02b60267bceeaFDC45005e0Fa0dd783eFeBc9F1b", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "ANIMA", + "APRS", + "AXS", + "BANANA", + "CGX", + "LINK", + "LUA", + "LUAUSD", + "PFVS", + "PIXEL", + "RETH", + "USDC", + "WBTC", + "WETH", + "YGG", + "ZENT" + ] + } + }, + "rootstock-mainnet": { + "mainnet": { + "offRamp": { + "address": "0x60FcDf09B8689B138f98a5f483E0dE6Ee0AD3A05", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x85a6Dc1E19EA051C0DA93290d030F3eDBD99B159", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "sei-mainnet": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x5b5Ee660e8D36B46857597D4ed97f73D0384cf1e", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x2026bF3E3465adb50a48D050B521A2087E1cD3Cc", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "VRTX"] + }, + "berachain-mainnet": { + "offRamp": { + "address": "0x8C022299ba2D2B261Bd68Bb7161E1c03BB1F5525", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x7B989002296ed4269618CD1B28c31df48842fe7F", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "bitcoin-mainnet-bob-1": { + "offRamp": { + "address": "0x9be3182D082A2c27daDa35A8069059A167d3EA3E", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6052F14312D81B4A47241dB104D7a8dB4913481C", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "bsc-mainnet": { + "offRamp": { + "address": "0xE1ea14c3C1c2443b1Cd9144c735eA67D9822F5E4", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x9008BbDB87183243a8A20BE55247f194d601640C", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0xB608ED315A2D582759c5B464439356C5e9c62932", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x3c5f420381395be6f7FA5cd50E72c9B4b82b24E5", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["VRTX"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0xfB465888BAe202216cDD673d5a5512A488c8395f", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x1BFe9EdAA897cC730F1E18dbd82706df5fD8E75D", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["VRTX"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0x96A1d8dB2f830bC4c7641a827c1B3Ee16505bD30", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xF4EBbd1B57a62eC6Fc70E2be47ba91ac8224C53E", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x1EfBD277FF1E0353A633ee4B944daD7A46Ce0aAB", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x346A744A508BdE3C6Dac722104305F143D789AdE", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x737563c69D9D84CE16D175f6b17bbC823ba5Afd5", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x47bA87120CA9047268A68d5B3b40f70a8a59a2B7", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, "matic-mainnet": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0x704a014C7235a7f48CF9Db6Bf7047e540Bf38788", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6c5d72C4Afe7Df5502D84C1F06725361F3Db0d3d", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] + }, + "solana-mainnet": { + "offRamp": { + "address": "0x3eC62564F66874f619640cBb7Fd42A157f21A442", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "address": "0x4E76D19073eF8c0CE63C2A0034e52745a94db284", "enforceOutOfOrder": true, "version": "1.6.0" + } + } + }, + "shibarium-mainnet": { + "avalanche-mainnet": { + "offRamp": { + "address": "0xa4125E03add87C6F68929D5F5FFB0217F92d1E3e", + "version": "1.5.0" }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "onRamp": { + "address": "0x08e963E41875f03A6e04Cd22FC7F452A87cFb00F", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "memento-mainnet": { + "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", - "version": "1.6.0" + "address": "0x86895bbe0914b00f481108b97281b4c717254E1c", + "version": "1.5.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, - "version": "1.6.0" + "address": "0x4E800ECC5976182ad27107e24b5EfF1A06f59a32", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "monad-mainnet": { + "ethereum-mainnet-base-1": { "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "address": "0xaB681D4f5498B23312B7C7f33d32318dc7E9F7Bb", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x39BFf297296f19257Dd999cb2b301137e2cD41D2", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["CANNED", "CHIKA", "DAMN", "FEED", "LUISA", "NEKO", "SAS", "SHIPA", "SNOW", "USAGI", "WOW"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x1819949117E7BA13d3B23869b200D8BB60Aab831", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xc8E545ebE0AD4e7A119e607C7671F0bc0C1eB2A3", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x7422809f8625Ec2b98a1DDd39db4C99F75EE118F", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x750BFfccf99D1Ad1C38b5FE4Ad83010bbb82E7DF", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SAS", "SHIRO"] + }, + "solana-mainnet": { + "offRamp": { + "address": "0x77FDbd20ED582794b1d9F1a8a94e4a60494D677e", "version": "1.6.0" }, "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "address": "0x530Ae314EC3fA038bd9A215095E37295ec76162a", "enforceOutOfOrder": true, "version": "1.6.0" } - }, - "plasma-mainnet": { + } + }, + "solana-mainnet": { + "0g-mainnet": { "offRamp": { "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", "version": "1.6.0" @@ -33000,35 +8987,7 @@ "version": "1.6.0" }, "supportedTokens": { - "eUSX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "FLUID": { - "rateLimiterConfig": { - "in": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "5787000000" - }, - "out": { - "capacity": "500000000000000", - "isEnabled": true, - "rate": "5787000000" - } - } - }, - "USX": { + "W0G": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -33044,7 +9003,7 @@ } } }, - "polygon-mainnet-katana": { + "avalanche-mainnet": { "offRamp": { "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", "version": "1.6.0" @@ -33053,9 +9012,10 @@ "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", "enforceOutOfOrder": true, "version": "1.6.0" - } + }, + "supportedTokens": ["USDC"] }, - "sei-mainnet": { + "berachain-mainnet": { "offRamp": { "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", "version": "1.6.0" @@ -33066,7 +9026,7 @@ "version": "1.6.0" } }, - "shibarium-mainnet": { + "bitcoin-mainnet-bitlayer-1": { "offRamp": { "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", "version": "1.6.0" @@ -33075,9 +9035,10 @@ "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", "enforceOutOfOrder": true, "version": "1.6.0" - } + }, + "supportedTokens": ["YBTC.B"] }, - "sonic-mainnet": { + "bsc-mainnet": { "offRamp": { "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", "version": "1.6.0" @@ -33087,332 +9048,171 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000", - "isEnabled": true, - "rate": "13880000000" - }, - "out": { - "capacity": "50000000000000", - "isEnabled": true, - "rate": "13880000000" - } - } - }, - "MEW": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - } - } - } - }, - "soneium-mainnet": { - "bitcoin-mainnet-bob-1": { + "supportedTokens": [ + "BR", + "FHE", + "ILMT", + "KNET", + "MEW", + "SolvBTC", + "SolvBTC.JUP", + "USELESS", + "WLFI", + "WMTX", + "XLAB", + "elizaOS", + "xSolvBTC" + ] + }, + "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "0xD0734ef5044B73929248637099caa122580531CB", - "version": "1.5.0" + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" + }, + "onRamp": { + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["FLUID", "USDC", "WFRAGSOL", "WMTX"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" }, "onRamp": { - "address": "0xD9F8Dd97688653965e57421a859520c144Fc176C", - "enforceOutOfOrder": false, - "version": "1.5.0" + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "SolvBTC.JUP": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } + "supportedTokens": ["FLUID", "LINK", "MEW", "MICHI", "USDC", "WMTX", "YNE", "elizaOS", "pippin", "zBTC"] }, - "bitcoin-mainnet-bsquared-1": { + "ethereum-mainnet-optimism-1": { "offRamp": { - "address": "0xF149aa4fA6e21cA94153aeA833145f0997166dea", - "version": "1.5.0" + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" }, "onRamp": { - "address": "0x911D4D671Ec2ACE5213E50f493dEc43cB556798B", - "enforceOutOfOrder": false, - "version": "1.5.0" - } + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["USDC"] }, - "bsc-mainnet": { + "ethereum-mainnet-unichain-1": { "offRamp": { - "address": "0x45004bA967A5a6a4cB7DB9C0FF9F67Ad77E2208F", - "version": "1.5.0" + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" }, "onRamp": { - "address": "0x3381fFEb675a2018357DC8A020B721cB227b5087", - "enforceOutOfOrder": false, - "version": "1.5.0" + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" }, - "supportedTokens": { - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC.JUP": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "1157400000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "1157400000000000" - } - } - } - } + "supportedTokens": ["USDC"] }, - "celo-mainnet": { + "ethereum-mainnet-worldchain-1": { "offRamp": { - "address": "0x2048413F78F6BF7b3499b28321e7B55a3aD95e56", - "version": "1.5.0" + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" }, "onRamp": { - "address": "0x4DFe6A7bd2A7B365EC93135221F2e7305A180bb9", - "enforceOutOfOrder": false, - "version": "1.5.0" + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" } }, - "ethereum-mainnet-arbitrum-1": { + "everclear-mainnet": { "offRamp": { - "address": "0xe9839BC342F22a6ABF11c0831Bf881F0eddc4bBb", - "version": "1.5.0" + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" }, "onRamp": { - "address": "0xFF7693049430da19E3957533a8aF45036eEe3594", - "enforceOutOfOrder": false, - "version": "1.5.0" + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" } }, - "ethereum-mainnet-base-1": { + "hyperliquid-mainnet": { "offRamp": { - "address": "0x5eB8e2aB40b54190bb49D05867d6572891786d01", - "version": "1.5.0" + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" }, "onRamp": { - "address": "0xAa60b228bB30f2d31a4410BD65eC5d9234456F42", - "enforceOutOfOrder": false, - "version": "1.5.0" + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" }, - "supportedTokens": { - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["WHLP"] }, - "ethereum-mainnet-ink-1": { + "mainnet": { "offRamp": { - "address": "0xC6102A4517370B8094F788C9a3211D7432e24b97", - "version": "1.5.0" + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" }, "onRamp": { - "address": "0x89392B6C2e5B789A3854F082e34860ff45A97da3", - "enforceOutOfOrder": false, - "version": "1.5.0" + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } - } + "supportedTokens": [ + "FHE", + "FLUID", + "LINK", + "MEW", + "OHM", + "PEPE", + "PTsUSDE", + "SolvBTC", + "USD1", + "USDC", + "WFRAGSOL", + "WLFI", + "WMTX", + "brBTC", + "elizaOS", + "syrupUSDC", + "uniBTC", + "xSolvBTC", + "zBTC" + ] }, - "mainnet": { + "matic-mainnet": { "offRamp": { - "address": "0x409c2609856CA8B40feed2E1F887426BC36c746B", - "version": "1.5.0" + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" }, "onRamp": { - "address": "0xbcC5895bb1bf1737f8c5088c5677302e3fdeb75c", - "enforceOutOfOrder": false, - "version": "1.5.0" + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" }, - "supportedTokens": { - "DEGEN": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "pufETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SKYA": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "60000000000000000000", - "isEnabled": true, - "rate": "694440000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "WASTR": { + "supportedTokens": ["USDC"] + }, + "memento-mainnet": { + "offRamp": { + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" + }, + "onRamp": { + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "monad-mainnet": { + "offRamp": { + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" + }, + "onRamp": { + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": { + "W0G": { "rateLimiterConfig": { "in": { "capacity": "0", @@ -33425,530 +9225,258 @@ "rate": "0" } } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "60000000000000000000", - "isEnabled": true, - "rate": "694440000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } } } }, - "matic-mainnet": { + "plasma-mainnet": { "offRamp": { - "address": "0xDE60CB594cD7E8b328680d8C7758F6a128752F92", + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" + }, + "onRamp": { + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["FLUID", "USX", "eUSX"] + }, + "polygon-mainnet-katana": { + "offRamp": { + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" + }, + "onRamp": { + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "sei-mainnet": { + "offRamp": { + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" + }, + "onRamp": { + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "shibarium-mainnet": { + "offRamp": { + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" + }, + "onRamp": { + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, + "sonic-mainnet": { + "offRamp": { + "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", + "version": "1.6.0" + }, + "onRamp": { + "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["LINK", "MEW", "zBTC"] + } + }, + "soneium-mainnet": { + "bitcoin-mainnet-bob-1": { + "offRamp": { + "address": "0xD0734ef5044B73929248637099caa122580531CB", "version": "1.5.0" }, "onRamp": { - "address": "0x653872449Df3008376e93A3d178c2739cc31eDdA", + "address": "0xD9F8Dd97688653965e57421a859520c144Fc176C", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - } + "supportedTokens": ["SolvBTC", "SolvBTC.JUP", "xSolvBTC"] + }, + "bitcoin-mainnet-bsquared-1": { + "offRamp": { + "address": "0xF149aa4fA6e21cA94153aeA833145f0997166dea", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x911D4D671Ec2ACE5213E50f493dEc43cB556798B", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "polkadot-mainnet-astar": { + "bsc-mainnet": { "offRamp": { - "address": "0x432072b9f18d5976EF1e69D7Fb1EC335511e92C6", + "address": "0x45004bA967A5a6a4cB7DB9C0FF9F67Ad77E2208F", "version": "1.5.0" }, "onRamp": { - "address": "0xEb9E93ca8047DD64BE46D249BD1E01E9473eBB58", + "address": "0x3381fFEb675a2018357DC8A020B721cB227b5087", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "WASTR": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - } - }, - "sonic-mainnet": { - "aptos-mainnet": { + "supportedTokens": ["SKYA", "SolvBTC.JUP"] + }, + "celo-mainnet": { "offRamp": { - "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", - "version": "1.6.0" + "address": "0x2048413F78F6BF7b3499b28321e7B55a3aD95e56", + "version": "1.5.0" }, "onRamp": { - "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", - "enforceOutOfOrder": true, - "version": "1.6.0" + "address": "0x4DFe6A7bd2A7B365EC93135221F2e7305A180bb9", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0xe9839BC342F22a6ABF11c0831Bf881F0eddc4bBb", + "version": "1.5.0" }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - } + "onRamp": { + "address": "0xFF7693049430da19E3957533a8aF45036eEe3594", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, - "avalanche-mainnet": { + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0x9076066423bC9a078D323eD2Aa652d324b77Be83", + "address": "0x5eB8e2aB40b54190bb49D05867d6572891786d01", "version": "1.5.0" }, "onRamp": { - "address": "0x0c245Dc1416C1180a383fce32Ef698Bf1fCf3169", + "address": "0xAa60b228bB30f2d31a4410BD65eC5d9234456F42", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["SKYA"] + }, + "ethereum-mainnet-ink-1": { + "offRamp": { + "address": "0xC6102A4517370B8094F788C9a3211D7432e24b97", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x89392B6C2e5B789A3854F082e34860ff45A97da3", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, - "bitcoin-mainnet-bob-1": { + "mainnet": { "offRamp": { - "address": "0xb32b4D72BbFBcbfBB342E993726D3597E6F1042d", + "address": "0x409c2609856CA8B40feed2E1F887426BC36c746B", "version": "1.5.0" }, "onRamp": { - "address": "0xD5e0999C86347d8A51519240f055A27be86258A8", + "address": "0xbcC5895bb1bf1737f8c5088c5677302e3fdeb75c", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - } - } + "supportedTokens": ["DEGEN", "LINK", "SKYA", "SolvBTC", "WASTR", "pufETH", "xSolvBTC"] }, - "bsc-mainnet": { + "matic-mainnet": { "offRamp": { - "address": "0x34762981e807034f6c0155Fe50EdA48E9fe9B832", + "address": "0xDE60CB594cD7E8b328680d8C7758F6a128752F92", "version": "1.5.0" }, "onRamp": { - "address": "0xb24d54916EC661B655AfFC93c04647032E7e46Ac", + "address": "0x653872449Df3008376e93A3d178c2739cc31eDdA", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } + "supportedTokens": ["SolvBTC", "xSolvBTC"] }, - "core-mainnet": { + "polkadot-mainnet-astar": { "offRamp": { - "address": "0x537ff0B45f1A9408cb01607977FDE5995A01B6d3", + "address": "0x432072b9f18d5976EF1e69D7Fb1EC335511e92C6", "version": "1.5.0" }, "onRamp": { - "address": "0x685331b773177dAc6B54cc078C84598991D08E0b", + "address": "0xEb9E93ca8047DD64BE46D249BD1E01E9473eBB58", "enforceOutOfOrder": false, "version": "1.5.0" - } + }, + "supportedTokens": ["LINK", "WASTR"] + } + }, + "sonic-mainnet": { + "aptos-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": true, + "version": "1.6.0" + }, + "supportedTokens": ["LINK"] }, - "ethereum-mainnet-arbitrum-1": { + "avalanche-mainnet": { "offRamp": { - "address": "0x78867d5D2791eFE73df1cE23Fb7bF4B2db94EE0D", + "address": "0x9076066423bC9a078D323eD2Aa652d324b77Be83", "version": "1.5.0" }, "onRamp": { - "address": "0xF0592475d795FB9Ef80B2ddB511d8c6Eb14D821F", + "address": "0x0c245Dc1416C1180a383fce32Ef698Bf1fCf3169", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1000000000000000000000000" - }, - "out": { - "capacity": "10000000000000000000000000", - "isEnabled": true, - "rate": "1000000000000000000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "supportedTokens": ["BOLD", "LBTC", "SILO", "VRTX", "xSILO"] + }, + "berachain-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "ethereum-mainnet-base-1": { + "bitcoin-mainnet-bob-1": { "offRamp": { - "address": "0xA8a877a0F7d3A837A98931b33d45aFd759F98C98", + "address": "0xb32b4D72BbFBcbfBB342E993726D3597E6F1042d", "version": "1.5.0" }, "onRamp": { - "address": "0xf54853C3502716D9673E1D71BbC94E16C20277E7", + "address": "0xD5e0999C86347d8A51519240f055A27be86258A8", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BMX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "VRTX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - } - } + "supportedTokens": ["USDT"] }, - "ethereum-mainnet-ink-1": { + "bsc-mainnet": { "offRamp": { - "address": "0x1E2786683e6fBF80B8773e53e6baB4684Bd20E90", + "address": "0x34762981e807034f6c0155Fe50EdA48E9fe9B832", "version": "1.5.0" }, "onRamp": { - "address": "0x0b3a51B27855e6D7a1CE7a47F6fF3922c2CfB0C8", + "address": "0xb24d54916EC661B655AfFC93c04647032E7e46Ac", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["LBTC", "mBTC", "wUSDx"] + }, + "core-mainnet": { + "offRamp": { + "address": "0x537ff0B45f1A9408cb01607977FDE5995A01B6d3", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x685331b773177dAc6B54cc078C84598991D08E0b", "enforceOutOfOrder": false, "version": "1.5.0" } }, - "ethereum-mainnet-linea-1": { + "corn-mainnet": { "offRamp": { "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", "version": "1.6.0" @@ -33959,322 +9487,125 @@ "version": "1.6.0" } }, - "ethereum-mainnet-mode-1": { + "ethereum-mainnet-arbitrum-1": { "offRamp": { - "address": "0xb74319e12FAfC25eca5E28fF19192B54616DaCDA", + "address": "0x78867d5D2791eFE73df1cE23Fb7bF4B2db94EE0D", "version": "1.5.0" }, "onRamp": { - "address": "0xc6a4FD636d6b05506b771373484C9Eb29d46b8e0", + "address": "0xF0592475d795FB9Ef80B2ddB511d8c6Eb14D821F", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BMX": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } + "supportedTokens": ["BOLD", "SILO", "VRTX", "mBTC", "wUSDx", "xSILO"] }, - "ethereum-mainnet-optimism-1": { + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0x30bFcE34462E446aA0304850033bb5339D74AFa4", + "address": "0xA8a877a0F7d3A837A98931b33d45aFd759F98C98", "version": "1.5.0" }, "onRamp": { - "address": "0xCe92bcE99a58cA396C0CE622f1521850535A6064", + "address": "0xf54853C3502716D9673E1D71BbC94E16C20277E7", "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - } - } + "supportedTokens": ["BMX", "BOLD", "LBTC", "USDT", "VRTX", "wUSDx", "zBTC"] }, - "ethereum-mainnet-unichain-1": { + "ethereum-mainnet-ink-1": { "offRamp": { - "address": "0xD9F9978e039C4Cc2A0177be04bF8578C91d6E091", + "address": "0x1E2786683e6fBF80B8773e53e6baB4684Bd20E90", "version": "1.5.0" }, "onRamp": { - "address": "0x5570D450909B114B59D2D728Fdb6Eea6720ae4d8", + "address": "0x0b3a51B27855e6D7a1CE7a47F6fF3922c2CfB0C8", "enforceOutOfOrder": false, "version": "1.5.0" } }, - "mainnet": { + "ethereum-mainnet-linea-1": { "offRamp": { - "address": "0x7c6963669EBFf136EE36c053EcF0089d59eE2287", - "version": "1.5.0" + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" }, "onRamp": { - "address": "0xF487000Fe6FE14Fd5E7E86514219994eCEaB6bA7", + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-mode-1": { + "offRamp": { + "address": "0xb74319e12FAfC25eca5E28fF19192B54616DaCDA", "version": "1.5.0" }, - "supportedTokens": { - "BOLD": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "egETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "mBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - }, - "out": { - "capacity": "400000000", - "isEnabled": true, - "rate": "18518" - } - } - }, - "mstETH": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - }, - "out": { - "capacity": "100000000000000000000", - "isEnabled": true, - "rate": "9260000000000000" - } - } - }, - "SILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "SolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - }, - "USDT": { - "rateLimiterConfig": { - "in": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - }, - "out": { - "capacity": "10000000000000", - "isEnabled": true, - "rate": "5000000000" - } - } - }, - "wUSDx": { - "rateLimiterConfig": { - "in": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - }, - "out": { - "capacity": "490000000000", - "isEnabled": true, - "rate": "136111000" - } - } - }, - "xSILO": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "xSolvBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - }, - "out": { - "capacity": "2500000000000000000", - "isEnabled": true, - "rate": "115740000000000" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - } + "onRamp": { + "address": "0xc6a4FD636d6b05506b771373484C9Eb29d46b8e0", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BMX", "wUSDx"] + }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0x30bFcE34462E446aA0304850033bb5339D74AFa4", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xCe92bcE99a58cA396C0CE622f1521850535A6064", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BOLD", "USDT", "wUSDx"] + }, + "ethereum-mainnet-unichain-1": { + "offRamp": { + "address": "0xD9F9978e039C4Cc2A0177be04bF8578C91d6E091", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x5570D450909B114B59D2D728Fdb6Eea6720ae4d8", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + }, + "etherlink-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, + "mainnet": { + "offRamp": { + "address": "0x7c6963669EBFf136EE36c053EcF0089d59eE2287", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xF487000Fe6FE14Fd5E7E86514219994eCEaB6bA7", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": [ + "BOLD", + "LBTC", + "LINK", + "SILO", + "SolvBTC", + "USDT", + "egETH", + "mBTC", + "mstETH", + "uniBTC", + "wUSDx", + "xSILO", + "xSolvBTC", + "zBTC" + ] + }, "matic-mainnet": { "offRamp": { "address": "0x614Ba49125B7b74F0CE979bC18B0C36395356E9d", @@ -34286,7 +9617,7 @@ "version": "1.5.0" } }, - "monad-mainnet": { + "megaeth-mainnet": { "offRamp": { "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", "version": "1.6.0" @@ -34313,6 +9644,18 @@ } } }, + "monad-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, "polygon-mainnet-katana": { "offRamp": { "address": "0xaDD9e69F0d1f6885Ae7d07aC0184D5Ed560f16cc", @@ -34323,22 +9666,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - } - } + "supportedTokens": ["LBTC"] }, "solana-mainnet": { "offRamp": { @@ -34350,78 +9678,220 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000", - "isEnabled": true, - "rate": "13880000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "13880000000000000000" - } - } - }, - "MEW": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - }, - "out": { - "capacity": "5000000000000", - "isEnabled": true, - "rate": "1388888888" - } - } - }, - "zBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - }, - "out": { - "capacity": "1000000000", - "isEnabled": true, - "rate": "11574" - } - } - } + "supportedTokens": ["LINK", "MEW", "zBTC"] + }, + "stable-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "tac-mainnet": { + "offRamp": { + "address": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x76a443768A5e3B8d1AED0105FC250877841Deb40", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "xdai-mainnet": { + "offRamp": { + "address": "0x8dc1d6233Cc4cA5C90fF4b068Af4d11ca1F38eA2", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xeb53521B58c42f15De01a1d449DAE8DdC5bb08Dd", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "stable-mainnet": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "berachain-mainnet": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "bsc-mainnet": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "ethereum-mainnet-arbitrum-1": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "etherlink-mainnet": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "mainnet": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC", "LINK"] + }, + "monad-mainnet": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "polygon-mainnet-katana": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + }, + "sonic-mainnet": { + "offRamp": { + "address": "0x3FD9aD7dC98e98c5E3FAB8d20f8aAEe5f7809933", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xD21D5a4e3fA0eBACC3DaBB5258d9C1F4d24dc894", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["LBTC"] + } + }, + "superseed-mainnet": { + "mainnet": { + "offRamp": { + "address": "0x07453fcf23f087B4CA409CB4e85C416f8fC6634A", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xf04D4Aa2e302cD4995D8cf8e84727c5B441e85ce", + "enforceOutOfOrder": false, + "version": "1.5.0" + } + } + }, + "tac-mainnet": { + "avalanche-mainnet": { + "offRamp": { + "address": "0x3201a20D2a33820C0DaC8Bc93C4819755C2a8c7F", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x51e2A24742Db77604B881d6781Ee16B5b8fcBE29", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "berachain-mainnet": { + "offRamp": { + "address": "0x3201a20D2a33820C0DaC8Bc93C4819755C2a8c7F", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x51e2A24742Db77604B881d6781Ee16B5b8fcBE29", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, - "xdai-mainnet": { + "bsc-mainnet": { "offRamp": { - "address": "0x8dc1d6233Cc4cA5C90fF4b068Af4d11ca1F38eA2", - "version": "1.5.0" + "address": "0x3201a20D2a33820C0DaC8Bc93C4819755C2a8c7F", + "version": "1.6.0" }, "onRamp": { - "address": "0xeb53521B58c42f15De01a1d449DAE8DdC5bb08Dd", + "address": "0x51e2A24742Db77604B881d6781Ee16B5b8fcBE29", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" } - } - }, - "superseed-mainnet": { - "mainnet": { + }, + "ethereum-mainnet-base-1": { "offRamp": { - "address": "0x07453fcf23f087B4CA409CB4e85C416f8fC6634A", - "version": "1.5.0" + "address": "0x3201a20D2a33820C0DaC8Bc93C4819755C2a8c7F", + "version": "1.6.0" }, "onRamp": { - "address": "0xf04D4Aa2e302cD4995D8cf8e84727c5B441e85ce", + "address": "0x51e2A24742Db77604B881d6781Ee16B5b8fcBE29", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" } - } - }, - "tac-mainnet": { - "bsc-mainnet": { + }, + "etherlink-mainnet": { "offRamp": { "address": "0x3201a20D2a33820C0DaC8Bc93C4819755C2a8c7F", "version": "1.6.0" @@ -34453,78 +9923,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "LBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - }, - "out": { - "capacity": "5000000000", - "isEnabled": true, - "rate": "462963" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "RETH": { - "rateLimiterConfig": { - "in": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - }, - "out": { - "capacity": "1800000000000000000000", - "isEnabled": true, - "rate": "5787000000000000" - } - } - }, - "tETH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "uniBTC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "200000000", - "isEnabled": true, - "rate": "2315" - } - } - } - } + "supportedTokens": ["LBTC", "LINK", "RETH", "tETH", "uniBTC"] } }, "wemix-mainnet": { @@ -34538,22 +9937,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } - } + "supportedTokens": ["una.WEMIX"] }, "bsc-mainnet": { "offRamp": { @@ -34565,22 +9949,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } - } + "supportedTokens": ["una.WEMIX"] }, "ethereum-mainnet-arbitrum-1": { "offRamp": { @@ -34590,174 +9959,45 @@ "onRamp": { "address": "0xA89c8E2b85a6BeC901C29107E9B640Ff256fc762", "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } - } - }, - "ethereum-mainnet-base-1": { - "offRamp": { - "address": "0xdF04f12f2CFd7e24c619738227fc3C186Ac97220", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xA251033386Ec311FF8FbE55971bAb834093a6486", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-mainnet-optimism-1": { - "offRamp": { - "address": "0xd76783CF6A98C95F5927b4b98D5E1Efb78CFc563", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x96c4e2B1b2c949F570D5992272B7722a3a1d1709", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } - } - }, - "mainnet": { - "offRamp": { - "address": "0x76DE34244b92aB9F4e9D550269Ef1CAdE0d1A2E9", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x6c6Dd4fCa5A7B2F11AA3057AB573DD8878C76C5e", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "4630000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "una.USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "300000000000", - "isEnabled": true, - "rate": "83330000" - }, - "out": { - "capacity": "300000000000", - "isEnabled": true, - "rate": "83330000" - } - } - }, - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } + "version": "1.5.0" + }, + "supportedTokens": ["una.WEMIX"] + }, + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0xdF04f12f2CFd7e24c619738227fc3C186Ac97220", + "version": "1.5.0" + }, + "onRamp": { + "address": "0xA251033386Ec311FF8FbE55971bAb834093a6486", + "enforceOutOfOrder": false, + "version": "1.5.0" } }, + "ethereum-mainnet-optimism-1": { + "offRamp": { + "address": "0xd76783CF6A98C95F5927b4b98D5E1Efb78CFc563", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x96c4e2B1b2c949F570D5992272B7722a3a1d1709", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["una.WEMIX"] + }, + "mainnet": { + "offRamp": { + "address": "0x76DE34244b92aB9F4e9D550269Ef1CAdE0d1A2E9", + "version": "1.5.0" + }, + "onRamp": { + "address": "0x6c6Dd4fCa5A7B2F11AA3057AB573DD8878C76C5e", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["BONE", "LEASH", "LINK", "SHIB", "USDC", "una.USDC", "una.WEMIX"] + }, "matic-mainnet": { "offRamp": { "address": "0xe22ef88FccfE6C304Fd245005e959837C86B52F6", @@ -34768,22 +10008,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "una.WEMIX": { - "rateLimiterConfig": { - "in": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - }, - "out": { - "capacity": "200000000000000000000000", - "isEnabled": true, - "rate": "55550000000000000000" - } - } - } - } + "supportedTokens": ["una.WEMIX"] } }, "xdai-mainnet": { @@ -34808,22 +10033,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } + "supportedTokens": ["GHO"] }, "bsc-mainnet": { "offRamp": { @@ -34846,22 +10056,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } + "supportedTokens": ["GHO"] }, "ethereum-mainnet-base-1": { "offRamp": { @@ -34873,22 +10068,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } + "supportedTokens": ["GHO"] }, "ethereum-mainnet-ink-1": { "offRamp": { @@ -34900,6 +10080,29 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, + "supportedTokens": ["GHO"] + }, + "ethereum-mainnet-linea-1": { + "offRamp": { + "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x5fA6f142EAC511DF12325776386AB92B0F4D1eba", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, + "ethereum-mainnet-mantle-1": { + "offRamp": { + "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x5fA6f142EAC511DF12325776386AB92B0F4D1eba", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, "supportedTokens": { "GHO": { "rateLimiterConfig": { @@ -34917,17 +10120,6 @@ } } }, - "ethereum-mainnet-linea-1": { - "offRamp": { - "address": "0x6525923279256B8a86c1C01cF5955eB00C39B048", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x5fA6f142EAC511DF12325776386AB92B0F4D1eba", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, "ethereum-mainnet-optimism-1": { "offRamp": { "address": "0xd84E2316634ab6516Ecc829E2367633bfB3e4B6D", @@ -34960,78 +10152,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "BONE": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - }, - "LEASH": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "REG": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - } - } - }, - "SHIB": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["BONE", "GHO", "LEASH", "REG", "SHIB"] }, "matic-mainnet": { "offRamp": { @@ -35043,22 +10164,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "REG": { - "rateLimiterConfig": { - "in": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - }, - "out": { - "capacity": "50000000000000000000000", - "isEnabled": true, - "rate": "14000000000000000000" - } - } - } - } + "supportedTokens": ["REG"] }, "plasma-mainnet": { "offRamp": { @@ -35070,22 +10176,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "GHO": { - "rateLimiterConfig": { - "in": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - }, - "out": { - "capacity": "1500000000000000000000000", - "isEnabled": true, - "rate": "300000000000000000000" - } - } - } - } + "supportedTokens": ["GHO"] }, "sonic-mainnet": { "offRamp": { @@ -35100,6 +10191,17 @@ } }, "xdc-mainnet": { + "ethereum-mainnet-base-1": { + "offRamp": { + "address": "0xE939C02E92e9E66d1F0D8E4F099E7d3d269a8a11", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x40530f5305d6Fd6912925C5ec2C36453B85d8F5f", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + }, "mainnet": { "offRamp": { "address": "0xE939C02E92e9E66d1F0D8E4F099E7d3d269a8a11", @@ -35110,36 +10212,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "LINK": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDf": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["LINK", "USDf"] } }, "zora-mainnet": { diff --git a/src/config/data/ccip/v1_2_0/mainnet/tokens.json b/src/config/data/ccip/v1_2_0/mainnet/tokens.json index aa901b607fb..0c9cacb7895 100644 --- a/src/config/data/ccip/v1_2_0/mainnet/tokens.json +++ b/src/config/data/ccip/v1_2_0/mainnet/tokens.json @@ -4,8 +4,12 @@ "allowListEnabled": false, "decimals": 18, "name": "PAAL AI", - "poolAddress": "0xE4De5151eD60Aa2086172c4caec29f058d16E46e", - "poolType": "burnMint", + "pool": { + "address": "0xE4De5151eD60Aa2086172c4caec29f058d16E46e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "$PAAL", "tokenAddress": "0xbb1B031c591235408755ff4E0739cb88C5cF2507" }, @@ -13,8 +17,12 @@ "allowListEnabled": false, "decimals": 18, "name": "PAAL AI", - "poolAddress": "0x5192Bd10f28A0206211CcBB66671118f85c2E539", - "poolType": "burnMint", + "pool": { + "address": "0x5192Bd10f28A0206211CcBB66671118f85c2E539", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "$PAAL", "tokenAddress": "0xd52333441c0553fACb259600FA833a69186893A5" }, @@ -22,8 +30,12 @@ "allowListEnabled": false, "decimals": 9, "name": "PAAL AI", - "poolAddress": "0x1A4B0621E90Bdc61d341D89158863458CA745dA2", - "poolType": "lockRelease", + "pool": { + "address": "0x1A4B0621E90Bdc61d341D89158863458CA745dA2", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "$PAAL", "tokenAddress": "0x14feE680690900BA0ccCfC76AD70Fd1b95D10e16" } @@ -33,8 +45,12 @@ "allowListEnabled": false, "decimals": 18, "name": "One-XMM Token", - "poolAddress": "0xFdcB1fB6675b7d7c33933Ef56BD031c7B084Af29", - "poolType": "burnMint", + "pool": { + "address": "0xFdcB1fB6675b7d7c33933Ef56BD031c7B084Af29", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "1XMM", "tokenAddress": "0x504C024fcDc01C30ee6379e3381144Df24Bc01B9" }, @@ -42,8 +58,12 @@ "allowListEnabled": false, "decimals": 18, "name": "One-XMM Token", - "poolAddress": "0xF56dcA7a981a53ec2EbeF2040800F04206021583", - "poolType": "burnMint", + "pool": { + "address": "0xF56dcA7a981a53ec2EbeF2040800F04206021583", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "1XMM", "tokenAddress": "0x958d200A49F4765f771C61d2649965e26277fB64" }, @@ -51,8 +71,12 @@ "allowListEnabled": false, "decimals": 18, "name": "One-XMM Token", - "poolAddress": "0x955c82760CAec660Bc823726ee3a90ef53C24577", - "poolType": "burnMint", + "pool": { + "address": "0x955c82760CAec660Bc823726ee3a90ef53C24577", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "1XMM", "tokenAddress": "0xfDC362324740B3CA225ee0E54063746EecB2BFd9" } @@ -62,8 +86,12 @@ "allowListEnabled": false, "decimals": 18, "name": "AicroStrategy", - "poolAddress": "0xafa0f7EEDd310168Ba84BddDA550BA9c93F1083d", - "poolType": "burnMint", + "pool": { + "address": "0xafa0f7EEDd310168Ba84BddDA550BA9c93F1083d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "AISTR", "tokenAddress": "0xFFd2087838d18225DE3428DFAEeFa4432E7D227F" }, @@ -71,8 +99,12 @@ "allowListEnabled": false, "decimals": 18, "name": "AicroStrategy", - "poolAddress": "0xF4fD65FE6E60822C22B3580ee43FA6E955adb3Ab", - "poolType": "lockRelease", + "pool": { + "address": "0xF4fD65FE6E60822C22B3580ee43FA6E955adb3Ab", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "AISTR", "tokenAddress": "0x323ac72a3a6267D97427944989b896fB411fdCbb" }, @@ -80,8 +112,12 @@ "allowListEnabled": false, "decimals": 18, "name": "AicroStrategy", - "poolAddress": "0xCDc4325995dE9Bd013c606da4D21519A99041673", - "poolType": "burnMint", + "pool": { + "address": "0xCDc4325995dE9Bd013c606da4D21519A99041673", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "AISTR", "tokenAddress": "0xaE1c4c55b0C82C02b0C933d1F890f8fa9D599D3f" }, @@ -89,8 +125,12 @@ "allowListEnabled": false, "decimals": 18, "name": "AicroStrategy", - "poolAddress": "0xe4a9fa29E3d88660577E4ACD9bf88Ef2DF4F8D7C", - "poolType": "burnMint", + "pool": { + "address": "0xe4a9fa29E3d88660577E4ACD9bf88Ef2DF4F8D7C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "AISTR", "tokenAddress": "0xBD4CaeE14EFDE2888F167130AF84D613D64618Da" } @@ -100,8 +140,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Anima", - "poolAddress": "0xD4C6184DEC4e10395AB84b9e7a7ab46d0D57329e", - "poolType": "burnMint", + "pool": { + "address": "0xD4C6184DEC4e10395AB84b9e7a7ab46d0D57329e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "ANIMA", "tokenAddress": "0x153A381D1207862cA003f68600462fAa66A828a7" }, @@ -109,19 +153,47 @@ "allowListEnabled": false, "decimals": 18, "name": "Anima", - "poolAddress": "0xD27F88501e62D0BDc70B20d6ed06d8E0fF8c3812", - "poolType": "lockRelease", + "pool": { + "address": "0xD27F88501e62D0BDc70B20d6ed06d8E0fF8c3812", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "ANIMA", "tokenAddress": "0xF80132FC0A86ADd011BffCe3AedD60A86E3d704D" } }, + "aprMON": { + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "aPriori LST", + "poolAddress": "0x3a138a2bA7DBA72ACBCdb2DCFBaF02ce311e5d0F", + "poolType": "burnMint", + "symbol": "aprMON", + "tokenAddress": "0x93783ccd94763e11B9a57394e63Ddd9CeedaD925" + }, + "monad-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "aPriori Monad LST", + "poolAddress": "0x3AaFf16d7f8c9163AF6e0f14Ec46CbA5bdc8C6C3", + "poolType": "lockRelease", + "symbol": "aprMON", + "tokenAddress": "0x0c65A0BC65a5D819235B71F554D210D3F80E0852" + } + }, "APRS": { "mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Aperios", - "poolAddress": "0x5882D12bbf902ee88d5FCF8793113ae85fFe97b1", - "poolType": "lockRelease", + "pool": { + "address": "0x5882D12bbf902ee88d5FCF8793113ae85fFe97b1", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "APRS", "tokenAddress": "0x95b4B8CaD3567B5d7EF7399C2aE1d7070692aB0D" }, @@ -129,10 +201,14 @@ "allowListEnabled": false, "decimals": 18, "name": "Aperios", - "poolAddress": "0x5dbBF90Ad00130Fd2Eb788016DcB3E4dFbD0C519", - "poolType": "burnMint", + "pool": { + "address": "0x5dbBF90Ad00130Fd2Eb788016DcB3E4dFbD0C519", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "APRS", - "tokenAddress": "0x7894b3088d069E70895EFfA4e8f7D2c243Fd04C1" + "tokenAddress": "0xB1eC71BE31da4fF603970c0d88584eF2aF102F38" } }, "APT": { @@ -140,7 +216,11 @@ "allowListEnabled": false, "decimals": 8, "name": "Aptos Coin", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "APT", "tokenAddress": "0x000000000000000000000000000000000000000000000000000000000000000A" } @@ -150,8 +230,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Apu Apustaja", - "poolAddress": "0x924982D6616962E7009f5f1fFe6F24ee1e58A2F4", - "poolType": "burnMint", + "pool": { + "address": "0x924982D6616962E7009f5f1fFe6F24ee1e58A2F4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "APU", "tokenAddress": "0x1F53B7aA6f4b36B7DfDEDb4Bc4A14747a19cf7B1" }, @@ -159,8 +243,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Apu Apustaja", - "poolAddress": "0xdf59f3eA407816FcC9e724fF29c5593a536e7984", - "poolType": "burnMint", + "pool": { + "address": "0xdf59f3eA407816FcC9e724fF29c5593a536e7984", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "APU", "tokenAddress": "0xB9926b3fBc5873Db0182016D55727D5ae89E5EFd" }, @@ -168,19 +256,97 @@ "allowListEnabled": false, "decimals": 18, "name": "Apu Apustaja", - "poolAddress": "0x0577EcCC8FBE54B321d3BC8d4F1d09Deb94d5A55", - "poolType": "lockRelease", + "pool": { + "address": "0x0577EcCC8FBE54B321d3BC8d4F1d09Deb94d5A55", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "APU", "tokenAddress": "0x594DaaD7D77592a2b97b725A7AD59D7E188b5bFa" } }, + "avBTC": { + "avalanche-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "avBTC", + "pool": { + "address": "0x5684B0455837d41e47260a31bD954bE72C935E32", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, + "symbol": "avBTC", + "tokenAddress": "0xfd2c2A98009d0cBed715882036e43d26C4289053" + }, + "ethereum-mainnet-linea-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "avBTC", + "pool": { + "address": "0xCE7Eb84463675C6dD219A6A8939Cc36F650808c6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, + "symbol": "avBTC", + "tokenAddress": "0x2D4C0d9742cd0F11b3627f103A3dDd9C8AE341b6" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "avBTC", + "pool": { + "address": "0x63bd4CC0A4F72cb3a6181604d03633671e5A93d2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "avBTC", + "tokenAddress": "0x84d797c33708E5bDbfdB73481530DCf8c03eC17E" + } + }, + "avBTCx": { + "avalanche-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "avBTC MAX", + "poolAddress": "0xC178A94C9C872C101b6DD3C6fc495C99b79e3db5", + "poolType": "lockRelease", + "symbol": "avBTCx", + "tokenAddress": "0xa7C10C510df4B1702E1F36451dd29D7C3EDC760C" + }, + "ethereum-mainnet-linea-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "avBTC MAX", + "poolAddress": "0x73FA08D6DC478eef89da438004682E37A5ea0D2e", + "poolType": "burnMint", + "symbol": "avBTCx", + "tokenAddress": "0x788002EBa02a9301008f03bf59c4B233E2272EB7" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "avBTC MAX", + "poolAddress": "0x1dD1b7F40B205B6836E87f1ed25A628ad35ba99e", + "poolType": "burnMint", + "symbol": "avBTCx", + "tokenAddress": "0x9Bc15d6dCB23EFbdCC235Bf54159B6E8bAd23dca" + } + }, "avETH": { "avalanche-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "avETH", - "poolAddress": "0xBEC991c38A8D2b04F7A2a6F2d9304078DFD33dB6", - "poolType": "burnMint", + "pool": { + "address": "0xBEC991c38A8D2b04F7A2a6F2d9304078DFD33dB6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "avETH", "tokenAddress": "0x223767286Be11d09Ae778fF608687fe858d3A2b4" }, @@ -188,8 +354,12 @@ "allowListEnabled": false, "decimals": 18, "name": "avETH", - "poolAddress": "0x9b52Ab55cFA7aB0079f84390b24Fdc0e5bF5Ab6F", - "poolType": "burnMint", + "pool": { + "address": "0x9b52Ab55cFA7aB0079f84390b24Fdc0e5bF5Ab6F", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "avETH", "tokenAddress": "0x3449A9155Afc1Bab56A572FdfE22A3a2B803AaC4" }, @@ -197,8 +367,12 @@ "allowListEnabled": false, "decimals": 18, "name": "avETH", - "poolAddress": "0xbD09E8846B9DbdA54Ef386Bd9eF3bbd15Add50ee", - "poolType": "lockRelease", + "pool": { + "address": "0xbD09E8846B9DbdA54Ef386Bd9eF3bbd15Add50ee", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "avETH", "tokenAddress": "0x9469470C9878bf3d6d0604831d9A3A366156f7EE" } @@ -208,8 +382,12 @@ "allowListEnabled": false, "decimals": 18, "name": "avETH MAX", - "poolAddress": "0xbb8a25Ee9509bDA375699F6977DfaaC04c08BADa", - "poolType": "burnMint", + "pool": { + "address": "0xbb8a25Ee9509bDA375699F6977DfaaC04c08BADa", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "avETHx", "tokenAddress": "0xDA63630094Aa23B7a49368b713d68dD98F547f98" }, @@ -217,8 +395,12 @@ "allowListEnabled": false, "decimals": 18, "name": "avETH MAX", - "poolAddress": "0x37912A5e451DC711D357E2dC6Bf9035235d6771f", - "poolType": "burnMint", + "pool": { + "address": "0x37912A5e451DC711D357E2dC6Bf9035235d6771f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "avETHx", "tokenAddress": "0x01C9ABFebCDcb53E72bF017Fc1D17F9DB38F722a" }, @@ -226,19 +408,109 @@ "allowListEnabled": false, "decimals": 18, "name": "avETH MAX", - "poolAddress": "0x18d3ebcEF1074f30aba5Da3951FF1a87B30B6Ec1", - "poolType": "lockRelease", + "pool": { + "address": "0x18d3ebcEF1074f30aba5Da3951FF1a87B30B6Ec1", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "avETHx", "tokenAddress": "0x2E8b7190eE84E7AC757Ddff42Ba14d4EAe24B865" } }, + "avUSD": { + "avalanche-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "avUSD", + "pool": { + "address": "0xD4fe4186c4A7b089eb849d57b43C5F6a3d3BcCbe", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, + "symbol": "avUSD", + "tokenAddress": "0x24dE8771bC5DdB3362Db529Fc3358F2df3A0E346" + }, + "ethereum-mainnet-linea-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "avUSD", + "pool": { + "address": "0x9F299fbDbB581E55217c15b8439588e16b95018f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "avUSD", + "tokenAddress": "0x37c44fc08e403Efc0946C0623CB1164A52CE1576" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "avUSD", + "pool": { + "address": "0x81B72171642FaB457aa815C0B8412A22B63A6aF8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "avUSD", + "tokenAddress": "0xf4c13D631450De6B12a19829E37c8e2826891dC4" + } + }, + "avUSDx": { + "avalanche-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "avUSD MAX", + "pool": { + "address": "0x89541CE9940DFA3add6D6dc2e20E3F743075DFF5", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, + "symbol": "avUSDx", + "tokenAddress": "0xDd1cDFA52E7D8474d434cd016fd346701db6B3B9" + }, + "ethereum-mainnet-linea-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "avUSD MAX", + "pool": { + "address": "0x2c12313da5465D6da6E0A3574249A30839Fe8766", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "avUSDx", + "tokenAddress": "0xC37d32b09B0bB0aa9B2A70372d7Bc1216CB7D903" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "avUSD MAX", + "pool": { + "address": "0xD08f814614Fb21bdcdd3Aa92123e2F954F9864b7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "avUSDx", + "tokenAddress": "0xF424a63E4aC41b1faC5074Ccc24c7E5048fcA25D" + } + }, "AXS": { "mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Axie Infinity Shard", - "poolAddress": "0xf33341f2CE329B5DbCa7F9a0986Cff40d050440a", - "poolType": "lockRelease", + "pool": { + "address": "0xf33341f2CE329B5DbCa7F9a0986Cff40d050440a", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "AXS", "tokenAddress": "0xBB0E17EF65F82Ab018d8EDd776e8DD940327B28b" }, @@ -246,8 +518,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Axie Infinity Shard", - "poolAddress": "0x554652E7F10fB8aa3e12226213c6826F98B09CF0", - "poolType": "burnMint", + "pool": { + "address": "0x554652E7F10fB8aa3e12226213c6826F98B09CF0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "AXS", "tokenAddress": "0x97a9107C1793BC407d6F527b77e7fff4D812bece" } @@ -257,8 +533,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Banana", - "poolAddress": "0xB18eE11849a805651aC5D456034FD6352cfF635d", - "poolType": "lockRelease", + "pool": { + "address": "0xB18eE11849a805651aC5D456034FD6352cfF635d", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "BANANA", "tokenAddress": "0x94e496474F1725f1c1824cB5BDb92d7691A4F03a" }, @@ -266,8 +546,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Banana", - "poolAddress": "0x93Af6da985fD08dFA839cB2eD189D31E11c0A58f", - "poolType": "burnMint", + "pool": { + "address": "0x93Af6da985fD08dFA839cB2eD189D31E11c0A58f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BANANA", "tokenAddress": "0x1a89ecd466a23e98f07111b0510a2D6c1cd5E400" } @@ -277,8 +561,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lorenzo Governance Token", - "poolAddress": "0x0f9bf5199815e0244cb79B8c768b6979eC0290d3", - "poolType": "lockRelease", + "pool": { + "address": "0x0f9bf5199815e0244cb79B8c768b6979eC0290d3", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "BANK", "tokenAddress": "0x3AeE7602b612de36088F3ffEd8c8f10E86EbF2bF" }, @@ -286,8 +574,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lorenzo Governance Token", - "poolAddress": "0xdEC1532Abf3c2329026B5B26eE0Ea6c5c07a6c9b", - "poolType": "burnMint", + "pool": { + "address": "0xdEC1532Abf3c2329026B5B26eE0Ea6c5c07a6c9b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BANK", "tokenAddress": "0x0ba12138c55A7828b3fA1F9ef002fABdCB8996ae" } @@ -297,8 +589,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lombard", - "poolAddress": "0xAA1BD1c07cfEAdb8Cc025fFa8781a853Dc88d555", - "poolType": "burnMint", + "pool": { + "address": "0xAA1BD1c07cfEAdb8Cc025fFa8781a853Dc88d555", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BARD", "tokenAddress": "0xd23A186A78c0B3B805505E5f8ea4083295ef9f3a" }, @@ -306,8 +602,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lombard", - "poolAddress": "0x94A43cC8C4d755271436cfE42793A66a6C9ae25b", - "poolType": "lockRelease", + "pool": { + "address": "0x94A43cC8C4d755271436cfE42793A66a6C9ae25b", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "BARD", "tokenAddress": "0xf0DB65D17e30a966C2ae6A21f6BBA71cea6e9754" } @@ -317,8 +617,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Bera Bitcoin", - "poolAddress": "0xE354FA112CD7aA0DE5C4Bedce19965c9f549e689", - "poolType": "lockRelease", + "pool": { + "address": "0xE354FA112CD7aA0DE5C4Bedce19965c9f549e689", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "beraBTC", "tokenAddress": "0xE368a6BBb2c285A557800FF676D85Dd7E9C6299B" }, @@ -326,8 +630,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Bera Bitcoin", - "poolAddress": "0x1eCFe2220f18a5e4cDBc08563572d413B46fA8Ea", - "poolType": "burnMint", + "pool": { + "address": "0x1eCFe2220f18a5e4cDBc08563572d413B46fA8Ea", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "beraBTC", "tokenAddress": "0x68C7A170bd9Ea9fb283a50d041531678111FBF31" } @@ -337,8 +645,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BetSwirl v2", - "poolAddress": "0xEf50b39fE4302D8bF499ce854f19B84098E64da6", - "poolType": "burnMint", + "pool": { + "address": "0xEf50b39fE4302D8bF499ce854f19B84098E64da6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BETS", "tokenAddress": "0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5" }, @@ -346,8 +658,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BetSwirl v2", - "poolAddress": "0x77BEd59eaBa481F3f5122A1C9953d477d97A900d", - "poolType": "burnMint", + "pool": { + "address": "0x77BEd59eaBa481F3f5122A1C9953d477d97A900d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BETS", "tokenAddress": "0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5" }, @@ -355,8 +671,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BetSwirl v2", - "poolAddress": "0xCba063b1f328e4d42b05a165CBBB590939BDD70a", - "poolType": "burnMint", + "pool": { + "address": "0xCba063b1f328e4d42b05a165CBBB590939BDD70a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BETS", "tokenAddress": "0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5" }, @@ -364,8 +684,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BetSwirl v2", - "poolAddress": "0xdfeaa4acb814564Ab8c756A95E8269C620Ed9DEe", - "poolType": "burnMint", + "pool": { + "address": "0xdfeaa4acb814564Ab8c756A95E8269C620Ed9DEe", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BETS", "tokenAddress": "0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5" }, @@ -373,8 +697,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BetSwirl v2", - "poolAddress": "0x17B54BCEb4dd037d8AFF01EccdAd358De73159dB", - "poolType": "burnMint", + "pool": { + "address": "0x17B54BCEb4dd037d8AFF01EccdAd358De73159dB", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BETS", "tokenAddress": "0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5" }, @@ -382,8 +710,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BetSwirl v2", - "poolAddress": "0x463D98c150A664452F68B914c353C4fB99B227AC", - "poolType": "burnMint", + "pool": { + "address": "0x463D98c150A664452F68B914c353C4fB99B227AC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BETS", "tokenAddress": "0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5" }, @@ -391,8 +723,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BetSwirl v2", - "poolAddress": "0x8315Bbe2b2828559CEeCCCBCB4550A466227336E", - "poolType": "burnMint", + "pool": { + "address": "0x8315Bbe2b2828559CEeCCCBCB4550A466227336E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BETS", "tokenAddress": "0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5" }, @@ -400,19 +736,47 @@ "allowListEnabled": false, "decimals": 18, "name": "BetSwirl v2", - "poolAddress": "0xe7A4bcEb04a06AabC63BAeffb34F7B75217a83fA", - "poolType": "burnMint", + "pool": { + "address": "0xe7A4bcEb04a06AabC63BAeffb34F7B75217a83fA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BETS", "tokenAddress": "0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5" } }, + "BGB": { + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "BitgetToken", + "poolAddress": "0x41993c7228221403723B37D9F0B5F162C2902aA8", + "poolType": "lockRelease", + "symbol": "BGB", + "tokenAddress": "0x54D2252757e1672EEaD234D27B1270728fF90581" + }, + "morph-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "BitgetToken", + "poolAddress": "0x27d3e7164a9263010D57626Ac37371e3BD91C770", + "poolType": "burnMint", + "symbol": "BGB", + "tokenAddress": "0x389C08Bc23A7317000a1FD76c7c5B0cb0b4640b5" + } + }, "BKN": { "bsc-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Brickken", - "poolAddress": "0x995d8725bFE4909999B86Bb09cf7Cb9fC199Dd8a", - "poolType": "burnMint", + "pool": { + "address": "0x995d8725bFE4909999B86Bb09cf7Cb9fC199Dd8a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BKN", "tokenAddress": "0xFc209EeBA3D744aA741cc5C2A73Ebf9C977B5F82" }, @@ -420,8 +784,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Brickken", - "poolAddress": "0xf7A646E5Fc6563B2BB4Cd8c4374CdFCa4185e975", - "poolType": "burnMint", + "pool": { + "address": "0xf7A646E5Fc6563B2BB4Cd8c4374CdFCa4185e975", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BKN", "tokenAddress": "0xFc209EeBA3D744aA741cc5C2A73Ebf9C977B5F82" }, @@ -429,8 +797,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Brickken", - "poolAddress": "0xFf3633c00CADAac2C881638D59dF3714a9d59E33", - "poolType": "burnMint", + "pool": { + "address": "0xFf3633c00CADAac2C881638D59dF3714a9d59E33", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BKN", "tokenAddress": "0xFc209EeBA3D744aA741cc5C2A73Ebf9C977B5F82" } @@ -440,8 +812,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BMX", - "poolAddress": "0xc64f6E56a19678190b8263f05beeed9fc5Cbc01f", - "poolType": "lockRelease", + "pool": { + "address": "0xc64f6E56a19678190b8263f05beeed9fc5Cbc01f", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "BMX", "tokenAddress": "0x548f93779fBC992010C07467cBaf329DD5F059B7" }, @@ -449,8 +825,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BMX", - "poolAddress": "0x303D6A634eaeEdD58f2CdbD2eaAD7090d96df15f", - "poolType": "burnMint", + "pool": { + "address": "0x303D6A634eaeEdD58f2CdbD2eaAD7090d96df15f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BMX", "tokenAddress": "0x66eEd5FF1701E6ed8470DC391F05e27B1d0657eb" }, @@ -458,8 +838,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BMX", - "poolAddress": "0x0366ac315670Cde909317F6fbf954E2De28CE5c1", - "poolType": "burnMint", + "pool": { + "address": "0x0366ac315670Cde909317F6fbf954E2De28CE5c1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BMX", "tokenAddress": "0xC28f1D82874ccFebFE6afDAB3c685D5E709067E5" } @@ -469,8 +853,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOB", - "poolAddress": "0xf924B3Ac2d63145Ad88BcD2621a63Cd7D650673e", - "poolType": "lockRelease", + "pool": { + "address": "0xf924B3Ac2d63145Ad88BcD2621a63Cd7D650673e", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "BOB", "tokenAddress": "0xB0BD54846a92b214C04A63B26AD7Dc5e19A60808" }, @@ -478,8 +866,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOB", - "poolAddress": "0x7E685254A1c696CF8A72a2F05d3eDBf18Ea624Bb", - "poolType": "burnMint", + "pool": { + "address": "0x7E685254A1c696CF8A72a2F05d3eDBf18Ea624Bb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BOB", "tokenAddress": "0x52B5fB4B0F6572B8C44d0251Cc224513ac5eB7E7" }, @@ -487,8 +879,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOB", - "poolAddress": "0x9Dfaaa0826b8D81Ea7Cf7ED95619574bcb47d6EA", - "poolType": "burnMint", + "pool": { + "address": "0x9Dfaaa0826b8D81Ea7Cf7ED95619574bcb47d6EA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BOB", "tokenAddress": "0xC9746F73cC33a36c2cD55b8aEFD732586946Cedd" } @@ -498,8 +894,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0xCfC5092583C1B2122F221F524C198ABDeCBf3D1b", - "poolType": "burnMint", + "pool": { + "address": "0xCfC5092583C1B2122F221F524C198ABDeCBf3D1b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BOLD", "tokenAddress": "0x03569CC076654F82679C4BA2124D64774781B01D" }, @@ -507,8 +907,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0xCfC5092583C1B2122F221F524C198ABDeCBf3D1b", - "poolType": "burnMint", + "pool": { + "address": "0xCfC5092583C1B2122F221F524C198ABDeCBf3D1b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BOLD", "tokenAddress": "0xf05a207442f14E446b0e32b12D2043bfc68Cb1C9" }, @@ -516,8 +920,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0x10A9DE252EB9e11841fa58B18fD09aB43d4B7D92", - "poolType": "burnMint", + "pool": { + "address": "0x10A9DE252EB9e11841fa58B18fD09aB43d4B7D92", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BOLD", "tokenAddress": "0x03569CC076654F82679C4BA2124D64774781B01D" }, @@ -525,8 +933,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0x10A9DE252EB9e11841fa58B18fD09aB43d4B7D92", - "poolType": "burnMint", + "pool": { + "address": "0x10A9DE252EB9e11841fa58B18fD09aB43d4B7D92", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BOLD", "tokenAddress": "0x03569CC076654F82679C4BA2124D64774781B01D" }, @@ -534,8 +946,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0x10A9DE252EB9e11841fa58B18fD09aB43d4B7D92", - "poolType": "burnMint", + "pool": { + "address": "0x10A9DE252EB9e11841fa58B18fD09aB43d4B7D92", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BOLD", "tokenAddress": "0x03569CC076654F82679C4BA2124D64774781B01D" }, @@ -543,8 +959,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0x10A9DE252EB9e11841fa58B18fD09aB43d4B7D92", - "poolType": "burnMint", + "pool": { + "address": "0x10A9DE252EB9e11841fa58B18fD09aB43d4B7D92", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BOLD", "tokenAddress": "0x03569CC076654F82679C4BA2124D64774781B01D" }, @@ -552,8 +972,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0x48Fd11f0F21bAC2D8486E6682fE1E2Cb98f9AAb1", - "poolType": "burnMint", + "pool": { + "address": "0x48Fd11f0F21bAC2D8486E6682fE1E2Cb98f9AAb1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BOLD", "tokenAddress": "0x84533b1512A3A23F0c9668D88FDf86FEffdbb11A" }, @@ -561,8 +985,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0xf05a207442f14E446b0e32b12D2043bfc68Cb1C9", - "poolType": "lockRelease", + "pool": { + "address": "0xf05a207442f14E446b0e32b12D2043bfc68Cb1C9", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "BOLD", "tokenAddress": "0x6440f144b7e50D6a8439336510312d2F54beB01D" }, @@ -570,8 +998,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0xA7D08c8252FCc5D6B4889eD8E80Ecd5BA37498C4", - "poolType": "burnMint", + "pool": { + "address": "0xA7D08c8252FCc5D6B4889eD8E80Ecd5BA37498C4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BOLD", "tokenAddress": "0xe09B197f8c517ba8EA9440C31a8dDCD049CF7ccC" }, @@ -579,8 +1011,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BOLD Stablecoin", - "poolAddress": "0xCfC5092583C1B2122F221F524C198ABDeCBf3D1b", - "poolType": "burnMint", + "pool": { + "address": "0xCfC5092583C1B2122F221F524C198ABDeCBf3D1b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BOLD", "tokenAddress": "0xf05a207442f14E446b0e32b12D2043bfc68Cb1C9" } @@ -590,8 +1026,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x932406A77B3cfd3EF845c7f2999Bae933Ae03739", - "poolType": "burnMint", + "pool": { + "address": "0x932406A77B3cfd3EF845c7f2999Bae933Ae03739", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BONE", "tokenAddress": "0xec0CA5d2F362A826fa8F53C89A5Ce1C17CD604fa" }, @@ -599,8 +1039,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x20Dacf037b437854926CAee12BfbEbAB123e6E69", - "poolType": "burnMint", + "pool": { + "address": "0x20Dacf037b437854926CAee12BfbEbAB123e6E69", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BONE", "tokenAddress": "0xF543915698bf89BD6d429adC79577d75DA2FA1fd" }, @@ -608,8 +1052,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x6d567695bA1e375e2F994181Aa997328c0bDaE72", - "poolType": "burnMint", + "pool": { + "address": "0x6d567695bA1e375e2F994181Aa997328c0bDaE72", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BONE", "tokenAddress": "0xD301a90cb3C7a9253305af30D92dd2C1FD1e704E" }, @@ -617,8 +1065,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x476e0714DE6Fcf0d009Eb4c4E8a8DB325BF2Ba4A", - "poolType": "burnMint", + "pool": { + "address": "0x476e0714DE6Fcf0d009Eb4c4E8a8DB325BF2Ba4A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BONE", "tokenAddress": "0x32aF448529b5067f9E4aBf9764ecfcE97d53aFD4" }, @@ -626,8 +1078,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x2d08A8979C9aE629a22dE33A884aF58bC31e2460", - "poolType": "burnMint", + "pool": { + "address": "0x2d08A8979C9aE629a22dE33A884aF58bC31e2460", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BONE", "tokenAddress": "0x387090cDEa72d6Ab1598394d45c5B3e05616f15D" }, @@ -635,8 +1091,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x37Bbd2052751c42Dc0C2A7A02A140FDE6A1F8416", - "poolType": "burnMint", + "pool": { + "address": "0x37Bbd2052751c42Dc0C2A7A02A140FDE6A1F8416", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BONE", "tokenAddress": "0x88B81FD1753FEF7bbFf3BbC65E4Ba73a28CC9449" }, @@ -644,8 +1104,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x795411Fe0C1f88B30D18F5061589Afd140e49Ff0", - "poolType": "burnMint", + "pool": { + "address": "0x795411Fe0C1f88B30D18F5061589Afd140e49Ff0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BONE", "tokenAddress": "0xe1886337D2ecBdB48A9dE8a68e8dEa2Ba9C5dFd2" }, @@ -653,8 +1117,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0xee83E603b755889ceB652F3D8af3C735a98C486D", - "poolType": "burnMint", + "pool": { + "address": "0xee83E603b755889ceB652F3D8af3C735a98C486D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BONE", "tokenAddress": "0xDd2D32Fea6e166fA53DEe5c1584456c0e8A889f5" }, @@ -662,8 +1130,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x691435ED2282052a064B8748BA2E3C7eeefcA8Fd", - "poolType": "burnMint", + "pool": { + "address": "0x691435ED2282052a064B8748BA2E3C7eeefcA8Fd", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BONE", "tokenAddress": "0x79a7d4EF9870474F18A88524Bf2349393B0C2e03" }, @@ -671,8 +1143,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x2B96db391d0f35f821e53De72508237492247e16", - "poolType": "burnMint", + "pool": { + "address": "0x2B96db391d0f35f821e53De72508237492247e16", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BONE", "tokenAddress": "0x2F0B60F0e269dc01132bdCcdD48Bb8CF33021f0a" }, @@ -680,8 +1156,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x67Df6368177C950914C0F634d1a003a6caa18aC0", - "poolType": "burnMint", + "pool": { + "address": "0x67Df6368177C950914C0F634d1a003a6caa18aC0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BONE", "tokenAddress": "0x4A7961249E49642474f9161f245Fc52D59F14113" }, @@ -689,8 +1169,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x7f399748490c25E32D3b8aaE4f0322c6466082B6", - "poolType": "burnMint", + "pool": { + "address": "0x7f399748490c25E32D3b8aaE4f0322c6466082B6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BONE", "tokenAddress": "0x010c6F656E06f12BB3b115FCBC9ca282654795D2" }, @@ -698,8 +1182,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x9ecde69DF43aDd57AA60949e6Db5AC7b6DC11831", - "poolType": "burnMint", + "pool": { + "address": "0x9ecde69DF43aDd57AA60949e6Db5AC7b6DC11831", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BONE", "tokenAddress": "0x23535421f6e13F2084684BB052F58d1b33E0dB8e" }, @@ -707,8 +1195,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x37cB2B7A45F8d17936EBaBB4Ed95dE61f5371022", - "poolType": "burnMint", + "pool": { + "address": "0x37cB2B7A45F8d17936EBaBB4Ed95dE61f5371022", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BONE", "tokenAddress": "0xeF76346aBA1F8c671BA6F51cCb47e93b4BF72aa0" }, @@ -716,8 +1208,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0xc75aCdceF4c679eaCb7a8CF1eF486B9Cf77478f8", - "poolType": "lockRelease", + "pool": { + "address": "0xc75aCdceF4c679eaCb7a8CF1eF486B9Cf77478f8", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "BONE", "tokenAddress": "0x9813037ee2218799597d83D4a5B6F3b6778218d9" }, @@ -725,8 +1221,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x1cdFc3B0fE64bb943829063D16ff7f835c0Fc28C", - "poolType": "burnMint", + "pool": { + "address": "0x1cdFc3B0fE64bb943829063D16ff7f835c0Fc28C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BONE", "tokenAddress": "0x56357929B7d7720ac19ad55c923E85EdAC4Fc5D3" }, @@ -734,8 +1234,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0xb88784Ff6fF162D3CD338627eBc171b08B17A1A3", - "poolType": "burnMint", + "pool": { + "address": "0xb88784Ff6fF162D3CD338627eBc171b08B17A1A3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BONE", "tokenAddress": "0xe785f763d30f583EE6666Fa0e84f8bc32E9D57B9" }, @@ -743,8 +1247,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0xd17E7239feEF68Ac9fdeC962F8cCbEcb3E130F5D", - "poolType": "burnMint", + "pool": { + "address": "0xd17E7239feEF68Ac9fdeC962F8cCbEcb3E130F5D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BONE", "tokenAddress": "0xc4B60B24F644282aaF6739bc7eb1888C69dB2A4F" }, @@ -752,8 +1260,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BONE SHIBASWAP", - "poolAddress": "0x9342547460E0BE4C9559caE9cfF5E0772371F9Da", - "poolType": "burnMint", + "pool": { + "address": "0x9342547460E0BE4C9559caE9cfF5E0772371F9Da", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BONE", "tokenAddress": "0x50E23d57309C61eab3D3d1EfE5DC02A36f945027" } @@ -763,8 +1275,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Bedrock", - "poolAddress": "0xEbaf5275843E4Ea7C9867307BB801D2a829e2a58", - "poolType": "burnMint", + "pool": { + "address": "0xEbaf5275843E4Ea7C9867307BB801D2a829e2a58", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BR", "tokenAddress": "0xd352dc6e5F0c45E2F2b38eb5565EB286A1ea4087" }, @@ -772,8 +1288,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Bedrock", - "poolAddress": "0x2E02DF052e7C4a12e1B334DC3D182c39bb754dc3", - "poolType": "lockRelease", + "pool": { + "address": "0x2E02DF052e7C4a12e1B334DC3D182c39bb754dc3", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "BR", "tokenAddress": "0xFf7d6A96ae471BbCD7713aF9CB1fEeB16cf56B41" }, @@ -781,8 +1301,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Bedrock", - "poolAddress": "0xA67AA68B1fF880dA771f2646a95d789EF929610b", - "poolType": "burnMint", + "pool": { + "address": "0xA67AA68B1fF880dA771f2646a95d789EF929610b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BR", "tokenAddress": "0xd6122ddADa244913521F3d62006eaF756c157660" }, @@ -790,8 +1314,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Bedrock", - "poolAddress": "0x3d430E1380286560899B94E3E9459c4ec300EF9a", - "poolType": "burnMint", + "pool": { + "address": "0x3d430E1380286560899B94E3E9459c4ec300EF9a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BR", "tokenAddress": "0x9B61879e91a0b1322F3d61c23Aaf936231882096" }, @@ -799,8 +1327,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Bedrock", - "poolAddress": "3m8zgkeD3WSEqqjkG8UehV9uwAunkZoiZK99ZjPsyZxH", - "poolType": "burnMint", + "pool": { + "address": "3m8zgkeD3WSEqqjkG8UehV9uwAunkZoiZK99ZjPsyZxH", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BR", "tokenAddress": "BRryKTBVA4xYbgY6kkZtRWGEKz4aujNMeBkqNLRQbzp1" } @@ -810,8 +1342,12 @@ "allowListEnabled": false, "decimals": 8, "name": "brBTC", - "poolAddress": "0x163b337546725c1ef4b943f8d5113af803b5e01e3bc567d000f6565ca38e0aec", - "poolType": "burnMint", + "pool": { + "address": "0x163b337546725c1ef4b943f8d5113af803b5e01e3bc567d000f6565ca38e0aec", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "brBTC", "tokenAddress": "0x8e51106b139001f1f25a320066621a2e0d140724ee9be1d49aaf9e76ceb24d75" }, @@ -819,8 +1355,12 @@ "allowListEnabled": false, "decimals": 8, "name": "brBTC", - "poolAddress": "0xC82793e403a637ded107C3c9D0785776e46852A8", - "poolType": "burnMint", + "pool": { + "address": "0xC82793e403a637ded107C3c9D0785776e46852A8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "brBTC", "tokenAddress": "0x93919784C523f39CACaa98Ee0a9d96c3F32b593e" }, @@ -828,8 +1368,12 @@ "allowListEnabled": false, "decimals": 8, "name": "brBTC", - "poolAddress": "0x5390E2e17C896244B7544e8566E9D77599700DE5", - "poolType": "burnMint", + "pool": { + "address": "0x5390E2e17C896244B7544e8566E9D77599700DE5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "brBTC", "tokenAddress": "0x733a6c29eDA4a58931AE81b8d91e29f2EAf01df3" }, @@ -837,8 +1381,12 @@ "allowListEnabled": false, "decimals": 8, "name": "brBTC", - "poolAddress": "0x30837313d7f9B0450267ccf269A36EdE3A963E56", - "poolType": "burnMint", + "pool": { + "address": "0x30837313d7f9B0450267ccf269A36EdE3A963E56", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "brBTC", "tokenAddress": "0x3376eBCa0A85Fc8D791B1001a571C41fdd61514a" }, @@ -846,8 +1394,12 @@ "allowListEnabled": false, "decimals": 8, "name": "brBTC", - "poolAddress": "0xa08Eb272f3d0bE2ee6D6586fE7A8a129387118d4", - "poolType": "burnMint", + "pool": { + "address": "0xa08Eb272f3d0bE2ee6D6586fE7A8a129387118d4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "brBTC", "tokenAddress": "0xa161132371C94299D215915D4Cbc3B629E2059Be" }, @@ -855,8 +1407,12 @@ "allowListEnabled": false, "decimals": 8, "name": "brBTC", - "poolAddress": "0x110D97B046920e23d201d147B2AfD9e853Ec7c28", - "poolType": "burnMint", + "pool": { + "address": "0x110D97B046920e23d201d147B2AfD9e853Ec7c28", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "brBTC", "tokenAddress": "0xa161132371C94299D215915D4Cbc3B629E2059Be" }, @@ -864,8 +1420,12 @@ "allowListEnabled": false, "decimals": 8, "name": "brBTC", - "poolAddress": "0x330BF3C554ab94533069AF11313143eD3884cf15", - "poolType": "burnMint", + "pool": { + "address": "0x330BF3C554ab94533069AF11313143eD3884cf15", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "brBTC", "tokenAddress": "0xDfc7D2d003A053b2E0490531e9317A59962b511E" }, @@ -873,8 +1433,12 @@ "allowListEnabled": false, "decimals": 8, "name": "brBTC", - "poolAddress": "0x512c2Ddf5f7F48a6c44cFF73CD8d7edEC5e6b0d8", - "poolType": "burnMint", + "pool": { + "address": "0x512c2Ddf5f7F48a6c44cFF73CD8d7edEC5e6b0d8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "brBTC", "tokenAddress": "0x2eC37d45FCAE65D9787ECf71dc85a444968f6646" }, @@ -882,19 +1446,83 @@ "allowListEnabled": false, "decimals": 8, "name": "brBTC", - "poolAddress": "HzJ3Y9MCuywRV4YLd6a8gigee3WDpWUv1dS5z57QNRaT", - "poolType": "burnMint", + "pool": { + "address": "HzJ3Y9MCuywRV4YLd6a8gigee3WDpWUv1dS5z57QNRaT", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "brBTC", "tokenAddress": "brBg8x9yT4WnQd8Z43aX7wfrGMrimLfT2WCWRibHo3d" } }, + "BTC.b": { + "avalanche-mainnet": { + "allowListEnabled": false, + "decimals": 8, + "name": "Bitcoin", + "poolAddress": "0x67927d7eA19F9A1053f4f5BBdf827Ed9870F1a1B", + "poolType": "burnMint", + "symbol": "BTC.b", + "tokenAddress": "0x152b9d0FdC40C096757F570A51E494bd4b943E50" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 8, + "name": "Bitcoin", + "poolAddress": "0xBA59cF1c1563a9B93A8C5D70F8E445eaCa9842D0", + "poolType": "burnMint", + "symbol": "BTC.b", + "tokenAddress": "0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072" + }, + "megaeth-mainnet": { + "allowListEnabled": false, + "decimals": 8, + "name": "Bitcoin", + "poolAddress": "0xa9FC147f45239b56781D09ec748df194d54A7913", + "poolType": "burnMint", + "symbol": "BTC.b", + "tokenAddress": "0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072" + }, + "monad-mainnet": { + "allowListEnabled": false, + "decimals": 8, + "name": "Bitcoin", + "poolAddress": "0xAe5E2940Fc01C0f8076D36749509C75E43da0C70", + "poolType": "burnMint", + "symbol": "BTC.b", + "tokenAddress": "0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072" + }, + "polygon-mainnet-katana": { + "allowListEnabled": false, + "decimals": 8, + "name": "Bitcoin on Katana", + "poolAddress": "0xf1fc1bE000Db6fa2193aB75E461a5603400d031F", + "poolType": "burnMint", + "symbol": "BTCK", + "tokenAddress": "0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072" + }, + "stable-mainnet": { + "allowListEnabled": false, + "decimals": 8, + "name": "Bitcoin", + "poolAddress": "0xc6c22D4Be6Cc50E6D01BD6325b6cD715A52f8154", + "poolType": "burnMint", + "symbol": "BTC.b", + "tokenAddress": "0xB0F70C0bD6FD87dbEb7C10dC692a2a6106817072" + } + }, "BTR": { "bitcoin-mainnet-bitlayer-1": { "allowListEnabled": false, "decimals": 18, "name": "BTR Token", - "poolAddress": "0x786248B634B1ebC7B5fc809c74a1A212fc920d63", - "poolType": "lockRelease", + "pool": { + "address": "0x786248B634B1ebC7B5fc809c74a1A212fc920d63", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "BTR", "tokenAddress": "0x0E4cF4Affdb72b39Ea91fA726D291781cBd020bF" }, @@ -902,8 +1530,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BTR token", - "poolAddress": "0x86248bE697645cfE0fdeB37FBa0102604f355eFA", - "poolType": "burnMint", + "pool": { + "address": "0x86248bE697645cfE0fdeB37FBa0102604f355eFA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BTR", "tokenAddress": "0xfed13D0c40790220fbdE712987079Eda1Ed75C51" }, @@ -911,8 +1543,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BTR token", - "poolAddress": "0xC78210649aF8A450C0f6E98107a0b614a3198359", - "poolType": "burnMint", + "pool": { + "address": "0xC78210649aF8A450C0f6E98107a0b614a3198359", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "BTR", "tokenAddress": "0x6C76dE483F1752Ac8473e2B4983A873991e70dA7" } @@ -922,8 +1558,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BYTES", - "poolAddress": "0xAb2e4F219E1A24bA061E0Ecf07c0e3Dc7d410A9A", - "poolType": "burnMint", + "pool": { + "address": "0xAb2e4F219E1A24bA061E0Ecf07c0e3Dc7d410A9A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BYTES", "tokenAddress": "0x13af0Fe9eB35e91758B467f95cbc78e16FdD8B6b" }, @@ -931,8 +1571,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BYTES", - "poolAddress": "0x5d8cf2624Aafd77b5E2bA9d729658F9BD2058069", - "poolType": "burnMint", + "pool": { + "address": "0x5d8cf2624Aafd77b5E2bA9d729658F9BD2058069", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "BYTES", "tokenAddress": "0x13af0Fe9eB35e91758B467f95cbc78e16FdD8B6b" }, @@ -940,8 +1584,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BYTES", - "poolAddress": "0x0ef01909C4aA5403654452729149F0Db8C7be1E1", - "poolType": "lockRelease", + "pool": { + "address": "0x0ef01909C4aA5403654452729149F0Db8C7be1E1", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "BYTES", "tokenAddress": "0xa19f5264F7D7Be11c451C093D8f92592820Bea86" }, @@ -949,8 +1597,12 @@ "allowListEnabled": false, "decimals": 18, "name": "BYTES", - "poolAddress": "0x8Cc3af9D6f107124791A34DFD05A496983b0c11e", - "poolType": "burnMint", + "pool": { + "address": "0x8Cc3af9D6f107124791A34DFD05A496983b0c11e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "BYTES", "tokenAddress": "0x13af0Fe9eB35e91758B467f95cbc78e16FdD8B6b" } @@ -960,8 +1612,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Canned dog", - "poolAddress": "0x5d7ccbaa5b0D65aa8A2Ed5989B32C64963fDF370", - "poolType": "burnMint", + "pool": { + "address": "0x5d7ccbaa5b0D65aa8A2Ed5989B32C64963fDF370", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CANNED", "tokenAddress": "0xa2e543EE6531bb9640dde7ad018eA965cD936a67" }, @@ -969,8 +1625,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Canned dog", - "poolAddress": "0x9076EFCAC1a98dF0edC756e3892ED0F54A2F4A29", - "poolType": "lockRelease", + "pool": { + "address": "0x9076EFCAC1a98dF0edC756e3892ED0F54A2F4A29", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "CANNED", "tokenAddress": "0x5d63C604803BbF7919953b73c89309B5CBcc227a" } @@ -980,8 +1640,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Forkast", - "poolAddress": "0xEcfec1595D273A71aC94370eA1C62480569dCAFf", - "poolType": "burnMint", + "pool": { + "address": "0xEcfec1595D273A71aC94370eA1C62480569dCAFf", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CGX", "tokenAddress": "0xdBDE08d475bd50E2D1A6af34c7b10DD430D8396e" }, @@ -989,8 +1653,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Forkast", - "poolAddress": "0x394d5854216d0d44c3828f49e201917451eb477B", - "poolType": "burnMint", + "pool": { + "address": "0x394d5854216d0d44c3828f49e201917451eb477B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CGX", "tokenAddress": "0x656fE582B4C6DC95c598EA54dc820eb36152E2f7" } @@ -1000,8 +1668,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Chintai Exchange Token", - "poolAddress": "0x4ea2cb69c1a347cB2eEE8FE0EfFA2762b4aD68bb", - "poolType": "burnMint", + "pool": { + "address": "0x4ea2cb69c1a347cB2eEE8FE0EfFA2762b4aD68bb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CHEX", "tokenAddress": "0x9Ce84F6A69986a83d92C324df10bC8E64771030f" }, @@ -1009,8 +1681,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Chintai Exchange Token", - "poolAddress": "0x1c01171761A94538377FD0FDA230ec921274Df47", - "poolType": "burnMint", + "pool": { + "address": "0x1c01171761A94538377FD0FDA230ec921274Df47", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CHEX", "tokenAddress": "0xc43F3Ae305a92043bd9b62eBd2FE14F7547ee485" }, @@ -1018,8 +1694,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Chintai Exchange Token", - "poolAddress": "0xAF819a87231cF522f1e2b2965acdbC436c737c98", - "poolType": "burnMint", + "pool": { + "address": "0xAF819a87231cF522f1e2b2965acdbC436c737c98", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CHEX", "tokenAddress": "0x9Ce84F6A69986a83d92C324df10bC8E64771030f" } @@ -1029,8 +1709,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Chiikawa", - "poolAddress": "0xCE5c6D7383BB72Fd7890f07aCF51C76A36ac00fB", - "poolType": "burnMint", + "pool": { + "address": "0xCE5c6D7383BB72Fd7890f07aCF51C76A36ac00fB", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CHIKA", "tokenAddress": "0xff70300dDED939Ff6db9174EB38EeC183a12344b" }, @@ -1038,8 +1722,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Chiikawa", - "poolAddress": "0x9aD61F86CD457da798C859c26517acd1FC971c04", - "poolType": "lockRelease", + "pool": { + "address": "0x9aD61F86CD457da798C859c26517acd1FC971c04", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "CHIKA", "tokenAddress": "0x61CFA29261d8151D39244b8FfCf8DFd2f9DF3839" } @@ -1049,8 +1737,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Cakepie", - "poolAddress": "0xA690C439dCd4a5507FCEB4Da0517a69e8244DB90", - "poolType": "burnMint", + "pool": { + "address": "0xA690C439dCd4a5507FCEB4Da0517a69e8244DB90", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CKP", "tokenAddress": "0x2B5D9ADea07B590b638FFc165792b2C610EdA649" }, @@ -1058,8 +1750,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Cakepie", - "poolAddress": "0x97Cb0f52CF2270971eB588C1CE664F65382cd032", - "poolType": "burnMint", + "pool": { + "address": "0x97Cb0f52CF2270971eB588C1CE664F65382cd032", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CKP", "tokenAddress": "0x346Af1954e3d6be46B96dA713a1f7fD2d1928F1d" } @@ -1069,8 +1765,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clBTC", - "poolAddress": "0xDDf56a92120E54B39D2E4ba4e92Cb23d45304e48", - "poolType": "burnMint", + "pool": { + "address": "0xDDf56a92120E54B39D2E4ba4e92Cb23d45304e48", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clBTC", "tokenAddress": "0xb944e1ceb32E5672Bf48fE7145D1A5D4F3D95D25" }, @@ -1078,8 +1778,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clBTC", - "poolAddress": "0x77fBC9CBCd931d4059Df523950F9f685a6003eA1", - "poolType": "lockRelease", + "pool": { + "address": "0x77fBC9CBCd931d4059Df523950F9f685a6003eA1", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "clBTC", "tokenAddress": "0x8d2757EA27AaBf172DA4CCa4e5474c76016e3dC5" }, @@ -1087,8 +1791,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clBTC", - "poolAddress": "0x604Ea3Dd67754bbd309a1657A2f5108559EEaBC9", - "poolType": "burnMint", + "pool": { + "address": "0x604Ea3Dd67754bbd309a1657A2f5108559EEaBC9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "clBTC", "tokenAddress": "0x7a4c2C39e25ca0D6A1Ac4af14dD601c2A7eDA8Ae" }, @@ -1096,8 +1804,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clBTC", - "poolAddress": "0xBb8b739C28898F7d143584380e7b689ecCaB2c9F", - "poolType": "burnMint", + "pool": { + "address": "0xBb8b739C28898F7d143584380e7b689ecCaB2c9F", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clBTC", "tokenAddress": "0x7a4c2C39e25ca0D6A1Ac4af14dD601c2A7eDA8Ae" } @@ -1107,8 +1819,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Creative Token", - "poolAddress": "0xE9daD7c1D857F09547703Be89Be102ca232D9837", - "poolType": "lockRelease", + "pool": { + "address": "0xE9daD7c1D857F09547703Be89Be102ca232D9837", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "CRTV", "tokenAddress": "0x4B62D9b3DE9FAB98659693c9ee488D2E4eE56c44" }, @@ -1116,8 +1832,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Creative Token", - "poolAddress": "0x7A16780ABCa3CB7C1968c7C726C31A4916F4F828", - "poolType": "burnMint", + "pool": { + "address": "0x7A16780ABCa3CB7C1968c7C726C31A4916F4F828", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CRTV", "tokenAddress": "0x06B9f097407084b9C7d82EA82E8FC693d3394eB6" }, @@ -1125,8 +1845,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Creative Token", - "poolAddress": "0x07d31ab079BF606BADdb806cced99D23284E62F2", - "poolType": "burnMint", + "pool": { + "address": "0x07d31ab079BF606BADdb806cced99D23284E62F2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CRTV", "tokenAddress": "0xEB531C4470E8588520a7deb8B5Ea2289f9a9ad0f" } @@ -1136,8 +1860,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sol Killer", - "poolAddress": "0x1dBDd800477B67191B70C51f327968f0F835c58d", - "poolType": "burnMint", + "pool": { + "address": "0x1dBDd800477B67191B70C51f327968f0F835c58d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "DAMN", "tokenAddress": "0x28be0935fd470C46325Bc47A1c65C168E8473a3d" }, @@ -1145,8 +1873,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sol Killer", - "poolAddress": "0x68D443e22AEd9bdEF014Fad3FD19752CCeaE9990", - "poolType": "lockRelease", + "pool": { + "address": "0x68D443e22AEd9bdEF014Fad3FD19752CCeaE9990", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "DAMN", "tokenAddress": "0xeCe898EdCc0AF91430603175F945D8de75291c70" } @@ -1156,8 +1888,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Degen Arena", - "poolAddress": "0xC8c2Fe3Df1d300F366cE831a34276d7E4dd1F9B5", - "poolType": "lockRelease", + "pool": { + "address": "0xC8c2Fe3Df1d300F366cE831a34276d7E4dd1F9B5", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "DEGEN", "tokenAddress": "0x420658A1d8B8F5C36DdAf1Bb828f347Ba9011969" }, @@ -1165,8 +1901,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Degen Arena", - "poolAddress": "0x09624a5520F0a452c5D3D8AefCd6B6E47FB5281f", - "poolType": "burnMint", + "pool": { + "address": "0x09624a5520F0a452c5D3D8AefCd6B6E47FB5281f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "DEGEN", "tokenAddress": "0xf252cf43175CF739022E3A9533b2267dcFE1A830" } @@ -1176,8 +1916,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DFX Token (L2)", - "poolAddress": "0x5B1f92CD2a3cd4137BDc16d92A78795F697bBf7c", - "poolType": "burnMint", + "pool": { + "address": "0x5B1f92CD2a3cd4137BDc16d92A78795F697bBf7c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "DFX", "tokenAddress": "0x27f485b62C4A7E635F561A87560Adf5090239E93" }, @@ -1185,8 +1929,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DFX Token", - "poolAddress": "0xc2ef2f272D2C09b0a8523cEf32C96D3A7f379979", - "poolType": "lockRelease", + "pool": { + "address": "0xc2ef2f272D2C09b0a8523cEf32C96D3A7f379979", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "DFX", "tokenAddress": "0x888888435FDe8e7d4c54cAb67f206e4199454c60" }, @@ -1194,8 +1942,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DFX Token (L2)", - "poolAddress": "0x04505E4182A2ab7989b03eB2321E3141C1c79187", - "poolType": "burnMint", + "pool": { + "address": "0x04505E4182A2ab7989b03eB2321E3141C1c79187", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "DFX", "tokenAddress": "0x27f485b62C4A7E635F561A87560Adf5090239E93" } @@ -1205,8 +1957,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Decentralized Insurance Protocol Token", - "poolAddress": "0x154d09dB12E6e1EF94e57ca1889ffEcBb90CE034", - "poolType": "burnMint", + "pool": { + "address": "0x154d09dB12E6e1EF94e57ca1889ffEcBb90CE034", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "DIP", "tokenAddress": "0xAc86f3556cBd2b4d800D17ADC3a266B500FCB9F5" }, @@ -1214,8 +1970,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Decentralized Insurance Protocol", - "poolAddress": "0xAc3453eEF710e1E6457383F29D696Db5435Bf95b", - "poolType": "lockRelease", + "pool": { + "address": "0xAc3453eEF710e1E6457383F29D696Db5435Bf95b", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "DIP", "tokenAddress": "0xc719d010B63E5bbF2C0551872CD5316ED26AcD83" } @@ -1225,8 +1985,12 @@ "allowListEnabled": false, "decimals": 9, "name": "DogeBonk.com", - "poolAddress": "0x51364bc1a2FB9BC271612BF0936E857B5e000aAb", - "poolType": "lockRelease", + "pool": { + "address": "0x51364bc1a2FB9BC271612BF0936E857B5e000aAb", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "DOBO", "tokenAddress": "0xAe2DF9F730c54400934c06a17462c41C08a06ED8" }, @@ -1234,8 +1998,12 @@ "allowListEnabled": false, "decimals": 9, "name": "DogeBonk.com", - "poolAddress": "0x5F49Ef413B9A0e8C31bf6ecBE67D9B98778294f2", - "poolType": "burnMint", + "pool": { + "address": "0x5F49Ef413B9A0e8C31bf6ecBE67D9B98778294f2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "DOBO", "tokenAddress": "0x57798c5dc0DCcE1E720c3C4aEB7e6786FeF1BE0d" }, @@ -1243,8 +2011,12 @@ "allowListEnabled": false, "decimals": 9, "name": "DogeBonk.com", - "poolAddress": "0x11EDBA90ae48d44808AB984206F776932c8575A9", - "poolType": "burnMint", + "pool": { + "address": "0x11EDBA90ae48d44808AB984206F776932c8575A9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "DOBO", "tokenAddress": "0x57798c5dc0DCcE1E720c3C4aEB7e6786FeF1BE0d" }, @@ -1252,8 +2024,12 @@ "allowListEnabled": false, "decimals": 9, "name": "DogeBonk.com", - "poolAddress": "0x817404e98d28b8065c6e1C76E6bCD9088aEFb31A", - "poolType": "burnMint", + "pool": { + "address": "0x817404e98d28b8065c6e1C76E6bCD9088aEFb31A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "DOBO", "tokenAddress": "0x3683f8F60A4a52ba7F26c43626E274913020aDaC" } @@ -1263,8 +2039,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Dolomite", - "poolAddress": "0x9E7728077F753dFDF53C2236097E27C743890992", - "poolType": "burnMint", + "pool": { + "address": "0x9E7728077F753dFDF53C2236097E27C743890992", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "DOLO", "tokenAddress": "0x0F81001eF0A83ecCE5ccebf63EB302c70a39a654" }, @@ -1272,8 +2052,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Dolomite", - "poolAddress": "0xeDD4b6936bDD9Fc272ac3a8dDC4A1b61b5C26bAC", - "poolType": "burnMint", + "pool": { + "address": "0xeDD4b6936bDD9Fc272ac3a8dDC4A1b61b5C26bAC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "DOLO", "tokenAddress": "0x0F81001eF0A83ecCE5ccebf63EB302c70a39a654" }, @@ -1281,8 +2065,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Dolomite", - "poolAddress": "0xC69e7a187fA739028Ee613426795D91B610932c7", - "poolType": "burnMint", + "pool": { + "address": "0xC69e7a187fA739028Ee613426795D91B610932c7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "DOLO", "tokenAddress": "0x0F81001eF0A83ecCE5ccebf63EB302c70a39a654" } @@ -1292,8 +2080,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DefiPulse Index", - "poolAddress": "0x5dFdAF7A7BDB9Da17FF22a8a796e2fcE58daA5b2", - "poolType": "burnMint", + "pool": { + "address": "0x5dFdAF7A7BDB9Da17FF22a8a796e2fcE58daA5b2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "DPI", "tokenAddress": "0x9737C658272e66Faad39D7AD337789Ee6D54F500" }, @@ -1301,8 +2093,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DefiPulse Index", - "poolAddress": "0xA77Ca3B16aEe1e177FD8Eff038F929819B75490f", - "poolType": "burnMint", + "pool": { + "address": "0xA77Ca3B16aEe1e177FD8Eff038F929819B75490f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "DPI", "tokenAddress": "0xc6955B85b622369a54Cc8C6DBeCb8e03c0885BD8" }, @@ -1310,8 +2106,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DefiPulse Index", - "poolAddress": "0x9b8FEf06D74c3880FC6886b3c6FbbBf601Db0DCC", - "poolType": "lockRelease", + "pool": { + "address": "0x9b8FEf06D74c3880FC6886b3c6FbbBf601Db0DCC", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "DPI", "tokenAddress": "0x1494CA1F11D487c2bBe4543E90080AeBa4BA3C2b" } @@ -1321,8 +2121,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Diversified Staked ETH Index", - "poolAddress": "0xabB35cA480b3f9bcB770fCB7447017373da2Bea6", - "poolType": "burnMint", + "pool": { + "address": "0xabB35cA480b3f9bcB770fCB7447017373da2Bea6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "dsETH", "tokenAddress": "0x6320320979A901aAb3461A8D9718Ab9CF07E73D3" }, @@ -1330,8 +2134,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Diversified Staked ETH Index", - "poolAddress": "0x9061247649e327B7DFd256D882dCC0A0D6d86A8e", - "poolType": "burnMint", + "pool": { + "address": "0x9061247649e327B7DFd256D882dCC0A0D6d86A8e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "dsETH", "tokenAddress": "0x37E7C051Dc5A24313cEEC581222882648ba537aa" }, @@ -1339,8 +2147,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Diversified Staked ETH Index (dsETH)", - "poolAddress": "0x8E7ebBb95e369BC854Ee7021C7CF2E282c3bCAEa", - "poolType": "lockRelease", + "pool": { + "address": "0x8E7ebBb95e369BC854Ee7021C7CF2E282c3bCAEa", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "dsETH", "tokenAddress": "0x341c05c0E9b33C0E38d64de76516b2Ce970bB3BE" } @@ -1350,8 +2162,12 @@ "allowListEnabled": false, "decimals": 18, "name": "EARNM Token", - "poolAddress": "0xaB9502c8886Bd9CEd344A3684784a5e4C0fC46d0", - "poolType": "burnMint", + "pool": { + "address": "0xaB9502c8886Bd9CEd344A3684784a5e4C0fC46d0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "EARNM", "tokenAddress": "0xcF1C66E3CF649F8E29835337687Be692896a23c5" }, @@ -1359,8 +2175,12 @@ "allowListEnabled": false, "decimals": 18, "name": "EARNM Token", - "poolAddress": "0xaB9502c8886Bd9CEd344A3684784a5e4C0fC46d0", - "poolType": "burnMint", + "pool": { + "address": "0xaB9502c8886Bd9CEd344A3684784a5e4C0fC46d0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "EARNM", "tokenAddress": "0xcF1C66E3CF649F8E29835337687Be692896a23c5" }, @@ -1368,8 +2188,12 @@ "allowListEnabled": false, "decimals": 18, "name": "EARNM Token", - "poolAddress": "0xaB9502c8886Bd9CEd344A3684784a5e4C0fC46d0", - "poolType": "burnMint", + "pool": { + "address": "0xaB9502c8886Bd9CEd344A3684784a5e4C0fC46d0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "EARNM", "tokenAddress": "0xcF1C66E3CF649F8E29835337687Be692896a23c5" }, @@ -1377,8 +2201,12 @@ "allowListEnabled": false, "decimals": 18, "name": "EARNM Token", - "poolAddress": "0xaB9502c8886Bd9CEd344A3684784a5e4C0fC46d0", - "poolType": "lockRelease", + "pool": { + "address": "0xaB9502c8886Bd9CEd344A3684784a5e4C0fC46d0", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "EARNM", "tokenAddress": "0xBA98B09050F8837424fa8b71B4802c61cb1a4097" } @@ -1388,8 +2216,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Eden Token", - "poolAddress": "0x74d0DD4551e4BF18e13c630C1a537fAF323bB43C", - "poolType": "burnMint", + "pool": { + "address": "0x74d0DD4551e4BF18e13c630C1a537fAF323bB43C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "EDEN", "tokenAddress": "0x235B6fe22B4642aDa16D311855c49Ce7DE260841" }, @@ -1397,8 +2229,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Eden Token", - "poolAddress": "0xC8ADf2f51a35b0a9d8f74675b64c954Ca2Dcbc14", - "poolType": "burnMint", + "pool": { + "address": "0xC8ADf2f51a35b0a9d8f74675b64c954Ca2Dcbc14", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "EDEN", "tokenAddress": "0x24A3D725C37A8D1a66Eb87f0E5D07fE67c120035" } @@ -1408,8 +2244,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Bridged egETH", - "poolAddress": "0xac939a46B8CE13205C68e949205c4683cfE715Ca", - "poolType": "burnMint", + "pool": { + "address": "0xac939a46B8CE13205C68e949205c4683cfE715Ca", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "Bridged egETH", "tokenAddress": "0x6C49A527bdd2E09D4337C8699aA7B44dD053Eda8" }, @@ -1417,8 +2257,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Eigenpie Restaked ETH", - "poolAddress": "0x4E63008092645521CFc989FB78c1324CDd371ed0", - "poolType": "lockRelease", + "pool": { + "address": "0x4E63008092645521CFc989FB78c1324CDd371ed0", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "egETH", "tokenAddress": "0x18f313Fc6Afc9b5FD6f0908c1b3D476E3feA1DD9" }, @@ -1426,8 +2270,12 @@ "allowListEnabled": false, "decimals": 18, "name": "egETH", - "poolAddress": "0x2e797C6b88bEBbD540831F4E55Ed56fDf06a49a7", - "poolType": "burnMint", + "pool": { + "address": "0x2e797C6b88bEBbD540831F4E55Ed56fDf06a49a7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "egETH", "tokenAddress": "0x8631e02168176AB709Cadf4Bcaea0B6266f5fa41" } @@ -1437,8 +2285,12 @@ "allowListEnabled": false, "decimals": 9, "name": "elizaOS", - "poolAddress": "0x3092650398cF38c548eA512C69564b086a357bcD", - "poolType": "burnMint", + "pool": { + "address": "0x3092650398cF38c548eA512C69564b086a357bcD", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "elizaOS", "tokenAddress": "0xea17Df5Cf6D172224892B5477A16ACb111182478" }, @@ -1446,8 +2298,12 @@ "allowListEnabled": false, "decimals": 9, "name": "elizaOS", - "poolAddress": "0x074D27002E1f0b89fEd9685af6e15a6EA8141A33", - "poolType": "burnMint", + "pool": { + "address": "0x074D27002E1f0b89fEd9685af6e15a6EA8141A33", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "elizaOS", "tokenAddress": "0xea17Df5Cf6D172224892B5477A16ACb111182478" }, @@ -1455,8 +2311,12 @@ "allowListEnabled": false, "decimals": 9, "name": "elizaOS", - "poolAddress": "0xC03F9E6c1C5F5D553C77781327640E0c7d30a73d", - "poolType": "burnMint", + "pool": { + "address": "0xC03F9E6c1C5F5D553C77781327640E0c7d30a73d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "elizaOS", "tokenAddress": "0xea17Df5Cf6D172224892B5477A16ACb111182478" }, @@ -1464,8 +2324,12 @@ "allowListEnabled": false, "decimals": 9, "name": "elizaOS", - "poolAddress": "9RyrjX5Jy3gFpYa4HLBBiK9sHWvvC9YTDKh1XZzJynSz", - "poolType": "burnMint", + "pool": { + "address": "9RyrjX5Jy3gFpYa4HLBBiK9sHWvvC9YTDKh1XZzJynSz", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "elizaOS", "tokenAddress": "DuMbhu7mvQvqQHGcnikDgb4XegXJRyhUBfdU22uELiZA" } @@ -1475,8 +2339,12 @@ "allowListEnabled": false, "decimals": 8, "name": "EmGEMx Switzerland", - "poolAddress": "0x0Fc71Baa3d2e40299c2c8039F6d7a24eF43509d8", - "poolType": "lockRelease", + "pool": { + "address": "0x0Fc71Baa3d2e40299c2c8039F6d7a24eF43509d8", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "EmCH", "tokenAddress": "0xA445bA2c94d9dE6bFd13F2fe4165E738C4330710" }, @@ -1484,8 +2352,12 @@ "allowListEnabled": false, "decimals": 8, "name": "EmGEMx Switzerland", - "poolAddress": "0x4488d79B3996364dBa219d98e82a6B0A3D937E62", - "poolType": "burnMint", + "pool": { + "address": "0x4488d79B3996364dBa219d98e82a6B0A3D937E62", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "EmCH", "tokenAddress": "0xA445bA2c94d9dE6bFd13F2fe4165E738C4330710" } @@ -1495,8 +2367,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Lorenzo Wrapped Bitcoin", - "poolAddress": "0xcb0FcCcb7a624395BaE54C3d3D0Ee27BC61Bd57a", - "poolType": "lockRelease", + "pool": { + "address": "0xcb0FcCcb7a624395BaE54C3d3D0Ee27BC61Bd57a", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "enzoBTC", "tokenAddress": "0x6A9A65B84843F5fD4aC9a0471C4fc11AFfFBce4a" }, @@ -1504,8 +2380,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Lorenzo Wrapped Bitcoin", - "poolAddress": "0xDA1EbA3837Ea8D96e6c24494F8590028Bc7C4788", - "poolType": "burnMint", + "pool": { + "address": "0xDA1EbA3837Ea8D96e6c24494F8590028Bc7C4788", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "enzoBTC", "tokenAddress": "0x1586E9A616B969e26f0712C504320a6800b5ce91" } @@ -1515,8 +2395,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ETHx", - "poolAddress": "0xc707F7E0f73c17a4eE7D3965c7b3c5E0ab42cBf5", - "poolType": "burnMint", + "pool": { + "address": "0xc707F7E0f73c17a4eE7D3965c7b3c5E0ab42cBf5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "ETHx", "tokenAddress": "0xED65C5085a18Fa160Af0313E60dcc7905E944Dc7" }, @@ -1524,8 +2408,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ETHx", - "poolAddress": "0xb144FcE921D564d77FD9F226965984654C1AFA55", - "poolType": "burnMint", + "pool": { + "address": "0xb144FcE921D564d77FD9F226965984654C1AFA55", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "ETHx", "tokenAddress": "0xc54B43eaF921A5194c7973A4d65E055E5a1453c2" }, @@ -1533,8 +2421,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ETHx", - "poolAddress": "0xeAD31B98179e2637Bb052a970Ac92Cbb2E26461d", - "poolType": "lockRelease", + "pool": { + "address": "0xeAD31B98179e2637Bb052a970Ac92Cbb2E26461d", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "ETHx", "tokenAddress": "0xA35b1B31Ce002FBF2058D22F30f95D405200A15b" } @@ -1544,8 +2436,12 @@ "allowListEnabled": false, "decimals": 6, "name": "eUSX Token", - "poolAddress": "0x60A97bd9ACf755954Ff0fE85837224f2920a57F3", - "poolType": "burnMint", + "pool": { + "address": "0x60A97bd9ACf755954Ff0fE85837224f2920a57F3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "eUSX", "tokenAddress": "0x21ACfc23D57dB524599dA96603acb5e97De2b7B2" }, @@ -1553,8 +2449,12 @@ "allowListEnabled": false, "decimals": 6, "name": "eUSX ", - "poolAddress": "3BLXohtpL2iyHsJLYzp4fmy9ZjbjE7ocPfDMFaU7U3gD", - "poolType": "lockRelease", + "pool": { + "address": "3BLXohtpL2iyHsJLYzp4fmy9ZjbjE7ocPfDMFaU7U3gD", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "eUSX", "tokenAddress": "3ThdFZQKM6kRyVGLG48kaPg5TRMhYMKY1iCRa9xop1WC" } @@ -1564,8 +2464,12 @@ "allowListEnabled": false, "decimals": 18, "name": "FEED", - "poolAddress": "0x6419221A0856f507a0b869814e461033d810990b", - "poolType": "burnMint", + "pool": { + "address": "0x6419221A0856f507a0b869814e461033d810990b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "FEED", "tokenAddress": "0xc3d77Eb7665eDF3c1D3Bdaa325A14D6ff254d2dD" }, @@ -1573,8 +2477,12 @@ "allowListEnabled": false, "decimals": 18, "name": "FEED", - "poolAddress": "0x9a22e73ef65F7EA0E6f2aE40F6847c944D3B5153", - "poolType": "lockRelease", + "pool": { + "address": "0x9a22e73ef65F7EA0E6f2aE40F6847c944D3B5153", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "FEED", "tokenAddress": "0xe9Cb2D7ADC24Fc59FE00D6C0A0669BDF16805Fe0" } @@ -1584,8 +2492,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Falcon Finance", - "poolAddress": "0x470ed414d305D2C784501Cc68e086E3B59d6E51E", - "poolType": "burnMint", + "pool": { + "address": "0x470ed414d305D2C784501Cc68e086E3B59d6E51E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "FF", "tokenAddress": "0xAC23B90A79504865D52B49B327328411a23d4dB2" }, @@ -1593,8 +2505,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Falcon Finance", - "poolAddress": "0x05ddaB21b57d0Dca8C3955c366526A229577558e", - "poolType": "lockRelease", + "pool": { + "address": "0x05ddaB21b57d0Dca8C3955c366526A229577558e", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "FF", "tokenAddress": "0xFA1C09fC8B491B6A4d3Ff53A10CAd29381b3F949" } @@ -1604,8 +2520,12 @@ "allowListEnabled": false, "decimals": 18, "name": "MindNetwork FHE Token", - "poolAddress": "0x8FA979BCf82859C994b82166390DFB03951CA86D", - "poolType": "burnMint", + "pool": { + "address": "0x8FA979BCf82859C994b82166390DFB03951CA86D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "FHE", "tokenAddress": "0xd55C9fB62E176a8Eb6968f32958FeFDD0962727E" }, @@ -1613,8 +2533,12 @@ "allowListEnabled": false, "decimals": 18, "name": "MindNetwork FHE Token", - "poolAddress": "0xCf2B643114b1098E5bc09B49f4D73C6A8Ea1c871", - "poolType": "burnMint", + "pool": { + "address": "0xCf2B643114b1098E5bc09B49f4D73C6A8Ea1c871", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "FHE", "tokenAddress": "0x8096cD953Fa2ABa1E60Dad27A3e58d71dF2F62F1" }, @@ -1622,8 +2546,12 @@ "allowListEnabled": false, "decimals": 18, "name": "MindNetwork FHE Token", - "poolAddress": "0x0c31b5DcF3CD6e588938D0699912d0028c911362", - "poolType": "lockRelease", + "pool": { + "address": "0x0c31b5DcF3CD6e588938D0699912d0028c911362", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "FHE", "tokenAddress": "0xd55C9fB62E176a8Eb6968f32958FeFDD0962727E" }, @@ -1631,8 +2559,12 @@ "allowListEnabled": false, "decimals": 18, "name": "MindNetwork FHE Token", - "poolAddress": "0xA88AEdaF95c85b5618379765f2725fFa6313B9DA", - "poolType": "burnMint", + "pool": { + "address": "0xA88AEdaF95c85b5618379765f2725fFa6313B9DA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "FHE", "tokenAddress": "0xd55C9fB62E176a8Eb6968f32958FeFDD0962727E" }, @@ -1640,28 +2572,49 @@ "allowListEnabled": false, "decimals": 9, "name": "MindNetwork FHE Token", - "poolAddress": "DJSZFhHPB197D5HRTvmPZ5e446wZihscHAPVmgw8jZ23", - "poolType": "burnMint", + "pool": { + "address": "DJSZFhHPB197D5HRTvmPZ5e446wZihscHAPVmgw8jZ23", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "FHE", "tokenAddress": "AUyYTiXWP77qerK7Ccb12oz27kdVcqCqDCe8MUBCWqWH" } }, "FLUID": { - "ethereum-mainnet-arbitrum-1": { + "bsc-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Fluid", - "poolAddress": "0x2d29D728C48C3F75e221D28d844E2bdFe5656BfC", + "poolAddress": "0x8945F36EDaf4c997aA23AC3246560808cBbB2373", "poolType": "burnMint", "symbol": "FLUID", "tokenAddress": "0x61E030A56D33e8260FdD81f03B162A79Fe3449Cd" }, + "ethereum-mainnet-arbitrum-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "Fluid", + "pool": { + "address": "0x2d29D728C48C3F75e221D28d844E2bdFe5656BfC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "FLUID", + "tokenAddress": "0x61E030A56D33e8260FdD81f03B162A79Fe3449Cd" + }, "ethereum-mainnet-base-1": { "allowListEnabled": false, "decimals": 18, "name": "Fluid", - "poolAddress": "0x99D94f528CeA3eE1791ab7B476A1FACb4297CA17", - "poolType": "burnMint", + "pool": { + "address": "0x99D94f528CeA3eE1791ab7B476A1FACb4297CA17", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "FLUID", "tokenAddress": "0x61E030A56D33e8260FdD81f03B162A79Fe3449Cd" }, @@ -1669,8 +2622,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Fluid", - "poolAddress": "0x639f35C5E212D61Fe14Bd5CD8b66aAe4df11a50c", - "poolType": "lockRelease", + "pool": { + "address": "0x639f35C5E212D61Fe14Bd5CD8b66aAe4df11a50c", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "FLUID", "tokenAddress": "0x6f40d4A6237C257fff2dB00FA0510DeEECd303eb" }, @@ -1678,8 +2635,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Fluid", - "poolAddress": "0x10fD7245f6ca39885D3A398b03dCcCC833fC96A1", - "poolType": "burnMint", + "pool": { + "address": "0x10fD7245f6ca39885D3A398b03dCcCC833fC96A1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "FLUID", "tokenAddress": "0x61E030A56D33e8260FdD81f03B162A79Fe3449Cd" }, @@ -1687,8 +2648,12 @@ "allowListEnabled": false, "decimals": 9, "name": "FLUID", - "poolAddress": "G9gWPSi5WFQuDEujXZgtuaD63uGmaGwfot6MiRZZ9pNm", - "poolType": "burnMint", + "pool": { + "address": "G9gWPSi5WFQuDEujXZgtuaD63uGmaGwfot6MiRZZ9pNm", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "FLUID", "tokenAddress": "DuEy8wWrzCUun5ZbbG9hkVqXqqicpTQw8gB7nEAzpCHQ" } @@ -1698,8 +2663,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Generative Protocol", - "poolAddress": "0x4097142E53fAA47b02f57D61Cf58787c3B6d951b", - "poolType": "burnMint", + "pool": { + "address": "0x4097142E53fAA47b02f57D61Cf58787c3B6d951b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "GEN", "tokenAddress": "0x876ceF4219752930c93446fF15bF64A94ed404D5" }, @@ -1707,8 +2676,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Generative Protocol", - "poolAddress": "0x003491Bdfe15179aC2cEfEf9F5D0e235F096C3b0", - "poolType": "burnMint", + "pool": { + "address": "0x003491Bdfe15179aC2cEfEf9F5D0e235F096C3b0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "GEN", "tokenAddress": "0x442457bA124721f7e0AB7bf8a80FBc35ACDdc9f5" } @@ -1718,8 +2691,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Gho Token", - "poolAddress": "0xDe6539018B095353A40753Dc54C91C68c9487D4E", - "poolType": "burnMint", + "pool": { + "address": "0xDe6539018B095353A40753Dc54C91C68c9487D4E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "GHO", "tokenAddress": "0xfc421aD3C883Bf9E7C4f42dE845C4e4405799e73" }, @@ -1727,8 +2704,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Gho Token", - "poolAddress": "0xB94Ab28c6869466a46a42abA834ca2B3cECCA5eB", - "poolType": "burnMint", + "pool": { + "address": "0xB94Ab28c6869466a46a42abA834ca2B3cECCA5eB", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "GHO", "tokenAddress": "0x7dfF72693f6A4149b17e7C6314655f6A9F7c8B33" }, @@ -1736,12 +2717,29 @@ "allowListEnabled": false, "decimals": 18, "name": "Gho Token", - "poolAddress": "0x98217A06721Ebf727f2C8d9aD7718ec28b7aAe34", - "poolType": "burnMint", + "pool": { + "address": "0x98217A06721Ebf727f2C8d9aD7718ec28b7aAe34", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "GHO", "tokenAddress": "0x6Bb7a212910682DCFdbd5BCBb3e28FB4E8da10Ee" }, "ethereum-mainnet-ink-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "Gho Token", + "pool": { + "address": "0xDe6539018B095353A40753Dc54C91C68c9487D4E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, + "symbol": "GHO", + "tokenAddress": "0xfc421aD3C883Bf9E7C4f42dE845C4e4405799e73" + }, + "ethereum-mainnet-mantle-1": { "allowListEnabled": false, "decimals": 18, "name": "Gho Token", @@ -1754,8 +2752,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Gho Token", - "poolAddress": "0x06179f7C1be40863405f374E7f5F8806c728660A", - "poolType": "lockRelease", + "pool": { + "address": "0x06179f7C1be40863405f374E7f5F8806c728660A", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "GHO", "tokenAddress": "0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f" }, @@ -1763,8 +2765,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Gho Token", - "poolAddress": "0x360d8aa8F6b09B7BC57aF34db2Eb84dD87bf4d12", - "poolType": "burnMint", + "pool": { + "address": "0x360d8aa8F6b09B7BC57aF34db2Eb84dD87bf4d12", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "GHO", "tokenAddress": "0xb77E872A68C62CfC0dFb02C067Ecc3DA23B4bbf3" }, @@ -1772,8 +2778,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Gho Token", - "poolAddress": "0xDe6539018B095353A40753Dc54C91C68c9487D4E", - "poolType": "burnMint", + "pool": { + "address": "0xDe6539018B095353A40753Dc54C91C68c9487D4E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "GHO", "tokenAddress": "0xfc421aD3C883Bf9E7C4f42dE845C4e4405799e73" } @@ -1783,8 +2793,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Graph Token", - "poolAddress": "0xf0b6E11fB42fA8874cCB422C22D8036b1742B783", - "poolType": "burnMint", + "pool": { + "address": "0xf0b6E11fB42fA8874cCB422C22D8036b1742B783", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "GRT", "tokenAddress": "0x408A6A9E7aFa805B92953e5E92D93d5DCCa2B4a2" }, @@ -1792,8 +2806,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Graph Token", - "poolAddress": "0x318Ec96df83AccC18B5EAD5D23e0F022F7Eb5503", - "poolType": "lockRelease", + "pool": { + "address": "0x318Ec96df83AccC18B5EAD5D23e0F022F7Eb5503", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "GRT", "tokenAddress": "0x9623063377AD1B27544C965cCd7342f7EA7e88C7" }, @@ -1801,8 +2819,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Graph Token", - "poolAddress": "0xC1E69F1b34E7F8d05919965Fc81FC7aDB546A52b", - "poolType": "burnMint", + "pool": { + "address": "0xC1E69F1b34E7F8d05919965Fc81FC7aDB546A52b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "GRT", "tokenAddress": "0x7CCC78a24C3311eB6f6806f6fcf2c07CAe78CfE3" } @@ -1812,8 +2834,12 @@ "allowListEnabled": false, "decimals": 18, "name": "High Yield ETH Index", - "poolAddress": "0x288B1b97603b4ae48F18B893caf721f20fcb0E59", - "poolType": "burnMint", + "pool": { + "address": "0x288B1b97603b4ae48F18B893caf721f20fcb0E59", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "hyETH", "tokenAddress": "0x8b5D1d8B3466eC21f8eE33cE63F319642c026142" }, @@ -1821,8 +2847,12 @@ "allowListEnabled": false, "decimals": 18, "name": "High Yield ETH Index", - "poolAddress": "0xbEE038Af079a702b2ED0af7886DA101443Ddb1CE", - "poolType": "burnMint", + "pool": { + "address": "0xbEE038Af079a702b2ED0af7886DA101443Ddb1CE", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "hyETH", "tokenAddress": "0xC73e76Aa9F14C1837CDB49bd028E8Ff5a0a71dAD" }, @@ -1830,8 +2860,12 @@ "allowListEnabled": false, "decimals": 18, "name": "High Yield ETH Index", - "poolAddress": "0x3999490C55Fb8332F5f3AD00212435526fA3E576", - "poolType": "lockRelease", + "pool": { + "address": "0x3999490C55Fb8332F5f3AD00212435526fA3E576", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "hyETH", "tokenAddress": "0xc4506022Fb8090774E8A628d5084EED61D9B99Ee" } @@ -1841,8 +2875,12 @@ "allowListEnabled": false, "decimals": 8, "name": "iBTC", - "poolAddress": "0xCBeD22C12b9CBFaBa8E352D1EC6279885Df8725F", - "poolType": "burnMint", + "pool": { + "address": "0xCBeD22C12b9CBFaBa8E352D1EC6279885Df8725F", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "IBTC", "tokenAddress": "0x050C24dBf1eEc17babE5fc585F06116A259CC77A" }, @@ -1850,8 +2888,12 @@ "allowListEnabled": false, "decimals": 8, "name": "iBTC", - "poolAddress": "0x206E9A22B384d3863b606C41030Ec2A19D3CBb95", - "poolType": "burnMint", + "pool": { + "address": "0x206E9A22B384d3863b606C41030Ec2A19D3CBb95", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "IBTC", "tokenAddress": "0x12418783e860997eb99e8aCf682DF952F721cF62" }, @@ -1859,8 +2901,12 @@ "allowListEnabled": false, "decimals": 8, "name": "iBTC", - "poolAddress": "0xb6f8e9604BAFD1482631740931783998e9E736A7", - "poolType": "burnMint", + "pool": { + "address": "0xb6f8e9604BAFD1482631740931783998e9E736A7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "IBTC", "tokenAddress": "0x2bAa7E92F3F14883264BfA63058cC223Ad719438" }, @@ -1868,8 +2914,12 @@ "allowListEnabled": false, "decimals": 8, "name": "iBTC", - "poolAddress": "0x08B4058F16D243C977ea1fe91B20Af31057b5aBb", - "poolType": "burnMint", + "pool": { + "address": "0x08B4058F16D243C977ea1fe91B20Af31057b5aBb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "IBTC", "tokenAddress": "0x20157DBAbb84e3BBFE68C349d0d44E48AE7B5AD2" } @@ -1879,8 +2929,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Iluminary Token", - "poolAddress": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", - "poolType": "burnMint", + "pool": { + "address": "0xa132F089492CcE5f1D79483a9e4552f37266ed01", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "ILMT", "tokenAddress": "0x98a0a245Ef9A96Cf28f1Ebf1a3b3bC562Ed8D783" }, @@ -1888,8 +2942,12 @@ "allowListEnabled": false, "decimals": 8, "name": "iLuminary Token", - "poolAddress": "GhgD4CQxPxrV3Ad3xaZn6AAJ6f1R5rKN3n2gkBzQ23jU", - "poolType": "burnMint", + "pool": { + "address": "GhgD4CQxPxrV3Ad3xaZn6AAJ6f1R5rKN3n2gkBzQ23jU", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "ILMT", "tokenAddress": "Au6V6WrkjWZYSdCJtJFYPysZXr1qncHXZshZ7w8SnDjv" } @@ -1899,8 +2957,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xPlanetIX", - "poolAddress": "0x1e9C67b9cbe6FfFfDc441Be359d9f78B5167f30E", - "poolType": "burnMint", + "pool": { + "address": "0x1e9C67b9cbe6FfFfDc441Be359d9f78B5167f30E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xIXT", "tokenAddress": "0x8b04bf3358B88e3630aa64C1c76FF3B6C699C6a7" }, @@ -1908,8 +2970,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xPlanetIX", - "poolAddress": "0x803e3858B81E0595E5F39946a68AF3546D629ee7", - "poolType": "burnMint", + "pool": { + "address": "0x803e3858B81E0595E5F39946a68AF3546D629ee7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xIXT", "tokenAddress": "0x8b04bf3358B88e3630aa64C1c76FF3B6C699C6a7" }, @@ -1917,8 +2983,12 @@ "allowListEnabled": false, "decimals": 18, "name": "PlanetIX", - "poolAddress": "0xF85fB90550bB01905556Efd7B07eDe487097Bf78", - "poolType": "burnMint", + "pool": { + "address": "0xF85fB90550bB01905556Efd7B07eDe487097Bf78", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "IXT", "tokenAddress": "0xD32B4e4a565A1B786979276de16a13eA2e10bECd" }, @@ -1926,8 +2996,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xPlanetIX", - "poolAddress": "0x51df9751404DB200b354ED6a5e27DdA6C557883D", - "poolType": "burnMint", + "pool": { + "address": "0x51df9751404DB200b354ED6a5e27DdA6C557883D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xIXT", "tokenAddress": "0x8b04bf3358B88e3630aa64C1c76FF3B6C699C6a7" }, @@ -1935,8 +3009,12 @@ "allowListEnabled": false, "decimals": 18, "name": "PlanetIX", - "poolAddress": "0x8206A135cac573a2f96873dc7ad7C83B08725FaB", - "poolType": "lockRelease", + "pool": { + "address": "0x8206A135cac573a2f96873dc7ad7C83B08725FaB", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "IXT", "tokenAddress": "0xE06Bd4F5aAc8D0aA337D13eC88dB6defC6eAEefE" } @@ -1946,8 +3024,12 @@ "allowListEnabled": false, "decimals": 18, "name": "JasmyCoin", - "poolAddress": "0xc929ad75B72593967DE83E7F7Cda0493458261D9", - "poolType": "burnMint", + "pool": { + "address": "0xc929ad75B72593967DE83E7F7Cda0493458261D9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "JASMY", "tokenAddress": "0x991Ad9149f3fe170ACc152BE2D46B804de688Ed8" }, @@ -1955,19 +3037,55 @@ "allowListEnabled": false, "decimals": 18, "name": "JasmyCoin", - "poolAddress": "0x3f7AeF129Ce37EA06150C176677bEc75EF29A33f", - "poolType": "lockRelease", + "pool": { + "address": "0x3f7AeF129Ce37EA06150C176677bEc75EF29A33f", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "JASMY", "tokenAddress": "0x7420B4b9a0110cdC71fB720908340C03F9Bc03EC" } }, + "JCT": { + "bsc-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "JANCTION", + "pool": { + "address": "0xdA1B1B3d3C97974B272E28f70F25Ab7c290e8357", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "JCT", + "tokenAddress": "0xeA37A8DE1de2d9D10772EEB569e28Bfa5Cb17707" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "JANCTION", + "pool": { + "address": "0x58e53cad56180743aCE00349Ef3E1BFE4EfF5732", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "JCT", + "tokenAddress": "0xC477B6dfd26EC2460b3b92de18837Fd476Ea7549" + } + }, "kHYPE": { "hyperliquid-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Kinetiq Staked HYPE", - "poolAddress": "0xca02b4fd9a4e5dAd986eA2Ecb5d7bb43fa9bC605", - "poolType": "lockRelease", + "pool": { + "address": "0xca02b4fd9a4e5dAd986eA2Ecb5d7bb43fa9bC605", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "kHYPE", "tokenAddress": "0xfD739d4e423301CE9385c1fb8850539D657C296D" }, @@ -1975,19 +3093,55 @@ "allowListEnabled": false, "decimals": 18, "name": "Kinetiq Staked HYPE", - "poolAddress": "0xf76A0c47900ca2dD1874AB4Dc4049810E919684d", - "poolType": "burnMint", + "pool": { + "address": "0xf76A0c47900ca2dD1874AB4Dc4049810E919684d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "kHYPE", "tokenAddress": "0x319053B625e598994Dd1179948771a4C2f66b873" } }, + "KNET": { + "bsc-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Kingnet AI", + "pool": { + "address": "0x02E5F79eFD3c5e0306fD1127787EA672634AACF1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "KNET", + "tokenAddress": "0x8b24BF9fE8BB1D4D9deA81Eebc9Fed6F0Fc67a46" + }, + "solana-mainnet": { + "allowListEnabled": false, + "decimals": 9, + "name": "Kingnet AI", + "pool": { + "address": "5skyDWAPgiNe7ttGoEEdn4Z3dHxvkF4vi3wGdebQ76cR", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, + "symbol": "KNET", + "tokenAddress": "CfVs3waH2Z9TM397qSkaipTDhA9wWgtt8UchZKfwkYiu" + } + }, "LAND": { "bsc-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Landshare Token", - "poolAddress": "0x3404C137c2AA3Cf69c7322c6f39a6cbd8c3b769D", - "poolType": "lockRelease", + "pool": { + "address": "0x3404C137c2AA3Cf69c7322c6f39a6cbd8c3b769D", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "LAND", "tokenAddress": "0xA73164DB271931CF952cBaEfF9E8F5817b42fA5C" }, @@ -1995,8 +3149,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Landshare Token", - "poolAddress": "0x0d13d3683DD866FDfd6707976eb38Fa9A058E100", - "poolType": "burnMint", + "pool": { + "address": "0x0d13d3683DD866FDfd6707976eb38Fa9A058E100", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LAND", "tokenAddress": "0x27Bc2757fAb0b8aB406016D1f71d8123452095d3" }, @@ -2004,8 +3162,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Landshare Token", - "poolAddress": "0x047beEDAC57540d407db63aD6CF72Bde07c5B093", - "poolType": "burnMint", + "pool": { + "address": "0x047beEDAC57540d407db63aD6CF72Bde07c5B093", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LAND", "tokenAddress": "0xC03E6ad83dE7C58c9166fF08D66B960d78e64105" } @@ -2015,8 +3177,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0xd24658051aa6c8ACf874F686D5dA325a87d2D146", - "poolType": "burnMint", + "pool": { + "address": "0xd24658051aa6c8ACf874F686D5dA325a87d2D146", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" }, @@ -2024,8 +3190,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0xc6c22D4Be6Cc50E6D01BD6325b6cD715A52f8154", - "poolType": "burnMint", + "pool": { + "address": "0xc6c22D4Be6Cc50E6D01BD6325b6cD715A52f8154", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" }, @@ -2033,8 +3203,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0xf191a1CE04fD54f090B4d97316258b6009C562d7", - "poolType": "burnMint", + "pool": { + "address": "0xf191a1CE04fD54f090B4d97316258b6009C562d7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" }, @@ -2042,8 +3216,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0x770D1bbdca08e3272233709B27C004F510bfDf86", - "poolType": "burnMint", + "pool": { + "address": "0x770D1bbdca08e3272233709B27C004F510bfDf86", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" }, @@ -2051,8 +3229,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0x2A70CbF60a9252Ff312719885088283f930750BA", - "poolType": "burnMint", + "pool": { + "address": "0x2A70CbF60a9252Ff312719885088283f930750BA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" }, @@ -2060,8 +3242,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0x9Ef2919f333Cdf13Fb609C0341bE0c852f691788", - "poolType": "burnMint", + "pool": { + "address": "0x9Ef2919f333Cdf13Fb609C0341bE0c852f691788", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" }, @@ -2069,26 +3255,47 @@ "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0x88E18636EfFC3b3cd520FC72B710eb99C0017BC7", - "poolType": "burnMint", + "pool": { + "address": "0x88E18636EfFC3b3cd520FC72B710eb99C0017BC7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LBTC", "tokenAddress": "0x8236a87084f8B84306f72007F36F2618A5634494" }, - "monad-mainnet": { + "megaeth-mainnet": { "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0xD9527ffE58CbEcC9A64511Fc559e0C0825Df940a", + "poolAddress": "0xD7F069e67345ED91AC699e7EcFDc211782495888", "poolType": "burnMint", "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" }, + "monad-mainnet": { + "allowListEnabled": false, + "decimals": 8, + "name": "Lombard Staked Bitcoin", + "pool": { + "address": "0xD9527ffE58CbEcC9A64511Fc559e0C0825Df940a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "LBTC", + "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" + }, "polygon-mainnet-katana": { "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0xE4B5166b1D60C2208A934176522461c470A37d56", - "poolType": "burnMint", + "pool": { + "address": "0xE4B5166b1D60C2208A934176522461c470A37d56", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" }, @@ -2096,8 +3303,25 @@ "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0x775C438b07d5667aEFa3DE493A7cc2Df3a199E99", - "poolType": "burnMint", + "pool": { + "address": "0x775C438b07d5667aEFa3DE493A7cc2Df3a199E99", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "LBTC", + "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" + }, + "stable-mainnet": { + "allowListEnabled": false, + "decimals": 8, + "name": "Lombard Staked Bitcoin", + "pool": { + "address": "0xD7F069e67345ED91AC699e7EcFDc211782495888", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" }, @@ -2105,8 +3329,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Lombard Staked Bitcoin", - "poolAddress": "0xAe5E2940Fc01C0f8076D36749509C75E43da0C70", - "poolType": "burnMint", + "pool": { + "address": "0xAe5E2940Fc01C0f8076D36749509C75E43da0C70", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LBTC", "tokenAddress": "0xecAc9C5F704e954931349Da37F60E39f515c11c1" } @@ -2116,8 +3344,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Ledgity Token", - "poolAddress": "0x9C4a695903Eaa0d958F3ECabdD8b9122c08505ac", - "poolType": "burnMint", + "pool": { + "address": "0x9C4a695903Eaa0d958F3ECabdD8b9122c08505ac", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LDY", "tokenAddress": "0x999FAF0AF2fF109938eeFE6A7BF91CA56f0D07e1" }, @@ -2125,8 +3357,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Ledgity Token", - "poolAddress": "0x9d5665F2C06C77dF7B3f3bbEE0a14e63dCd614b2", - "poolType": "burnMint", + "pool": { + "address": "0x9d5665F2C06C77dF7B3f3bbEE0a14e63dCd614b2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LDY", "tokenAddress": "0x055d20a70eFd45aB839Ae1A39603D0cFDBDd8a13" }, @@ -2134,8 +3370,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Ledgity Token", - "poolAddress": "0x542BF6910dB102D10f84565E041c2761BE95be84", - "poolType": "lockRelease", + "pool": { + "address": "0x542BF6910dB102D10f84565E041c2761BE95be84", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "LDY", "tokenAddress": "0x482dF7483a52496F4C65AB499966dfcdf4DDFDbc" } @@ -2145,8 +3385,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x56046FcadbcB62eD4b5643aF09724313624e88e1", - "poolType": "burnMint", + "pool": { + "address": "0x56046FcadbcB62eD4b5643aF09724313624e88e1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LEASH", "tokenAddress": "0x897Ce250199d102Ea103Aaf3a6E7906cde757560" }, @@ -2154,8 +3398,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x385FE033d211BEA56a2E0bF0DE39feB1cE24DFC9", - "poolType": "burnMint", + "pool": { + "address": "0x385FE033d211BEA56a2E0bF0DE39feB1cE24DFC9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LEASH", "tokenAddress": "0xf94A52468fF79862B8f288faF7900d34e74A1992" }, @@ -2163,8 +3411,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x33aC23E54A7Bfb159e781c8973B832b3bE2Bf211", - "poolType": "burnMint", + "pool": { + "address": "0x33aC23E54A7Bfb159e781c8973B832b3bE2Bf211", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LEASH", "tokenAddress": "0x2b702DC45b540aEDA62F60cE4E5BFAED37b1D27a" }, @@ -2172,8 +3424,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x2133c3b98928d0DC519Fc0607EB39DC2fc4b9df4", - "poolType": "burnMint", + "pool": { + "address": "0x2133c3b98928d0DC519Fc0607EB39DC2fc4b9df4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LEASH", "tokenAddress": "0xc55eABF6624224b6E185B6A79a3217e0e751046A" }, @@ -2181,8 +3437,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0xDFb202aD6734530d60501aEaC1BCf99688D8319F", - "poolType": "burnMint", + "pool": { + "address": "0xDFb202aD6734530d60501aEaC1BCf99688D8319F", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LEASH", "tokenAddress": "0x1649DE9028C0a6B958118A977099d66eF0DA5a92" }, @@ -2190,8 +3450,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0xB23a7814f718448ba2e1a2B362a8AB0c4e8Ab341", - "poolType": "burnMint", + "pool": { + "address": "0xB23a7814f718448ba2e1a2B362a8AB0c4e8Ab341", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LEASH", "tokenAddress": "0x90B0C73F19bd2EB9Bcd6b1C6c787a63ae851b336" }, @@ -2199,8 +3463,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x26dEd7458Bf906316b638504965D1e9D5AE73c57", - "poolType": "burnMint", + "pool": { + "address": "0x26dEd7458Bf906316b638504965D1e9D5AE73c57", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LEASH", "tokenAddress": "0xBc53643F2D736743ed29B6dC36E30F5Fb8941090" }, @@ -2208,8 +3476,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x3da3283E0D0c30b44BA899b37fD6da6D0B776646", - "poolType": "burnMint", + "pool": { + "address": "0x3da3283E0D0c30b44BA899b37fD6da6D0B776646", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LEASH", "tokenAddress": "0x4e1a69B48A7aE9Fc8fD2623089c4B378f24a64A9" }, @@ -2217,8 +3489,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0xA6a6663a159e80ad3682698b0a595DF3594491B5", - "poolType": "burnMint", + "pool": { + "address": "0xA6a6663a159e80ad3682698b0a595DF3594491B5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LEASH", "tokenAddress": "0x70Ed1C42D29678D2D5Bad7197A4281B095AD7fD6" }, @@ -2226,8 +3502,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x852467AB8b1bBB2D1c8d8802cd7820B906D4609A", - "poolType": "burnMint", + "pool": { + "address": "0x852467AB8b1bBB2D1c8d8802cd7820B906D4609A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LEASH", "tokenAddress": "0xA3D0D0C81dBe4511724f875F7f2fa794a14bee64" }, @@ -2235,8 +3515,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x975f51b7BFac520F35A791F5E4206162300244c3", - "poolType": "burnMint", + "pool": { + "address": "0x975f51b7BFac520F35A791F5E4206162300244c3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LEASH", "tokenAddress": "0xDE4dd6Db8072eb6999B88B7D7E0c8C0C01637578" }, @@ -2244,8 +3528,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x1d201c7277f971CBb6Cf32636E79187c83C58490", - "poolType": "burnMint", + "pool": { + "address": "0x1d201c7277f971CBb6Cf32636E79187c83C58490", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LEASH", "tokenAddress": "0xCEeDbfc700d17A277Ab1cA9E19A2CaF0c42ced41" }, @@ -2253,8 +3541,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x7f5BB6146B490B6C1e1c8D8fD60FDE93636274b1", - "poolType": "burnMint", + "pool": { + "address": "0x7f5BB6146B490B6C1e1c8D8fD60FDE93636274b1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LEASH", "tokenAddress": "0xa9BBE4c88F4988Ec8328e44b0889404824aBEb62" }, @@ -2262,8 +3554,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0xef98939F005Da3Aa186ebb842842569213863D17", - "poolType": "burnMint", + "pool": { + "address": "0xef98939F005Da3Aa186ebb842842569213863D17", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LEASH", "tokenAddress": "0x743C48C6057b4c2480F2458F2D1CE967dF96B724" }, @@ -2271,8 +3567,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0xEa9c3dB69C9eE60FB0B06d1A1c9077B16F2D7C82", - "poolType": "lockRelease", + "pool": { + "address": "0xEa9c3dB69C9eE60FB0B06d1A1c9077B16F2D7C82", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "LEASH", "tokenAddress": "0x27C70Cd1946795B66be9d954418546998b546634" }, @@ -2280,8 +3580,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x711948bE2234b51653dD9978c107671aF4Eb8d7F", - "poolType": "burnMint", + "pool": { + "address": "0x711948bE2234b51653dD9978c107671aF4Eb8d7F", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LEASH", "tokenAddress": "0x6aF85BfA857bB88F2E3Ae07839182491d34ca11d" }, @@ -2289,8 +3593,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x1D67640d37117Cbe876c5C50e6e2B6DE0c53dA70", - "poolType": "burnMint", + "pool": { + "address": "0x1D67640d37117Cbe876c5C50e6e2B6DE0c53dA70", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LEASH", "tokenAddress": "0x2992F24a5d1A2914C0981933E9870e76d60D299c" }, @@ -2298,8 +3606,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0x5EF69257f95d822b7D6dd60Ee574A34e66D6B3B2", - "poolType": "burnMint", + "pool": { + "address": "0x5EF69257f95d822b7D6dd60Ee574A34e66D6B3B2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LEASH", "tokenAddress": "0x3C76af2dCCd31ac4A146C0d55cCc4bfd13051379" }, @@ -2307,8 +3619,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DOGE KILLER", - "poolAddress": "0xEaA2885DcdD6689a95642DC6d72F24F81EB170f5", - "poolType": "burnMint", + "pool": { + "address": "0xEaA2885DcdD6689a95642DC6d72F24F81EB170f5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LEASH", "tokenAddress": "0xBb1ea2697b13Cc06e03D875D2d39c06AC6dd5a93" } @@ -2318,8 +3634,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lendefi DAO", - "poolAddress": "0x934635de453A1161D02Ce395F2F59E775597fE13", - "poolType": "burnMint", + "pool": { + "address": "0x934635de453A1161D02Ce395F2F59E775597fE13", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LEND", "tokenAddress": "0x5e53AeBE377eFC92213514eC07f8EF3Af426DD1d" }, @@ -2327,8 +3647,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lendefi DAO", - "poolAddress": "0x934635de453A1161D02Ce395F2F59E775597fE13", - "poolType": "burnMint", + "pool": { + "address": "0x934635de453A1161D02Ce395F2F59E775597fE13", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LEND", "tokenAddress": "0x5e53AeBE377eFC92213514eC07f8EF3Af426DD1d" }, @@ -2336,8 +3660,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lendefi DAO", - "poolAddress": "0x934635de453A1161D02Ce395F2F59E775597fE13", - "poolType": "burnMint", + "pool": { + "address": "0x934635de453A1161D02Ce395F2F59E775597fE13", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LEND", "tokenAddress": "0x5e53AeBE377eFC92213514eC07f8EF3Af426DD1d" }, @@ -2345,8 +3673,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lendefi DAO", - "poolAddress": "0x934635de453A1161D02Ce395F2F59E775597fE13", - "poolType": "burnMint", + "pool": { + "address": "0x934635de453A1161D02Ce395F2F59E775597fE13", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LEND", "tokenAddress": "0x5e53AeBE377eFC92213514eC07f8EF3Af426DD1d" }, @@ -2354,8 +3686,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lendefi DAO", - "poolAddress": "0x934635de453A1161D02Ce395F2F59E775597fE13", - "poolType": "burnMint", + "pool": { + "address": "0x934635de453A1161D02Ce395F2F59E775597fE13", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LEND", "tokenAddress": "0x5e53AeBE377eFC92213514eC07f8EF3Af426DD1d" }, @@ -2363,8 +3699,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lendefi DAO", - "poolAddress": "0x934635de453A1161D02Ce395F2F59E775597fE13", - "poolType": "burnMint", + "pool": { + "address": "0x934635de453A1161D02Ce395F2F59E775597fE13", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LEND", "tokenAddress": "0x5e53AeBE377eFC92213514eC07f8EF3Af426DD1d" } @@ -2374,8 +3714,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xF81f4a748F8d2DbCA48Bfa704968A76fB062A358", - "poolType": "burnMint", + "pool": { + "address": "0xF81f4a748F8d2DbCA48Bfa704968A76fB062A358", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x76159c2b43ff6F630193e37EC68452169914C1Bb" }, @@ -2383,8 +3727,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xD3F31950e5Ec340b021D0d27454F44Edb7304C18", - "poolType": "burnMint", + "pool": { + "address": "0xD3F31950e5Ec340b021D0d27454F44Edb7304C18", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x76a443768A5e3B8d1AED0105FC250877841Deb40" }, @@ -2392,7 +3740,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x2Ea38D6cDb6774992d4A62fe622f4405663729Dd" }, @@ -2400,7 +3752,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xf575731b78981B86d34321d875A3D25a48479be6" }, @@ -2408,8 +3764,12 @@ "allowListEnabled": false, "decimals": 8, "name": "ChainLink Token", - "poolAddress": "0x7a5dcf83decbfc7418ae0d37be93370b47bf9bc4657dacd1a02d6f58629f6b38", - "poolType": "burnMint", + "pool": { + "address": "0x7a5dcf83decbfc7418ae0d37be93370b47bf9bc4657dacd1a02d6f58629f6b38", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x8c764993820ea735719f1ff7f1a0f80c022b18e7b5daefa35adf60a3a6556566" }, @@ -2417,7 +3777,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Chainlink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK.e", "tokenAddress": "0x5947BB275c521040051D82396192181b413227A3" }, @@ -2425,7 +3789,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x71052BAe71C25C78E37fD12E5ff1101A71d9018F" }, @@ -2433,7 +3801,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x99f0d88B81b758AB07E22C7AbA00E0121a882dEA" }, @@ -2441,7 +3813,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x56B275c0Ec034a229a1deD8DB17089544bc276D9" }, @@ -2449,7 +3825,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x5aB885CDa7216b163fb6F813DEC1E1532516c833" }, @@ -2457,7 +3837,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x30e85A5c9525AD9a7A0FA5C74df4Baf0b01aD241" }, @@ -2465,7 +3849,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x709229D9587886a1eDFeE6b5cE636E1D70d1cE39" }, @@ -2473,7 +3861,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x71052BAe71C25C78E37fD12E5ff1101A71d9018F" }, @@ -2481,7 +3873,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13" }, @@ -2489,7 +3885,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x404460C6A5EdE2D891e8297795264fDe62ADBB75" }, @@ -2497,8 +3897,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0x554652E7F10fB8aa3e12226213c6826F98B09CF0", - "poolType": "burnMint", + "pool": { + "address": "0x554652E7F10fB8aa3e12226213c6826F98B09CF0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xd07294e6E917e07dfDcee882dd1e2565085C2ae0" }, @@ -2506,7 +3910,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x3902228D6A3d2Dc44731fD9d45FeE6a61c722D0b" }, @@ -2514,7 +3922,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x7311DED199CC28D80E58e81e8589aa160199FCD2" }, @@ -2522,7 +3934,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x8c80A01F461f297Df7F9DA3A4f740D7297C8Ac85" }, @@ -2530,7 +3946,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x61170ca9fB9cF98d4c7d684e07be6D969D59667E" }, @@ -2538,8 +3958,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xff170aD8f1d86eFAC90CA7a2E1204bA64aC5e0f9", - "poolType": "burnMint", + "pool": { + "address": "0xff170aD8f1d86eFAC90CA7a2E1204bA64aC5e0f9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xd2FE54D1E5F568eB710ba9d898Bf4bD02C7c0353" }, @@ -2547,7 +3971,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4" }, @@ -2555,8 +3983,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xBA148bAF60CCc4d7D86aED4fCff04D5b3265cAd4", - "poolType": "burnMint", + "pool": { + "address": "0xBA148bAF60CCc4d7D86aED4fCff04D5b3265cAd4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x88Fb150BDc53A65fe94Dea0c9BA0a6dAf8C6e196" }, @@ -2564,8 +3996,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0x9fCd83bC7F67ADa1fB51a4caBEa333c72B641bd1", - "poolType": "burnMint", + "pool": { + "address": "0x9fCd83bC7F67ADa1fB51a4caBEa333c72B641bd1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x93202eC683288a9EA75BB829c6baCFb2BfeA9013" }, @@ -2573,7 +4009,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x71052BAe71C25C78E37fD12E5ff1101A71d9018F" }, @@ -2581,7 +4021,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x71052BAe71C25C78E37fD12E5ff1101A71d9018F" }, @@ -2589,7 +4033,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xa18152629128738a5c081eb226335FEd4B9C95e9" }, @@ -2597,7 +4045,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xfe36cF0B43aAe49fBc5cFC5c0AF22a623114E043" }, @@ -2605,8 +4057,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xDeC8A6f06FDdA5aAE262631f37b79f182a23464B", - "poolType": "burnMint", + "pool": { + "address": "0xDeC8A6f06FDdA5aAE262631f37b79f182a23464B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x183E3691EfF3524B2315D3703D94F922CbE51F54" }, @@ -2614,7 +4070,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x350a791Bfc2C21F9Ed5d10980Dad2e2638ffa7f6" }, @@ -2622,7 +4082,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xdB7A504CF869484dd6aC5FaF925c8386CBF7573D" }, @@ -2630,8 +4094,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xff170aD8f1d86eFAC90CA7a2E1204bA64aC5e0f9", - "poolType": "burnMint", + "pool": { + "address": "0xff170aD8f1d86eFAC90CA7a2E1204bA64aC5e0f9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x548C6944cba02B9D1C0570102c89de64D258d3Ac" }, @@ -2639,7 +4107,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x917a3964C37993e99a47C779bEb5Db1E9d13804d" }, @@ -2647,7 +4119,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xEF66491eab4bbB582c57b14778afd8dFb70D8A1A" }, @@ -2655,7 +4131,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x915b648e994d5f31059B38223b9fbe98ae185473" }, @@ -2663,7 +4143,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x8aF9711B44695a5A081F25AB9903DDB73aCf8FA9" }, @@ -2671,7 +4155,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x5D6d033B4FbD2190D99D930719fAbAcB64d2439a" }, @@ -2679,8 +4167,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xff170aD8f1d86eFAC90CA7a2E1204bA64aC5e0f9", - "poolType": "burnMint", + "pool": { + "address": "0xff170aD8f1d86eFAC90CA7a2E1204bA64aC5e0f9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x52869bae3E091e36b0915941577F2D47d8d8B534" }, @@ -2688,7 +4180,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x8ce7618E8f8E514d13889283F58FF03B794e6CC3" }, @@ -2696,7 +4192,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x318Ec96df83AccC18B5EAD5D23e0F022F7Eb5503" }, @@ -2704,7 +4204,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xd6A6ba37fAaC229B9665E86739ca501401f5a940" }, @@ -2712,7 +4216,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x7Ce6bb2Cc2D3Fd45a974Da6a0F29236cb9513a98" }, @@ -2720,7 +4228,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x63dbE12A6381D64adE47bc3D92aBF4393DFF4BC8" }, @@ -2728,15 +4240,36 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x1AC2EE68b8d038C982C1E1f73F596927dd70De59" }, + "jovay-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "address": "0x6E6CBEF068fe546ceA52af587AEd8A2EfDD846bD", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "LINK", + "tokenAddress": "0x76a443768A5e3B8d1AED0105FC250877841Deb40" + }, "kaia-mainnet": { "allowListEnabled": false, "decimals": 0, "name": "", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "", "tokenAddress": "0x7311DED199CC28D80E58e81e8589aa160199FCD2" }, @@ -2744,7 +4277,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x6e970e8d6758164798290c8db1D79a527ca6e1B2" }, @@ -2752,7 +4289,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x71052BAe71C25C78E37fD12E5ff1101A71d9018F" }, @@ -2760,8 +4301,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0x1B7492C3bD23A4aDB448710e4275FF14A5288932", - "poolType": "lockRelease", + "pool": { + "address": "0x1B7492C3bD23A4aDB448710e4275FF14A5288932", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x514910771AF9Ca656af840dff83E8264EcF986CA" }, @@ -2769,23 +4314,43 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1" }, - "memento-mainnet": { + "megaeth-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", "poolType": "feeTokenOnly", "symbol": "LINK", + "tokenAddress": "0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae" + }, + "memento-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, + "symbol": "LINK", "tokenAddress": "0x76a443768A5e3B8d1AED0105FC250877841Deb40" }, "metal-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x587d19DDF735D6B536aAdB1a2A92938eB23B8d5C" }, @@ -2793,7 +4358,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xd8A9246e84903e82CA01e42774b01A7CdD465BFa" }, @@ -2801,7 +4370,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x71052BAe71C25C78E37fD12E5ff1101A71d9018F" }, @@ -2809,15 +4382,36 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x76f257B1DDA5cC71bee4eF637Fbdde4C801310A9" }, + "morph-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "address": "0x2E64625FF3b3c9d51A022B28d96935d920a2993A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, + "symbol": "LINK", + "tokenAddress": "0x76a443768A5e3B8d1AED0105FC250877841Deb40" + }, "nexon-mainnet-henesys": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x76a443768A5e3B8d1AED0105FC250877841Deb40" }, @@ -2825,8 +4419,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0x3fca88541D9bebe3600Ec03193FfC9D9c4d4Bb49", - "poolType": "burnMint", + "pool": { + "address": "0x3fca88541D9bebe3600Ec03193FfC9D9c4d4Bb49", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x76a443768A5e3B8d1AED0105FC250877841Deb40" }, @@ -2834,7 +4432,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xb549B375dA0c76f8b3877B9aDfDD28378f087A64" }, @@ -2842,8 +4444,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xDeC8A6f06FDdA5aAE262631f37b79f182a23464B", - "poolType": "burnMint", + "pool": { + "address": "0xDeC8A6f06FDdA5aAE262631f37b79f182a23464B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x31EFB841d5e0b4082F7E1267dab8De1b853f2A9d" }, @@ -2851,7 +4457,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xc2C447b04e0ED3476DdbDae8E9E39bE7159d27b6" }, @@ -2859,8 +4469,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0x6bBB2D614f4336784b835E392c62ed7A5345Db6e", - "poolType": "burnMint", + "pool": { + "address": "0x6bBB2D614f4336784b835E392c62ed7A5345Db6e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x3902228D6A3d2Dc44731fD9d45FeE6a61c722D0b" }, @@ -2868,7 +4482,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x938D84942f5D924070A6bb82F8e56a5E2b3098A4" }, @@ -2876,7 +4494,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x71052BAe71C25C78E37fD12E5ff1101A71d9018F" }, @@ -2884,7 +4506,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x71052BAe71C25C78E37fD12E5ff1101A71d9018F" }, @@ -2892,8 +4518,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Chainlink Token", - "poolAddress": "Gu68eAsbqHG8Jx6yLPWu3JDZEdCUzTFnrTCeRQKEy1br", - "poolType": "burnMint", + "pool": { + "address": "Gu68eAsbqHG8Jx6yLPWu3JDZEdCUzTFnrTCeRQKEy1br", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "LinkhB3afbBKb2EQQu7s7umdZceV3wcvAUJhQAfQ23L" }, @@ -2901,8 +4531,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xDeC8A6f06FDdA5aAE262631f37b79f182a23464B", - "poolType": "burnMint", + "pool": { + "address": "0xDeC8A6f06FDdA5aAE262631f37b79f182a23464B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x32D8F819C8080ae44375F8d383Ffd39FC642f3Ec" }, @@ -2910,16 +4544,37 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0x554652E7F10fB8aa3e12226213c6826F98B09CF0", - "poolType": "burnMint", + "pool": { + "address": "0x554652E7F10fB8aa3e12226213c6826F98B09CF0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x71052BAe71C25C78E37fD12E5ff1101A71d9018F" }, + "stable-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "address": "0x0dC94D4E45031f87b7df9e9B749dBB88f67Bcd78", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "LINK", + "tokenAddress": "0x985FB0821Eef0056ec26DD8b33dC61b9415B7F4b" + }, "superseed-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x41Ccf59e3F30EB624eF8E5Ea34b2da96bee472d9" }, @@ -2927,8 +4582,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0x819d06D62D7Fc29cFdafEc61bE44a8DB575D6102", - "poolType": "burnMint", + "pool": { + "address": "0x819d06D62D7Fc29cFdafEc61bE44a8DB575D6102", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xc2BE2F77562A6676098e8D363B9d8A33Ea009D4e" }, @@ -2936,8 +4595,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0xDeC8A6f06FDdA5aAE262631f37b79f182a23464B", - "poolType": "burnMint", + "pool": { + "address": "0xDeC8A6f06FDdA5aAE262631f37b79f182a23464B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x80f1FcdC96B55e459BF52b998aBBE2c364935d69" }, @@ -2945,7 +4608,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token on xDai", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xE2e73A1c69ecF83F464EFCE6A5be353a37cA09b2" }, @@ -2953,8 +4620,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolAddress": "0x414024b789097c9a81Ec2D34f95B009718f44365", - "poolType": "burnMint", + "pool": { + "address": "0x414024b789097c9a81Ec2D34f95B009718f44365", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xE27dd9BF01B55ce6803c0d81386A04212c718b95" }, @@ -2962,7 +4633,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x3662B6f73c5560229D1a98aF6e59E6649D568374" } @@ -2972,8 +4647,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Liquid Staked ETH", - "poolAddress": "0x3A4e3B9a4fb73A4015b4AFe1efe02214B614D591", - "poolType": "burnMint", + "pool": { + "address": "0x3A4e3B9a4fb73A4015b4AFe1efe02214B614D591", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LsETH", "tokenAddress": "0xB29749498954A3A821ec37BdE86e386dF3cE30B6" }, @@ -2981,8 +4660,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Liquid Staked ETH", - "poolAddress": "0xE939C02E92e9E66d1F0D8E4F099E7d3d269a8a11", - "poolType": "burnMint", + "pool": { + "address": "0xE939C02E92e9E66d1F0D8E4F099E7d3d269a8a11", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LsETH", "tokenAddress": "0xB29749498954A3A821ec37BdE86e386dF3cE30B6" }, @@ -2990,8 +4673,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Liquid Staked ETH", - "poolAddress": "0x0a02473E57902fD7764E6E952E2962763045B404", - "poolType": "lockRelease", + "pool": { + "address": "0x0a02473E57902fD7764E6E952E2962763045B404", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "LsETH", "tokenAddress": "0x8c1BEd5b9a0928467c9B1341Da1D7BD5e10b6549" } @@ -3001,8 +4688,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lumi Finance Token", - "poolAddress": "0xD27F88501e62D0BDc70B20d6ed06d8E0fF8c3812", - "poolType": "lockRelease", + "pool": { + "address": "0xD27F88501e62D0BDc70B20d6ed06d8E0fF8c3812", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "LUA", "tokenAddress": "0x88D100432F98956b16B66Df56962FD3e5cCd297A" }, @@ -3010,8 +4701,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lumi Finance Token", - "poolAddress": "0xCE562455a389F14f54135B84749ddd81Bc0bF869", - "poolType": "burnMint", + "pool": { + "address": "0xCE562455a389F14f54135B84749ddd81Bc0bF869", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LUA", "tokenAddress": "0xd61bBBB8369c46c15868ad9263a2710AcED156C4" } @@ -3021,8 +4716,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lumi Finance USD", - "poolAddress": "0x5686CCb55ee86BEB1e8A1Cf7C769930f3A5E521c", - "poolType": "lockRelease", + "pool": { + "address": "0x5686CCb55ee86BEB1e8A1Cf7C769930f3A5E521c", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "LUAUSD", "tokenAddress": "0x540ddE0739EeFAf90D0Ca05aCa90513Ce89E7e79" }, @@ -3030,8 +4729,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lumi Finance USD", - "poolAddress": "0xe6712A2b96780986342e2C3C0Accdce58fc7Ac38", - "poolType": "burnMint", + "pool": { + "address": "0xe6712A2b96780986342e2C3C0Accdce58fc7Ac38", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LUAUSD", "tokenAddress": "0x18d2bDEf572C67127E218c425f546FE64430a92C" } @@ -3041,8 +4744,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Luisa", - "poolAddress": "0xe9516fB95778682F48C551071Bb917F937229596", - "poolType": "burnMint", + "pool": { + "address": "0xe9516fB95778682F48C551071Bb917F937229596", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LUISA", "tokenAddress": "0x5699c51660C765e57793D1837B400B241cbC4B46" }, @@ -3050,8 +4757,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Luisa", - "poolAddress": "0xCa8FaCd0EB11DEB6114d515D136c79C6f4170E87", - "poolType": "lockRelease", + "pool": { + "address": "0xCa8FaCd0EB11DEB6114d515D136c79C6f4170E87", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "LUISA", "tokenAddress": "0x0cCD687CC6F8461170336D8e8cf46A39313DEab9" } @@ -3061,8 +4772,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lympid Token", - "poolAddress": "0xBCc91222266156c9e92217Bf68117fF3d8Ec5f38", - "poolType": "burnMint", + "pool": { + "address": "0xBCc91222266156c9e92217Bf68117fF3d8Ec5f38", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "LYP", "tokenAddress": "0x4837b18a6d7aF6159c8665505B90a2ed393255E0" }, @@ -3070,8 +4785,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lympid Token", - "poolAddress": "0xba0Db2166508A030324F14dEBE3a6D9d3B8A32c8", - "poolType": "burnMint", + "pool": { + "address": "0xba0Db2166508A030324F14dEBE3a6D9d3B8A32c8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "LYP", "tokenAddress": "0x4837b18a6d7aF6159c8665505B90a2ed393255E0" } @@ -3081,8 +4800,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Bridged Magpie-Peg BTC", - "poolAddress": "0xD7550e0a1C055B444D8d1a9EB3DeA02c0F09D7A1", - "poolType": "burnMint", + "pool": { + "address": "0xD7550e0a1C055B444D8d1a9EB3DeA02c0F09D7A1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "Bridged mBTC", "tokenAddress": "0x7c1cCA5b25Fa0bC9AF9275Fb53cBA89DC172b878" }, @@ -3090,8 +4813,12 @@ "allowListEnabled": false, "decimals": 8, "name": "mBTC", - "poolAddress": "0x82164603B46a79C0DDcF2E622e242f16428939DB", - "poolType": "burnMint", + "pool": { + "address": "0x82164603B46a79C0DDcF2E622e242f16428939DB", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "mBTC", "tokenAddress": "0x2172fAD929E857dDfD7dDC31E24904438434cB0B" }, @@ -3099,8 +4826,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Liquid Staked BTC", - "poolAddress": "0xd86e1fEDB7120369fF5175b74F4413Cb74FCAcDB", - "poolType": "burnMint", + "pool": { + "address": "0xd86e1fEDB7120369fF5175b74F4413Cb74FCAcDB", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "mBTC", "tokenAddress": "0x7FdFbE1fB9783745991CFb0a3D396acE6eE0c909" }, @@ -3108,8 +4839,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Liquid Staked BTC", - "poolAddress": "0x476EefeF46e0d65e1E371Fe093696259B1240B93", - "poolType": "burnMint", + "pool": { + "address": "0x476EefeF46e0d65e1E371Fe093696259B1240B93", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "mBTC", "tokenAddress": "0xbDf245957992bfBC62B07e344128a1EEc7b7eE3f" }, @@ -3117,8 +4852,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Magpie Stake BTC", - "poolAddress": "0xa6F5410BCb028c62DB6f60361C004D9740cFA82b", - "poolType": "burnMint", + "pool": { + "address": "0xa6F5410BCb028c62DB6f60361C004D9740cFA82b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "mBTC", "tokenAddress": "0x29190A076072bd71454E032F821eAAb3ba07e0D3" } @@ -3128,8 +4867,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Magpie locked DLP", - "poolAddress": "0x3fd1D7fc5fE44fCbEE3d506530b790b09EF1459B", - "poolType": "burnMint", + "pool": { + "address": "0x3fd1D7fc5fE44fCbEE3d506530b790b09EF1459B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "mDLP", "tokenAddress": "0xfe14F790DA92971131544d915c4ADa6F1abce3Bd" }, @@ -3137,8 +4880,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Magpie locked DLP", - "poolAddress": "0x5180865890246278544ea457342b46665C196a97", - "poolType": "burnMint", + "pool": { + "address": "0x5180865890246278544ea457342b46665C196a97", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "mDLP", "tokenAddress": "0x1Cbc4BF664907669CfAB86a3b1aCC3EC8867a25F" } @@ -3148,8 +4895,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Cryptex Meme Index", - "poolAddress": "0x797C54f6E028c70d76c0031e03ab43Eb1b80fa74", - "poolType": "burnMint", + "pool": { + "address": "0x797C54f6E028c70d76c0031e03ab43Eb1b80fa74", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "MEEM", "tokenAddress": "0x15f9cec1c568352Cd48Da1E84D3e74F27f6ee160" }, @@ -3157,8 +4908,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Cryptex Meme Index", - "poolAddress": "0xbfc86CA9b7fa158287bD392eE098246465E63351", - "poolType": "lockRelease", + "pool": { + "address": "0xbfc86CA9b7fa158287bD392eE098246465E63351", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "MEEM", "tokenAddress": "0xA544b3F0c46c15F0B2b00ba3D67b56C250287905" } @@ -3168,8 +4923,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DEXTF Token", - "poolAddress": "0x114c782B4d351fdd7b8323716DAc7bB556Cc354A", - "poolType": "burnMint", + "pool": { + "address": "0x6c9E5fD0FDB36AaF3293Fcc1fb43D9581F706bf7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "DEXTF", "tokenAddress": "0x4816B2157203D8D4c53918e8d4076Adfe9e2FE22" }, @@ -3177,8 +4936,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Memento", - "poolAddress": "0x05286231783494D61B1C253E1BC68E4782B41604", - "poolType": "burnMint", + "pool": { + "address": "0x1c20Db242C0d8EE2cb36480211B9629a00B1e42f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "DEXTF", "tokenAddress": "0xB69bBB15095C0949489FBB43951d2b750Fa7fA89" }, @@ -3186,8 +4949,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DEXTF Token", - "poolAddress": "0x0549475Ff447CBC0CfF51CB0719E0AA2dAF4eDC8", - "poolType": "lockRelease", + "pool": { + "address": "0x40fa6991CDbd66e91a25a2875d4d6fb1aF88cD91", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "DEXTF", "tokenAddress": "0x5F64Ab1544D28732F0A24F4713c2C8ec0dA089f0" }, @@ -3195,8 +4962,12 @@ "allowListEnabled": false, "decimals": 18, "name": "DEXTF Token", - "poolAddress": "0x6CCF71Db1CAeF39F58f388D8c34d8A49927d73A9", - "poolType": "burnMint", + "pool": { + "address": "0x1c20Db242C0d8EE2cb36480211B9629a00B1e42f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "DEXTF", "tokenAddress": "0x5C5C6D078A6458179a2E4837Db25dA4a9330ECD4" } @@ -3206,8 +4977,12 @@ "allowListEnabled": false, "decimals": 18, "name": "MEMEX", - "poolAddress": "0xD0bFBE2f17599607AB58def61b9A30CCFF4a0505", - "poolType": "burnMint", + "pool": { + "address": "0xD0bFBE2f17599607AB58def61b9A30CCFF4a0505", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "MEMEX", "tokenAddress": "0x5e7E82B875b09e7A491611B626d90D7748d166d8" }, @@ -3215,8 +4990,12 @@ "allowListEnabled": false, "decimals": 18, "name": "MEMEX", - "poolAddress": "0x21EfedF48D33f09d948fB98dED7dE766b682F049", - "poolType": "burnMint", + "pool": { + "address": "0x21EfedF48D33f09d948fB98dED7dE766b682F049", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "MEMEX", "tokenAddress": "0xd6effD9911797742435EF3d5880545129934aBbe" } @@ -3226,8 +5005,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Metafluence", - "poolAddress": "0xC9eDf4f727A1C21b65613f29059FE9928244110b", - "poolType": "burnMint", + "pool": { + "address": "0xC9eDf4f727A1C21b65613f29059FE9928244110b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "METO", "tokenAddress": "0xa78775bba7a542F291e5ef7f13C6204E704A90Ba" }, @@ -3235,8 +5018,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Metafluence", - "poolAddress": "0x78a2AeDdb8fD3446Fda31F6451a7e11c6446F5B8", - "poolType": "burnMint", + "pool": { + "address": "0x78a2AeDdb8fD3446Fda31F6451a7e11c6446F5B8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "METO", "tokenAddress": "0x4665d6c8882F0fB1b973776C63578f9AF1A0A726" } @@ -3246,8 +5033,12 @@ "allowListEnabled": false, "decimals": 5, "name": "cat in a dogs world", - "poolAddress": "0xBF38331E34ef7f248020611bB31Be0576D06413D", - "poolType": "burnMint", + "pool": { + "address": "0xBF38331E34ef7f248020611bB31Be0576D06413D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "MEW", "tokenAddress": "0x1b3CF4C6ad50788291160cD10bFEFafC5e4e951C" }, @@ -3255,8 +5046,12 @@ "allowListEnabled": false, "decimals": 5, "name": "cat in a dogs world", - "poolAddress": "0xBF38331E34ef7f248020611bB31Be0576D06413D", - "poolType": "burnMint", + "pool": { + "address": "0xBF38331E34ef7f248020611bB31Be0576D06413D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "MEW", "tokenAddress": "0xE49FB237974E29AE8022347Ed14084669D70875B" }, @@ -3264,8 +5059,12 @@ "allowListEnabled": false, "decimals": 5, "name": "cat in a dogs world", - "poolAddress": "0xaf0b8f79b667055Db3a54a31144e86e841Be3dAD", - "poolType": "burnMint", + "pool": { + "address": "0xaf0b8f79b667055Db3a54a31144e86e841Be3dAD", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "MEW", "tokenAddress": "0xE49FB237974E29AE8022347Ed14084669D70875B" }, @@ -3273,8 +5072,12 @@ "allowListEnabled": false, "decimals": 5, "name": "cat in a dogs world", - "poolAddress": "BomBbNZ1jgmCin3xzhCwMe1j3ewV3DoRAKAuEy6bJ4Px", - "poolType": "lockRelease", + "pool": { + "address": "BomBbNZ1jgmCin3xzhCwMe1j3ewV3DoRAKAuEy6bJ4Px", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "MEW", "tokenAddress": "MEW1gQWJ3nEXg2qgERiKu7FAFj79PHvQVREQUzScPP5" }, @@ -3282,8 +5085,12 @@ "allowListEnabled": false, "decimals": 5, "name": "cat in a dogs world", - "poolAddress": "0x15C03488B29e27d62BAf10E30b0c474bf60E0264", - "poolType": "burnMint", + "pool": { + "address": "0x15C03488B29e27d62BAf10E30b0c474bf60E0264", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "MEW", "tokenAddress": "0xE49FB237974E29AE8022347Ed14084669D70875B" } @@ -3293,8 +5100,12 @@ "allowListEnabled": false, "decimals": 6, "name": "michi", - "poolAddress": "0x65615642056b48BCB8120C109f7e7c0c3623A8BF", - "poolType": "burnMint", + "pool": { + "address": "0x65615642056b48BCB8120C109f7e7c0c3623A8BF", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "michi", "tokenAddress": "0x18a4d375323DFAB49862aCeb1A4c6E65F8e53F67" }, @@ -3302,8 +5113,12 @@ "allowListEnabled": false, "decimals": 6, "name": "michi", - "poolAddress": "ATyY7SaiayLnp3teH3c4jRBGiPinSSZyt2gHNNN9C6BV", - "poolType": "lockRelease", + "pool": { + "address": "ATyY7SaiayLnp3teH3c4jRBGiPinSSZyt2gHNNN9C6BV", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "$michi", "tokenAddress": "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp" } @@ -3313,8 +5128,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Milo", - "poolAddress": "0xb1F9dBF3bdc2575F338ac218fDb903E1AF8e88Fb", - "poolType": "lockRelease", + "pool": { + "address": "0xb1F9dBF3bdc2575F338ac218fDb903E1AF8e88Fb", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "MILO", "tokenAddress": "0x8FfC46A1b7a3b12F4A11Db8877d302876DCA7Ab1" }, @@ -3322,8 +5141,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Milo", - "poolAddress": "0xdD66A2a06D1201C6aA84A89248887831Fe625922", - "poolType": "burnMint", + "pool": { + "address": "0xdD66A2a06D1201C6aA84A89248887831Fe625922", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "MILO", "tokenAddress": "0xe22fe63E20c3D817121022316B2430b5A516a6CE" } @@ -3333,8 +5156,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Bridged mmETH", - "poolAddress": "0x2D1d3F65449dd3F36548bBBBD8E9f3C089d30374", - "poolType": "burnMint", + "pool": { + "address": "0x2D1d3F65449dd3F36548bBBBD8E9f3C089d30374", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "Bridged mmETH", "tokenAddress": "0x5d84E0f246E629E6AB29252ecBD9ab20e89aC845" }, @@ -3342,8 +5169,12 @@ "allowListEnabled": false, "decimals": 18, "name": "mmETH", - "poolAddress": "0xa27501561B01D99cde347a63891e8762DCa5bBbd", - "poolType": "lockRelease", + "pool": { + "address": "0xa27501561B01D99cde347a63891e8762DCa5bBbd", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "mmETH", "tokenAddress": "0x8a053350ca5F9352a16deD26ab333e2D251DAd7c" } @@ -3353,8 +5184,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Bridged mstETH", - "poolAddress": "0xf1f89d5127Ce97a3e839993CCC77781AA7DA90bA", - "poolType": "burnMint", + "pool": { + "address": "0xf1f89d5127Ce97a3e839993CCC77781AA7DA90bA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "Bridged mstETH", "tokenAddress": "0xE367d4b1b9bB40e34aDCE448e1edb0141Fc6a8AC" }, @@ -3362,8 +5197,12 @@ "allowListEnabled": false, "decimals": 18, "name": "mstETH", - "poolAddress": "0x2E3c68D6d2eDD9881429f0565B88024B5Db10F73", - "poolType": "lockRelease", + "pool": { + "address": "0x2E3c68D6d2eDD9881429f0565B88024B5Db10F73", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "mstETH", "tokenAddress": "0x49446A0874197839D15395B908328a74ccc96Bc0" }, @@ -3371,8 +5210,12 @@ "allowListEnabled": false, "decimals": 18, "name": "mstETH", - "poolAddress": "0x7361B97025e2207178EDB9BA59c61BDA69E032fa", - "poolType": "burnMint", + "pool": { + "address": "0x7361B97025e2207178EDB9BA59c61BDA69E032fa", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "mstETH", "tokenAddress": "0x11d525Fb3f8CDfa58bE0d0FaB9339964Aeb89deb" } @@ -3382,8 +5225,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Bridged mswETH", - "poolAddress": "0x5D83430652F8B799F24Dae05B1B9916eB2D089b7", - "poolType": "burnMint", + "pool": { + "address": "0x5D83430652F8B799F24Dae05B1B9916eB2D089b7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "Bridged mswETH", "tokenAddress": "0xAbf9F7200D5337e50BF85748B7e780032BC5838e" }, @@ -3391,8 +5238,12 @@ "allowListEnabled": false, "decimals": 18, "name": "mswETH", - "poolAddress": "0xBDCc99f05D73FB3C2ad4b0F496318BaAE20218b7", - "poolType": "lockRelease", + "pool": { + "address": "0xBDCc99f05D73FB3C2ad4b0F496318BaAE20218b7", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "mswETH", "tokenAddress": "0x32bd822d615A3658A68b6fDD30c2fcb2C996D678" } @@ -3402,8 +5253,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Metaverse Index", - "poolAddress": "0xa970d6B0002CDfd4Ca12f0c4F13315dB612DDB5c", - "poolType": "burnMint", + "pool": { + "address": "0xa970d6B0002CDfd4Ca12f0c4F13315dB612DDB5c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "MVI", "tokenAddress": "0x0104a6FA30540DC1d9F45D2797F05eEa79304525" }, @@ -3411,8 +5266,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Metaverse Index", - "poolAddress": "0xA688993b1195aA6e64f4F835415c854a2C83BC21", - "poolType": "burnMint", + "pool": { + "address": "0xA688993b1195aA6e64f4F835415c854a2C83BC21", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "MVI", "tokenAddress": "0xEA8954dE7607b90F5ec81A5e2e673D0f60BB7596" }, @@ -3420,8 +5279,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Metaverse Index", - "poolAddress": "0x6A888F0f25d2e846ec854d6Fb011BeC6DE31480B", - "poolType": "lockRelease", + "pool": { + "address": "0x6A888F0f25d2e846ec854d6Fb011BeC6DE31480B", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "MVI", "tokenAddress": "0x72e364F2ABdC788b7E918bc238B21f109Cd634D7" } @@ -3431,8 +5294,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Bridged mwBETH", - "poolAddress": "0xF975EafE68839F326012f8AEc8759455B5e0050A", - "poolType": "burnMint", + "pool": { + "address": "0xF975EafE68839F326012f8AEc8759455B5e0050A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "Bridged mwBETH", "tokenAddress": "0x7dC91cBD6CB5A3E6A95EED713Aa6bF1d987146c8" }, @@ -3440,8 +5307,12 @@ "allowListEnabled": false, "decimals": 18, "name": "mwBETH", - "poolAddress": "0xa7689C57aa6D09d28244d3932F34176d853A660f", - "poolType": "lockRelease", + "pool": { + "address": "0xa7689C57aa6D09d28244d3932F34176d853A660f", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "mwBETH", "tokenAddress": "0xE46a5E19B19711332e33F33c2DB3eA143e86Bc10" } @@ -3451,8 +5322,12 @@ "allowListEnabled": false, "decimals": 18, "name": "MyStandard", - "poolAddress": "0xA4D5EF72fCFfa9eac0907856B1db1b68098fA23a", - "poolType": "burnMint", + "pool": { + "address": "0xA4D5EF72fCFfa9eac0907856B1db1b68098fA23a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "MYST", "tokenAddress": "0x0256B279D973C8d687264AC3eB36bE09232D4474" }, @@ -3460,8 +5335,12 @@ "allowListEnabled": false, "decimals": 18, "name": "MyStandard", - "poolAddress": "0x717C753F9EA66eb763466cf3F8d299C634889B29", - "poolType": "burnMint", + "pool": { + "address": "0x717C753F9EA66eb763466cf3F8d299C634889B29", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "MYST", "tokenAddress": "0xA821aDaCCf08d856c0A36DC2C136B5188c525967" }, @@ -3469,8 +5348,12 @@ "allowListEnabled": false, "decimals": 18, "name": "MyStandard", - "poolAddress": "0xe1A8223DAc2aeC3090322674F054D35C240Dc37f", - "poolType": "burnMint", + "pool": { + "address": "0xe1A8223DAc2aeC3090322674F054D35C240Dc37f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "MYST", "tokenAddress": "0x3d5F61a4BB385B6D1eB34F47aA790A996f1Eba65" } @@ -3480,8 +5363,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Neiro", - "poolAddress": "0x8f43e6A0E48c860946bbDeea28F1eE710FdCf6d4", - "poolType": "burnMint", + "pool": { + "address": "0x8f43e6A0E48c860946bbDeea28F1eE710FdCf6d4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "NEIRO", "tokenAddress": "0x1d192a2f367DaF23540fFEAbF8dBe9B17803F00A" }, @@ -3489,8 +5376,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Neiro", - "poolAddress": "0x47158771e67e4bDdaFd0FBD36f26Db929420B26C", - "poolType": "lockRelease", + "pool": { + "address": "0x47158771e67e4bDdaFd0FBD36f26Db929420B26C", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "NEIRO", "tokenAddress": "0xEE2a03Aa6Dacf51C18679C516ad5283d8E7C2637" } @@ -3500,8 +5391,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Neko", - "poolAddress": "0x6a9A43871a8D468ACF6309f8459bC9623a0F169c", - "poolType": "burnMint", + "pool": { + "address": "0x6a9A43871a8D468ACF6309f8459bC9623a0F169c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "NEKO", "tokenAddress": "0xdb2aa3cDda310AE4e648E0FcE5cb6c19a37a9aD8" }, @@ -3509,8 +5404,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Neko", - "poolAddress": "0xDcE9cf770345584f2DFAA2eA23625cF3eDd6B7cF", - "poolType": "lockRelease", + "pool": { + "address": "0xDcE9cf770345584f2DFAA2eA23625cF3eDd6B7cF", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "NEKO", "tokenAddress": "0x63A67329f761517570345eE86f791F74f9DC5461" } @@ -3520,8 +5419,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Non-Playable Coin", - "poolAddress": "0xe185299D35f5f346ab0e42476B4172A0d020Aad9", - "poolType": "burnMint", + "pool": { + "address": "0xe185299D35f5f346ab0e42476B4172A0d020Aad9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "NPC", "tokenAddress": "0x765DaF34f09CFb86A7d172e016513B6c6355b13d" }, @@ -3529,8 +5432,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Non-Playable Coin", - "poolAddress": "0xF4208675b84E678d0d01528fA97634e2B0873Fa6", - "poolType": "lockRelease", + "pool": { + "address": "0xF4208675b84E678d0d01528fA97634e2B0873Fa6", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "NPC", "tokenAddress": "0x8eD97a637A790Be1feff5e888d43629dc05408F6" } @@ -3540,8 +5447,12 @@ "allowListEnabled": false, "decimals": 18, "name": "NUON", - "poolAddress": "0x7a1d89A602c98936b5b484c2DB42ec77E1E5743C", - "poolType": "lockRelease", + "pool": { + "address": "0x7a1d89A602c98936b5b484c2DB42ec77E1E5743C", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "NUON", "tokenAddress": "0xfb9Fed8cB962548A11fE7F6F282949061395c7F5" }, @@ -3549,8 +5460,12 @@ "allowListEnabled": false, "decimals": 18, "name": "NUON", - "poolAddress": "0xeE9Ea9B65475EE7693e0Ec9B9c308cA2d536e7ea", - "poolType": "burnMint", + "pool": { + "address": "0xeE9Ea9B65475EE7693e0Ec9B9c308cA2d536e7ea", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "NUON", "tokenAddress": "0xCA160D11087E03fd398d40f561cd4768825f4958" }, @@ -3558,8 +5473,12 @@ "allowListEnabled": false, "decimals": 18, "name": "NUON", - "poolAddress": "0xc1D8f275f651E1CAe3A6D971d0836cDAcD25d91a", - "poolType": "burnMint", + "pool": { + "address": "0xc1D8f275f651E1CAe3A6D971d0836cDAcD25d91a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "NUON", "tokenAddress": "0xCA160D11087E03fd398d40f561cd4768825f4958" } @@ -3569,8 +5488,12 @@ "allowListEnabled": false, "decimals": 18, "name": "NXPC", - "poolAddress": "0x0D9A14a6eD561770295BcCCF1995ae5B026a65d6", - "poolType": "lockRelease", + "pool": { + "address": "0x0D9A14a6eD561770295BcCCF1995ae5B026a65d6", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "NXPC", "tokenAddress": "0x5E0E90E268BC247Cc850c789A0DB0d5c7621fb59" }, @@ -3578,17 +5501,34 @@ "allowListEnabled": false, "decimals": 18, "name": "Nexpace", - "poolAddress": "0xEB8a99EDdFA50375E58033c187A4b65EC3c6B40C", - "poolType": "burnMint", + "pool": { + "address": "0xEB8a99EDdFA50375E58033c187A4b65EC3c6B40C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "NXPC", "tokenAddress": "0x9f2c4FD0a0BFF91723089775C73394E72c0fC116" }, + "monad-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "NXPC", + "poolAddress": "0xc1E3A199873846AAfcFE71D31e3D82c8B97588D9", + "poolType": "burnMint", + "symbol": "NXPC", + "tokenAddress": "0xD33F18D8d48CbbB2f8b47063DE97f94De0D49B99" + }, "ronin-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Nexpace", - "poolAddress": "0x6f9234e7ffdC4Fda751f13269a6584582B9F3C8d", - "poolType": "burnMint", + "pool": { + "address": "0x6f9234e7ffdC4Fda751f13269a6584582B9F3C8d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "NXPC", "tokenAddress": "0x1B601A055711FeE5Ea965bC2AE341e2e4a79D622" } @@ -3598,8 +5538,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Olympus", - "poolAddress": "0xa5588e518CE5ee0e4628C005E4edAbD5e87de3aD", - "poolType": "lockRelease", + "pool": { + "address": "0xa5588e518CE5ee0e4628C005E4edAbD5e87de3aD", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "OHM", "tokenAddress": "0x64aa3364F17a4D01c6f1751Fd97C2BD3D7e7f1D5" }, @@ -3607,8 +5551,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Olympus", - "poolAddress": "4N7bZnVSC1GE27vo2Bv6kG983brwhT68BGsLuzH5nTQp", - "poolType": "burnMint", + "pool": { + "address": "4N7bZnVSC1GE27vo2Bv6kG983brwhT68BGsLuzH5nTQp", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "OHM", "tokenAddress": "2Xva1NeLRuBFdK41gEuXqgeWtnKKDve9PKeCnMEpNG6K" } @@ -3618,8 +5566,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Orange", - "poolAddress": "0x42DFf772b40Eeb42B4DdEd4BB7Fe8ad9212821De", - "poolType": "lockRelease", + "pool": { + "address": "0x42DFf772b40Eeb42B4DdEd4BB7Fe8ad9212821De", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "ORNG", "tokenAddress": "0x6c14c1898C843FF66cA51e87244690bBc28DF215" }, @@ -3627,8 +5579,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Orange", - "poolAddress": "0x5aDc61883D1aEEfF77DF019A119b8528741fed1e", - "poolType": "burnMint", + "pool": { + "address": "0x5aDc61883D1aEEfF77DF019A119b8528741fed1e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "ORNG", "tokenAddress": "0xA588041eA7285e8ab47cfBCC8871Ab338f672147" } @@ -3638,8 +5594,12 @@ "allowListEnabled": false, "decimals": 18, "name": "OSIS Token", - "poolAddress": "0x475c8Fb7F7D4d3bba0b0a4da2bE31328fc36E358", - "poolType": "burnMint", + "pool": { + "address": "0x475c8Fb7F7D4d3bba0b0a4da2bE31328fc36E358", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "OSIS", "tokenAddress": "0x45fcf0Ebb7d79E3de9Fc308b6c7cb680A981CB7a" }, @@ -3647,8 +5607,12 @@ "allowListEnabled": false, "decimals": 18, "name": "OSIS", - "poolAddress": "0xCCb9Ce82667b8ca0178E281340F469787096Ba14", - "poolType": "lockRelease", + "pool": { + "address": "0xCCb9Ce82667b8ca0178E281340F469787096Ba14", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "OSIS", "tokenAddress": "0x3e5351935595600D8e094dEE3Ec7E942CAf9907F" } @@ -3658,8 +5622,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Overtime DAO Token", - "poolAddress": "0xccEDD35627336F20b86a96D81EB88A75908D67e9", - "poolType": "burnMint", + "pool": { + "address": "0xccEDD35627336F20b86a96D81EB88A75908D67e9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "OVER", "tokenAddress": "0x5829D6FE7528bc8E92c4e81CC8F20a528820B51a" }, @@ -3667,8 +5635,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Overtime DAO Token", - "poolAddress": "0xAd897dd53328D86282A3A822C15201d669201AA8", - "poolType": "burnMint", + "pool": { + "address": "0xAd897dd53328D86282A3A822C15201d669201AA8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "OVER", "tokenAddress": "0x7750C092e284e2c7366f50C8306F43c7EB2e82a2" }, @@ -3676,8 +5648,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Overtime DAO Token", - "poolAddress": "0x5c5E86ABC6cfE3772dc2aAe4FAffEEFd641fd460", - "poolType": "burnMint", + "pool": { + "address": "0x5c5E86ABC6cfE3772dc2aAe4FAffEEFd641fd460", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "OVER", "tokenAddress": "0xedF38688b27036816A50185cAA430D5479e1C63e" }, @@ -3685,8 +5661,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Overtime DAO Token", - "poolAddress": "0x9054f2DF5f2AC59b39a175c27a00165989D17d2B", - "poolType": "lockRelease", + "pool": { + "address": "0x9054f2DF5f2AC59b39a175c27a00165989D17d2B", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "OVER", "tokenAddress": "0x90cE5720c17587D28E4Af120ae2d313B3BAD1722" } @@ -3696,8 +5676,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenXAUT", - "poolAddress": "0x18e25Ac83477d7013D43174508B7AE7EC2CE2e08", - "poolType": "burnMint", + "pool": { + "address": "0x18e25Ac83477d7013D43174508B7AE7EC2CE2e08", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "oXAUT", "tokenAddress": "0x30974f73A4ac9E606Ed80da928e454977ac486D2" }, @@ -3705,8 +5689,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenXAUT", - "poolAddress": "0xaF35bef911A5e0be90987cE5070d7c9CbF5cFd3c", - "poolType": "burnMint", + "pool": { + "address": "0xaF35bef911A5e0be90987cE5070d7c9CbF5cFd3c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "oXAUT", "tokenAddress": "0x30974f73A4ac9E606Ed80da928e454977ac486D2" }, @@ -3714,8 +5702,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenXAUT", - "poolAddress": "0xF8AE5209DE22dbd06Dace938934b0D75B5E80299", - "poolType": "burnMint", + "pool": { + "address": "0xF8AE5209DE22dbd06Dace938934b0D75B5E80299", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "oXAUT", "tokenAddress": "0x30974f73A4ac9E606Ed80da928e454977ac486D2" }, @@ -3723,8 +5715,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Tether Gold", - "poolAddress": "0x04db9b1D7f52cB288b95B4934a1fA688F6d0cBc3", - "poolType": "burnMint", + "pool": { + "address": "0x04db9b1D7f52cB288b95B4934a1fA688F6d0cBc3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "XAUt", "tokenAddress": "0x68749665FF8D2d112Fa859AA293F07A622782F38" } @@ -3734,7 +5730,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Pegged Bitcoin", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "pBTC", "tokenAddress": "0x0D2437F93Fed6EA64Ef01cCde385FB1263910C56" } @@ -3744,8 +5744,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Pepe", - "poolAddress": "0xe48D935e6C9e735463ccCf29a7F11e32bC09136E", - "poolType": "lockRelease", + "pool": { + "address": "0xe48D935e6C9e735463ccCf29a7F11e32bC09136E", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "PEPE", "tokenAddress": "0x6982508145454Ce325dDbE47a25d4ec3d2311933" }, @@ -3753,8 +5757,12 @@ "allowListEnabled": false, "decimals": 4, "name": "Pepe", - "poolAddress": "4gqQkUyXrfUuRbviWNPeSWUhqko9Q7KX6axMjE3g9Ma3", - "poolType": "burnMint", + "pool": { + "address": "4gqQkUyXrfUuRbviWNPeSWUhqko9Q7KX6axMjE3g9Ma3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "PEPE", "tokenAddress": "8NPXRWxUD7xKcexDpK1aC5MTckRykvGya8rzgK8cbQcX" } @@ -3764,8 +5772,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Puffverse Token", - "poolAddress": "0x337Dec2C7D98CdC0f59976F3A48aCd706cC6c495", - "poolType": "burnMint", + "pool": { + "address": "0x337Dec2C7D98CdC0f59976F3A48aCd706cC6c495", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "PFVS", "tokenAddress": "0x3157874A7508FCF972379D24590C6806522B784F" }, @@ -3773,19 +5785,55 @@ "allowListEnabled": false, "decimals": 18, "name": "Puffverse Token", - "poolAddress": "0x50Dbf7140A444DB0ACFb6d1bcc12408C6485Fe27", - "poolType": "lockRelease", + "pool": { + "address": "0x50Dbf7140A444DB0ACFb6d1bcc12408C6485Fe27", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "PFVS", "tokenAddress": "0xb4562fDEFD5eD58f7705CE9386D54EE9B53831d1" } }, + "pippin": { + "ethereum-mainnet-base-1": { + "allowListEnabled": false, + "decimals": 6, + "name": "Pippin", + "pool": { + "address": "0x5Efb8F091d49ce1e138353c75d4AAd07a98D79A5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "pippin", + "tokenAddress": "0x3945Eaaf908d6c743090D4ca1748c057d8A5634a" + }, + "solana-mainnet": { + "allowListEnabled": false, + "decimals": 6, + "name": "Pippin", + "pool": { + "address": "GFZDNxdQFFoPok1ZX1uwzbbfFNB46kJGNnAa1rd7LUVF", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, + "symbol": "pippin", + "tokenAddress": "Dfh5DzRgSvvCFDoYc2ciTkMrbDfRKybA4SoFbPmApump" + } + }, "PIXEL": { "mainnet": { "allowListEnabled": false, "decimals": 18, "name": "PIXEL", - "poolAddress": "0xe26D9c68cF6d284367C5e90EC834C6Ec0051f73C", - "poolType": "lockRelease", + "pool": { + "address": "0xe26D9c68cF6d284367C5e90EC834C6Ec0051f73C", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "PIXEL", "tokenAddress": "0x3429d03c6F7521AeC737a0BBF2E5ddcef2C3Ae31" }, @@ -3793,19 +5841,124 @@ "allowListEnabled": false, "decimals": 18, "name": "PIXEL", - "poolAddress": "0xd7CE1E7262ce471CC3Db3Bcd8c3EdeEe6d114115", - "poolType": "burnMint", + "pool": { + "address": "0xd7CE1E7262ce471CC3Db3Bcd8c3EdeEe6d114115", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "PIXEL", "tokenAddress": "0x7EAe20d11Ef8c779433Eb24503dEf900b9d28ad7" } }, + "POWER": { + "bsc-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Power", + "poolAddress": "0x7EeeAd4571b12BC3e331E6Ce2D954E1528aC2921", + "poolType": "burnMint", + "symbol": "POWER", + "tokenAddress": "0x9dC44ae5BE187ECA9e2A67e33f27A4c91cEA1223" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Power", + "poolAddress": "0x7EeeAd4571b12BC3e331E6Ce2D954E1528aC2921", + "poolType": "lockRelease", + "symbol": "POWER", + "tokenAddress": "0x9dC44ae5BE187ECA9e2A67e33f27A4c91cEA1223" + }, + "ronin-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Power", + "poolAddress": "0x9B0B4aFf23aC0e144BCb947aD99Bde308dea5641", + "poolType": "burnMint", + "symbol": "POWER", + "tokenAddress": "0x394cEF8bDd737EE24DBc9f43d0d5D2ab83136054" + } + }, + "PTjrUSDe": { + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "PT Strata Junior USDe 2APR2026", + "poolAddress": "0x2d2a804E10B0CA29e3246F438b1223393AB3EDf8", + "poolType": "lockRelease", + "symbol": "PT-jrUSDe-2APR2026", + "tokenAddress": "0xd0609Ac13000d88B0BEbf5Bb21074916eDd92Bb1" + }, + "solana-mainnet": { + "allowListEnabled": false, + "decimals": 9, + "name": "ETH PT jrUSDe (USDe) 2026Apr", + "poolAddress": "3T6Bok68RDHJdQNN3ebrTj4vxaPqjxM148c7JJj8Fawc", + "poolType": "burnMint", + "symbol": "PTjrUSDe", + "tokenAddress": "PTjrYm3qif3qo3tsoqmr41TVCZyhBvkgukcDB2Qk8dd" + } + }, + "PTsrUSDe": { + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "PT Strata Senior USDe 2APR2026", + "poolAddress": "0x33D5E3e9964772A054Ad79B605B7eCc95EBc96c6", + "poolType": "lockRelease", + "symbol": "PT-srUSDe-2APR2026", + "tokenAddress": "0x9Bf45ab47747F4B4dD09B3C2c73953484b4eB375" + }, + "solana-mainnet": { + "allowListEnabled": false, + "decimals": 9, + "name": "ETH PT srUSDe (USDe) 2026Apr", + "poolAddress": "2ESptT6YLTCK19vAZ3DQnC9UhGChy58wfaPkW4WuApWa", + "poolType": "burnMint", + "symbol": "PTsrUSDe", + "tokenAddress": "PTsrBnshSkHwufaak5p2jRR5Jgf4dTp3N7Mx1sdV1hv" + } + }, + "PTsUSDE": { + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "PT Ethena sUSDE 5FEB2026", + "pool": { + "address": "0x04790065826123136eB50d9dF1276f98376a6e91", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, + "symbol": "PT-sUSDE-5FEB2026", + "tokenAddress": "0xE8483517077afa11A9B07f849cee2552f040d7b2" + }, + "solana-mainnet": { + "allowListEnabled": false, + "decimals": 9, + "name": "ETH PT sUSDe (USDe) 2026Feb", + "pool": { + "address": "R78LZoZJCfG5dTxPT9bAc6DCgvYQ32Gp8hVrkbjGiF1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, + "symbol": "PTsUSDE", + "tokenAddress": "PTSg1sXMujX5bgTM88C2PMksHG5w2bqvXJrG9uUdzpA" + } + }, "pufETH": { "berachain-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "pufETH", - "poolAddress": "0x8dA0baE597aC15fB0924713b1e3c1F624474F3E4", - "poolType": "burnMint", + "pool": { + "address": "0x8dA0baE597aC15fB0924713b1e3c1F624474F3E4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "pufETH", "tokenAddress": "0x417b0Ff8358Eb72867Da92225CaB99BCD5e6F205" }, @@ -3813,8 +5966,12 @@ "allowListEnabled": false, "decimals": 18, "name": "pufETH", - "poolAddress": "0x87d00066cf131ff54B72B134a217D5401E5392b6", - "poolType": "burnMint", + "pool": { + "address": "0x87d00066cf131ff54B72B134a217D5401E5392b6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "pufETH", "tokenAddress": "0x37D6382B6889cCeF8d6871A8b60E667115eDDBcF" }, @@ -3822,8 +5979,12 @@ "allowListEnabled": false, "decimals": 18, "name": "pufETH", - "poolAddress": "0xBc1324F4FaB8e63bF33E5117bb887671B378BFF3", - "poolType": "lockRelease", + "pool": { + "address": "0xBc1324F4FaB8e63bF33E5117bb887671B378BFF3", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "pufETH", "tokenAddress": "0xD9A442856C234a39a81a089C06451EBAa4306a72" }, @@ -3831,19 +5992,85 @@ "allowListEnabled": false, "decimals": 18, "name": "pufETH", - "poolAddress": "0xF9Dd335bF363b2E4ecFe3c94A86EBD7Dd3Dcf0e7", - "poolType": "burnMint", + "pool": { + "address": "0xF9Dd335bF363b2E4ecFe3c94A86EBD7Dd3Dcf0e7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "pufETH", "tokenAddress": "0x6c460b2c6D6719562D5dA43E5152B375e79B9A8B" } }, + "QUICK": { + "ethereum-mainnet-base-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "QuickSwap", + "poolAddress": "0xf7C2DbFF4dFEc28eaf52CAAc8FdA22FbA19199ce", + "poolType": "lockRelease", + "symbol": "QUICK", + "tokenAddress": "0x7094c27f342DBAdfbbeD005b219431595E33b305" + }, + "matic-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "QuickSwap", + "poolAddress": "0x8D89611841D3389711ea3c74538f953F8dffA427", + "poolType": "lockRelease", + "symbol": "QUICK", + "tokenAddress": "0xB5C064F955D8e7F38fE0460C556a72987494eE17" + } + }, + "RAIN": { + "bsc-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Rain Coin", + "poolAddress": "0xa71433A266dB0B15cF127dE74B3Fa33Cbe730526", + "poolType": "burnMint", + "symbol": "RAIN", + "tokenAddress": "0x24b1C3f935DfFcADb606920022BA8C703BB065D7" + }, + "ethereum-mainnet-base-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "Rain Coin", + "poolAddress": "0xDca466bE13e06659CfED0f0467c370FCAbE46F32", + "poolType": "burnMint", + "symbol": "RAIN", + "tokenAddress": "0x4E21eABf4fC4cF66f10a93395E4B0e2438de81a6" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Rain Coin", + "poolAddress": "0x390735D3b3C3805F71644154e5Fba82E0e542e76", + "poolType": "burnMint", + "symbol": "RAIN", + "tokenAddress": "0x59DB93D135F16585ED90b8C942d4f8AE0DcFBFc0" + }, + "matic-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped Rain Coin", + "poolAddress": "0x3D9C216B971C82B95106ec98F6ade87F6a56915C", + "poolType": "lockRelease", + "symbol": "wRAIN", + "tokenAddress": "0x2b72C03feAf5f6B624Db83974054848C9dF2c8e7" + } + }, "RDP": { "bsc-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Radpie", - "poolAddress": "0x879d0803Dc3fB6b435E6407F4b74101bB8f742C8", - "poolType": "burnMint", + "pool": { + "address": "0x879d0803Dc3fB6b435E6407F4b74101bB8f742C8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "RDP", "tokenAddress": "0x27c073e8427aa493a90b8dC8b73A89e670FD77bB" }, @@ -3851,8 +6078,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Radpie", - "poolAddress": "0x3be3266713DeBDeb1CdC420a88f1E9EefB7982e2", - "poolType": "burnMint", + "pool": { + "address": "0x3be3266713DeBDeb1CdC420a88f1E9EefB7982e2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "RDP", "tokenAddress": "0x54BDBF3cE36f451Ec61493236b8E6213ac87c0f6" } @@ -3862,8 +6093,12 @@ "allowListEnabled": false, "decimals": 18, "name": "RealToken Ecosystem Governance", - "poolAddress": "0x307D0353313F544fc8Da0D85F1005b1de516Bce8", - "poolType": "burnMint", + "pool": { + "address": "0x307D0353313F544fc8Da0D85F1005b1de516Bce8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "REG", "tokenAddress": "0x0AA1e96D2a46Ec6beB2923dE1E61Addf5F5f1dce" }, @@ -3871,8 +6106,12 @@ "allowListEnabled": false, "decimals": 18, "name": "RealToken Ecosystem Governance", - "poolAddress": "0xe61d70B29F6a83A50Acff39e8b8AC6B27F6e6ddA", - "poolType": "burnMint", + "pool": { + "address": "0xe61d70B29F6a83A50Acff39e8b8AC6B27F6e6ddA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "REG", "tokenAddress": "0x0AA1e96D2a46Ec6beB2923dE1E61Addf5F5f1dce" }, @@ -3880,8 +6119,12 @@ "allowListEnabled": false, "decimals": 18, "name": "RealToken Ecosystem Governance", - "poolAddress": "0x8058d5d465C8CA6BA76De043A7637F8Df74a0989", - "poolType": "burnMint", + "pool": { + "address": "0x8058d5d465C8CA6BA76De043A7637F8Df74a0989", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "REG", "tokenAddress": "0x0AA1e96D2a46Ec6beB2923dE1E61Addf5F5f1dce" } @@ -3891,8 +6134,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Rocket Pool ETH", - "poolAddress": "0x3A2Ea8BaE01410425d01c2C5f488e4777DAA54Df", - "poolType": "lockRelease", + "pool": { + "address": "0x3A2Ea8BaE01410425d01c2C5f488e4777DAA54Df", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "rETH", "tokenAddress": "0xae78736Cd615f374D3085123A210448E74Fc6393" }, @@ -3900,8 +6147,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Rocket Pool ETH", - "poolAddress": "0xABC0F3b9455E308C27C2a6fe0EF82A596c95709F", - "poolType": "burnMint", + "pool": { + "address": "0xABC0F3b9455E308C27C2a6fe0EF82A596c95709F", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "rETH", "tokenAddress": "0xC61a178d9742775f3B741fE60F12659D853c66A1" }, @@ -3909,8 +6160,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Rocket Pool ETH", - "poolAddress": "0xCd4Ee1110707D79704d6881A4fEf158e5FdB334b", - "poolType": "burnMint", + "pool": { + "address": "0xCd4Ee1110707D79704d6881A4fEf158e5FdB334b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "RETH", "tokenAddress": "0x29c46e6F2A67872Ad6b1Dc04e1591934a96Af62E" }, @@ -3918,8 +6173,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Rocket Pool ETH", - "poolAddress": "0xbf22058C8cd5a9fd426aa5176424d41027F14545", - "poolType": "burnMint", + "pool": { + "address": "0xbf22058C8cd5a9fd426aa5176424d41027F14545", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "rETH", "tokenAddress": "0x6e5e9b22E461c2F9786e6d8069d47adA1Ef58aDc" } @@ -3929,8 +6188,12 @@ "allowListEnabled": false, "decimals": 18, "name": "RIZE", - "poolAddress": "0xf234609b2e2704b48745A819C89774Fe21E4a722", - "poolType": "burnMint", + "pool": { + "address": "0xf234609b2e2704b48745A819C89774Fe21E4a722", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "RIZE", "tokenAddress": "0xAEDAff046601BEb063b647845Dfb21841f32d6A4" }, @@ -3938,8 +6201,12 @@ "allowListEnabled": false, "decimals": 18, "name": "RIZE", - "poolAddress": "0xd4D129Df31bF9d9eF7fF030aDF984f3d028E16a0", - "poolType": "burnMint", + "pool": { + "address": "0xd4D129Df31bF9d9eF7fF030aDF984f3d028E16a0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "RIZE", "tokenAddress": "0x9818B6c09f5ECc843060927E8587c427C7C93583" }, @@ -3947,8 +6214,12 @@ "allowListEnabled": false, "decimals": 18, "name": "RIZE", - "poolAddress": "0x17Be5d735D49c84919d3cFDfF9eABbdB12D6Ac20", - "poolType": "burnMint", + "pool": { + "address": "0x17Be5d735D49c84919d3cFDfF9eABbdB12D6Ac20", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "RIZE", "tokenAddress": "0x9F1E8F87c6321b84baD7DDa7DfB86D5115A47605" }, @@ -3956,8 +6227,12 @@ "allowListEnabled": false, "decimals": 18, "name": "RIZE", - "poolAddress": "0xAEDAff046601BEb063b647845Dfb21841f32d6A4", - "poolType": "burnMint", + "pool": { + "address": "0xAEDAff046601BEb063b647845Dfb21841f32d6A4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "RIZE", "tokenAddress": "0x9F1E8F87c6321b84baD7DDa7DfB86D5115A47605" } @@ -3967,8 +6242,12 @@ "allowListEnabled": false, "decimals": 18, "name": "rsETH", - "poolAddress": "0x72a7ffbd763c369d5A86eEe886ABb99BdA613f8A", - "poolType": "burnMint", + "pool": { + "address": "0x72a7ffbd763c369d5A86eEe886ABb99BdA613f8A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "rsETH", "tokenAddress": "0xb999Ea589E0a1Cce9153601daC2D6e203c2fD577" }, @@ -3976,8 +6255,12 @@ "allowListEnabled": false, "decimals": 18, "name": "rsETH", - "poolAddress": "0xc28A1F91e6D0eCf6cBFe6809D256a7753fae52B5", - "poolType": "burnMint", + "pool": { + "address": "0xc28A1F91e6D0eCf6cBFe6809D256a7753fae52B5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "rsETH", "tokenAddress": "0x043849686EE254ada46A432770E1a491491FC44D" }, @@ -3985,8 +6268,12 @@ "allowListEnabled": false, "decimals": 18, "name": "rsETH", - "poolAddress": "0x5bdB8499D400Fb19afc665D1CE0C5459bB3401Eb", - "poolType": "burnMint", + "pool": { + "address": "0x5bdB8499D400Fb19afc665D1CE0C5459bB3401Eb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "rsETH", "tokenAddress": "0x571405D597091e8728d8240F558BAc01275E8659" }, @@ -3994,8 +6281,12 @@ "allowListEnabled": false, "decimals": 18, "name": "rsETH", - "poolAddress": "0x55e5a21B4cCC7FA502434ab1109D4EDe0397AB25", - "poolType": "lockRelease", + "pool": { + "address": "0x55e5a21B4cCC7FA502434ab1109D4EDe0397AB25", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "rsETH", "tokenAddress": "0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7" } @@ -4005,8 +6296,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ShibArmyStrong", - "poolAddress": "0xd13129ee86f6285d51F66196A02a929E2be977a4", - "poolType": "burnMint", + "pool": { + "address": "0xd13129ee86f6285d51F66196A02a929E2be977a4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SAS", "tokenAddress": "0x28BE7E8cD8125CB7A74D2002A5862E1bfd774cd9" }, @@ -4014,8 +6309,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ShibArmyStrong", - "poolAddress": "0xd13129ee86f6285d51F66196A02a929E2be977a4", - "poolType": "burnMint", + "pool": { + "address": "0xd13129ee86f6285d51F66196A02a929E2be977a4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SAS", "tokenAddress": "0x28BE7E8cD8125CB7A74D2002A5862E1bfd774cd9" }, @@ -4023,8 +6322,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ShibArmyStrong", - "poolAddress": "0x89F39cdbad48b6531DDBd38ea0D84E9c9CbCdA27", - "poolType": "lockRelease", + "pool": { + "address": "0x89F39cdbad48b6531DDBd38ea0D84E9c9CbCdA27", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "SAS", "tokenAddress": "0x28BE7E8cD8125CB7A74D2002A5862E1bfd774cd9" }, @@ -4032,8 +6335,12 @@ "allowListEnabled": false, "decimals": 18, "name": "ShibArmyStrong", - "poolAddress": "0xab8B05d4d7d31b28d9973C5CD2965b9e48a2a35d", - "poolType": "burnMint", + "pool": { + "address": "0xab8B05d4d7d31b28d9973C5CD2965b9e48a2a35d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SAS", "tokenAddress": "0x7E315C269F7849F80824755A666DC6fb4Ba8BEe1" } @@ -4043,8 +6350,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avBTC", - "poolAddress": "0x9E3021Cedd853C63cBa44e8a351ea807fd116e7C", - "poolType": "lockRelease", + "pool": { + "address": "0x9E3021Cedd853C63cBa44e8a351ea807fd116e7C", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "savBTC", "tokenAddress": "0x649342c6bff544d82DF1B2bA3C93e0C22cDeBa84" }, @@ -4052,8 +6363,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avBTC", - "poolAddress": "0x79A42a8dC09F3501DC265e65139912aE20c5BCeb", - "poolType": "burnMint", + "pool": { + "address": "0x79A42a8dC09F3501DC265e65139912aE20c5BCeb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "savBTC", "tokenAddress": "0x19452d507b2738aDB8942cD2b0d52BB519f1790a" }, @@ -4061,8 +6376,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avBTC", - "poolAddress": "0x5b0B44bB38E23193111e7AA03E380Ba841e58B17", - "poolType": "burnMint", + "pool": { + "address": "0x5b0B44bB38E23193111e7AA03E380Ba841e58B17", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "savBTC", "tokenAddress": "0x45cF31aF4d67899674B50ab14093b55006fFf563" }, @@ -4070,8 +6389,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avBTC", - "poolAddress": "0x78991cd8ADDf98672A1201D70c6db46e21C25C57", - "poolType": "burnMint", + "pool": { + "address": "0x78991cd8ADDf98672A1201D70c6db46e21C25C57", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "savBTC", "tokenAddress": "0x92181c6f0FED1f1A30c0Ec131f41577F81924bf5" } @@ -4081,8 +6404,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avETH", - "poolAddress": "0xd039ac36B5082ee285471968b88f468e42E27Fa0", - "poolType": "burnMint", + "pool": { + "address": "0xd039ac36B5082ee285471968b88f468e42E27Fa0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "savETH", "tokenAddress": "0x260c0c715A279F239cF44e2F73E964AB550738f3" }, @@ -4090,8 +6417,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avETH", - "poolAddress": "0x10CBdedfD636C777977d621D344791A288528fF0", - "poolType": "burnMint", + "pool": { + "address": "0x10CBdedfD636C777977d621D344791A288528fF0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "savETH", "tokenAddress": "0xA0Fbf835fd24bD1aAFD39a0D4b1779B5B8329770" }, @@ -4099,8 +6430,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avETH", - "poolAddress": "0x43f47a434DADd5A122C42E49378365CcA949fA54", - "poolType": "lockRelease", + "pool": { + "address": "0x43f47a434DADd5A122C42E49378365CcA949fA54", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "savETH", "tokenAddress": "0xDA06eE2dACF9245Aa80072a4407deBDea0D7e341" } @@ -4110,35 +6445,69 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avUSD", - "poolAddress": "0x8FcC42c414E29e8e3dBFa1628CF45E8ed80C999D", - "poolType": "lockRelease", + "pool": { + "address": "0x8FcC42c414E29e8e3dBFa1628CF45E8ed80C999D", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "savUSD", "tokenAddress": "0x06d47F3fb376649c3A9Dafe069B3D6E35572219E" }, - "bsc-mainnet": { + "berachain-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Staked avUSD", - "poolAddress": "0x8e4eC56B2E74bD48557F327Ea35F6f08b7E8a4bd", + "poolAddress": "0x59E2a16B388999D0d258e52623aC97F8841c37d2", "poolType": "burnMint", "symbol": "savUSD", + "tokenAddress": "0xa744Fe3688291aC3A4a7eC917678783aD9946a1E" + }, + "bsc-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Staked avUSD", + "pool": { + "address": "0x8e4eC56B2E74bD48557F327Ea35F6f08b7E8a4bd", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "savUSD", "tokenAddress": "0x14063733875204b35D20D5Fc52C7B5569aD00335" }, - "ethereum-mainnet-linea-1": { + "ethereum-mainnet-arbitrum-1": { "allowListEnabled": false, "decimals": 18, "name": "Staked avUSD", - "poolAddress": "0xDd10449dEAF27fc4937DDA64d0b5Af819b79EE63", + "poolAddress": "0xC164b8232ca67D2f8dDA43CF75CbE8161E6861D8", "poolType": "burnMint", "symbol": "savUSD", + "tokenAddress": "0xA322e23a357cB7C596A7a834102B9d6d5b15da3e" + }, + "ethereum-mainnet-linea-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "Staked avUSD", + "pool": { + "address": "0xDd10449dEAF27fc4937DDA64d0b5Af819b79EE63", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "savUSD", "tokenAddress": "0x5C247948fD58Bb02B6c4678d9940F5e6B9af1127" }, "mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Staked avUSD", - "poolAddress": "0x6d3B65eB14ad3546ab4Aa32cf8645a3610a9737b", - "poolType": "burnMint", + "pool": { + "address": "0x6d3B65eB14ad3546ab4Aa32cf8645a3610a9737b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "savUSD", "tokenAddress": "0xb8D89678E75a973E74698c976716308abB8a46A4" }, @@ -4146,8 +6515,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avUSD", - "poolAddress": "0xFCCfA86d9AEdD2fF8dF60600110d6D1649679Fef", - "poolType": "burnMint", + "pool": { + "address": "0xFCCfA86d9AEdD2fF8dF60600110d6D1649679Fef", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "savUSD", "tokenAddress": "0xA29420057F3e3B9512D4786df135Da1674BD74D4" }, @@ -4155,8 +6528,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked avUSD", - "poolAddress": "0x8d2145dB5Da67B262aEb451D16b07B1a958124eC", - "poolType": "burnMint", + "pool": { + "address": "0x8d2145dB5Da67B262aEb451D16b07B1a958124eC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "savUSD", "tokenAddress": "0xb9827268eBCc4EA7b105cfC787A92c612629A3f1" } @@ -4166,8 +6543,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stader", - "poolAddress": "0x1AEfE4c18198C5838e22951C9382cD3080052407", - "poolType": "burnMint", + "pool": { + "address": "0x1AEfE4c18198C5838e22951C9382cD3080052407", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SD", "tokenAddress": "0x9445F4081AFC7Fa66b53224DCb84aC6e6A1714A2" }, @@ -4175,8 +6556,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stader", - "poolAddress": "0x98BBA66d65Dd48bAD447b73db8181930c02c794D", - "poolType": "burnMint", + "pool": { + "address": "0x98BBA66d65Dd48bAD447b73db8181930c02c794D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SD", "tokenAddress": "0x32E94BB4A3521EBEBE14AE3Aa5Bc09fCc9E42306" }, @@ -4184,8 +6569,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stader", - "poolAddress": "0x61D405818C8127f0fD30102BF01E6227097eF92f", - "poolType": "lockRelease", + "pool": { + "address": "0x61D405818C8127f0fD30102BF01E6227097eF92f", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "SD", "tokenAddress": "0x30D20208d987713f46DFD34EF128Bb16C404D10f" } @@ -4195,8 +6584,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Mode Savings Dai", - "poolAddress": "0x0e3229079543F047a394833063702E71F733F6a5", - "poolType": "burnMint", + "pool": { + "address": "0x0e3229079543F047a394833063702E71F733F6a5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "msDAI", "tokenAddress": "0x3f51c6c5927B88CDEc4b61e2787F9BD0f5249138" }, @@ -4204,37 +6597,53 @@ "allowListEnabled": false, "decimals": 18, "name": "Savings Dai", - "poolAddress": "0xF6c88f0933126c2e2CDb060910165aA4BfC11B99", - "poolType": "lockRelease", + "pool": { + "address": "0xF6c88f0933126c2e2CDb060910165aA4BfC11B99", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "sDAI", "tokenAddress": "0x83F20F44975D03b1b09e64809B757c47f942BEeA" } }, "SDL": { - "ethereum-mainnet-andromeda-1": { + "ethereum-mainnet-arbitrum-1": { "allowListEnabled": false, "decimals": 18, "name": "stake.link", - "poolAddress": "0xC31A8B3Ba209FC60c3E9364649ED452939403E27", - "poolType": "burnMint", + "pool": { + "address": "0xC31A8B3Ba209FC60c3E9364649ED452939403E27", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SDL", - "tokenAddress": "0xd7cf0e0fC12fB97e03841CE4f3086dB327CE0F2B" + "tokenAddress": "0xdFeA35757264F5b6C0ff21104151D9F991D0eEC0" }, - "ethereum-mainnet-arbitrum-1": { + "ethereum-mainnet-base-1": { "allowListEnabled": false, "decimals": 18, "name": "stake.link", - "poolAddress": "0xb473be8A2b4778C418451C18F4357261D626f91C", - "poolType": "burnMint", + "pool": { + "address": "0xb473be8A2b4778C418451C18F4357261D626f91C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SDL", - "tokenAddress": "0xdFeA35757264F5b6C0ff21104151D9F991D0eEC0" + "tokenAddress": "0xe5B64a705db9d2395C471af1608972cCbacE26E6" }, "mainnet": { "allowListEnabled": false, "decimals": 18, "name": "stake.link", - "poolAddress": "0xAFcC997D86713FeC802Cc665122d64a5130bDd1D", - "poolType": "lockRelease", + "pool": { + "address": "0xAFcC997D86713FeC802Cc665122d64a5130bDd1D", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "SDL", "tokenAddress": "0xA95C5ebB86E0dE73B4fB8c47A45B792CFeA28C23" } @@ -4244,8 +6653,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Diamondz Shadow Game + Movies", - "poolAddress": "0x97831d9E9896B941d1047ECE33031C1eF19fB9A5", - "poolType": "burnMint", + "pool": { + "address": "0x97831d9E9896B941d1047ECE33031C1eF19fB9A5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SDM", "tokenAddress": "0x602b869eEf1C9F0487F31776bad8Af3C4A173394" }, @@ -4253,8 +6666,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Diamondz Shadow Game + Movies", - "poolAddress": "0xBC3cc3F1122a664dc3C650C0A8138Ca2731b9431", - "poolType": "burnMint", + "pool": { + "address": "0xBC3cc3F1122a664dc3C650C0A8138Ca2731b9431", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SDM", "tokenAddress": "0xDd5C53Fa95741B3B896BaC689bd460C29a4F7034" } @@ -4264,8 +6681,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked DOLA", - "poolAddress": "0x8Bbd036d018657E454F679E7C4726F7a8ECE2773", - "poolType": "burnMint", + "pool": { + "address": "0x8Bbd036d018657E454F679E7C4726F7a8ECE2773", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "sDOLA", "tokenAddress": "0x02eaa69646183c069FC2B64F15923F27B9CF3b03" }, @@ -4273,8 +6694,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked DOLA", - "poolAddress": "0xbbc28DB61DF26B76D5F7D5Eed17eD4D6C278460e", - "poolType": "burnMint", + "pool": { + "address": "0xbbc28DB61DF26B76D5F7D5Eed17eD4D6C278460e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "sDOLA", "tokenAddress": "0x7a1e123e41458aabaB8068BFed6010D8f9480898" }, @@ -4282,8 +6707,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked DOLA", - "poolAddress": "0xd84e1B7e1a7A8D49167884855c3985ef4bCa45aB", - "poolType": "burnMint", + "pool": { + "address": "0xd84e1B7e1a7A8D49167884855c3985ef4bCa45aB", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "sDOLA", "tokenAddress": "0xCa78ee4544ec5a33Af86F1E786EfC7d3652bf005" }, @@ -4291,8 +6720,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked DOLA", - "poolAddress": "0x8404024d8F74Ad2D20E82c184816B64D4184A018", - "poolType": "burnMint", + "pool": { + "address": "0x8404024d8F74Ad2D20E82c184816B64D4184A018", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "sDOLA", "tokenAddress": "0xfc63C9c8Ba44AE89C01265453Ed4F427C80cBd4E" }, @@ -4300,8 +6733,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked Dola", - "poolAddress": "0x05eEe76f456C51Be0459EC1c0a78bf177B2c877C", - "poolType": "lockRelease", + "pool": { + "address": "0x05eEe76f456C51Be0459EC1c0a78bf177B2c877C", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "sDOLA", "tokenAddress": "0xb45ad160634c528Cc3D2926d9807104FA3157305" } @@ -4311,8 +6748,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stake DAO Token", - "poolAddress": "0xB1133f3A7bC0392948f4Bb43947b9BB662fB8E20", - "poolType": "burnMint", + "pool": { + "address": "0xB1133f3A7bC0392948f4Bb43947b9BB662fB8E20", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SDT", "tokenAddress": "0x07715EE7219B07b8e01CC7d2787f4e5e75860383" }, @@ -4320,8 +6761,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stake DAO Token", - "poolAddress": "0x4AFdDee00D68ebA82B882db98015bfD816818093", - "poolType": "burnMint", + "pool": { + "address": "0x4AFdDee00D68ebA82B882db98015bfD816818093", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SDT", "tokenAddress": "0x07715EE7219B07b8e01CC7d2787f4e5e75860383" }, @@ -4329,8 +6774,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stake DAO Token", - "poolAddress": "0x89c9038906887A69bD9C20f81B1B4C309F9A6D04", - "poolType": "lockRelease", + "pool": { + "address": "0x89c9038906887A69bD9C20f81B1B4C309F9A6D04", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "SDT", "tokenAddress": "0x73968b9a57c6E53d41345FD57a6E6ae27d6CDB2F" } @@ -4340,8 +6789,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Steadefi", - "poolAddress": "0x2910769511bA734895B127b9564A2b56cd7a4B02", - "poolType": "burnMint", + "pool": { + "address": "0x2910769511bA734895B127b9564A2b56cd7a4B02", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SDY", "tokenAddress": "0x338c6d2DF4dB2459EAB0835fd9004Cf2915842e0" }, @@ -4349,8 +6802,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Steadefi", - "poolAddress": "0x53606d47E92e390B2B4B105e92bAC238CC77F28c", - "poolType": "burnMint", + "pool": { + "address": "0x53606d47E92e390B2B4B105e92bAC238CC77F28c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SDY", "tokenAddress": "0x7d262214f368A896Af42E36F20a97E2d83df701b" }, @@ -4358,8 +6815,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Steadefi", - "poolAddress": "0xC4ABCd324ED49B98795CC8F51C80DAF1A24F5F58", - "poolType": "burnMint", + "pool": { + "address": "0xC4ABCd324ED49B98795CC8F51C80DAF1A24F5F58", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SDY", "tokenAddress": "0xf2DbAaBd8F8E0993F11DE4CEd470Df1ED1a4491b" } @@ -4369,8 +6830,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x6f6F5645B86b1fD3c4C015822a0E672132D4e2F8", - "poolType": "burnMint", + "pool": { + "address": "0x6f6F5645B86b1fD3c4C015822a0E672132D4e2F8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SHIB", "tokenAddress": "0x2f643d728926C20269f0A04931dd7b4b6B650204" }, @@ -4378,8 +6843,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x7f1f90E6b6BAD9fc14ca71224B072541B739beb3", - "poolType": "burnMint", + "pool": { + "address": "0x7f1f90E6b6BAD9fc14ca71224B072541B739beb3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIB", "tokenAddress": "0xEc59dE82FFf1959E92b91daB975e4564FC3447cC" }, @@ -4387,8 +6856,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x346368422407aCaF48025ff18891b1D7540539Bf", - "poolType": "burnMint", + "pool": { + "address": "0x346368422407aCaF48025ff18891b1D7540539Bf", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIB", "tokenAddress": "0xf5607d767CCa3789CAe872A33E3cfb76cFbaaaA2" }, @@ -4396,8 +6869,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x48A148B6EFAD4D59225034f1A243cea734e67bB0", - "poolType": "burnMint", + "pool": { + "address": "0x48A148B6EFAD4D59225034f1A243cea734e67bB0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIB", "tokenAddress": "0x7C87cc813Ce92D384c437C263E9FB2E7F945188E" }, @@ -4405,8 +6882,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x6f93AD7963BBdD8C655A0C819B9b79347EE04b70", - "poolType": "burnMint", + "pool": { + "address": "0x6f93AD7963BBdD8C655A0C819B9b79347EE04b70", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SHIB", "tokenAddress": "0xB359155378FF5E2837f12ed0bee5168123c88ACC" }, @@ -4414,8 +6895,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0xC026ae03C857093979872C665b13dBBA83B55987", - "poolType": "burnMint", + "pool": { + "address": "0xC026ae03C857093979872C665b13dBBA83B55987", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SHIB", "tokenAddress": "0x9Ded28d9EC69F97efd718CE768dc39D78fd014F8" }, @@ -4423,8 +6908,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x2bc58Bf0705f24200c19cF4248E4580d03C44EB8", - "poolType": "burnMint", + "pool": { + "address": "0x2bc58Bf0705f24200c19cF4248E4580d03C44EB8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SHIB", "tokenAddress": "0x3b4F8E846437c7CacE31080E6c9DFC455C1DBE77" }, @@ -4432,8 +6921,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x98A6F5ae745934ba25FF67B1e59C502b97ff1Cc3", - "poolType": "burnMint", + "pool": { + "address": "0x98A6F5ae745934ba25FF67B1e59C502b97ff1Cc3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIB", "tokenAddress": "0xC52F506591eb89c04620D47B895d5f951efAd4b4" }, @@ -4441,8 +6934,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x70f30536699c7180C53Ae9e7f64c06c5E7164960", - "poolType": "burnMint", + "pool": { + "address": "0x70f30536699c7180C53Ae9e7f64c06c5E7164960", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIB", "tokenAddress": "0x4d8E5D0c79B02A37074025B4C10854df01f33a3F" }, @@ -4450,8 +6947,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x13C4D04ED1Cba19391bD8E9F8F13B261340F474d", - "poolType": "burnMint", + "pool": { + "address": "0x13C4D04ED1Cba19391bD8E9F8F13B261340F474d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIB", "tokenAddress": "0x1bA642B2f27E45d730ff20714B17309644274167" }, @@ -4459,8 +6960,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x7c8d25EF1cE7A5d342A3889DE9BB59939d67DFf8", - "poolType": "burnMint", + "pool": { + "address": "0x7c8d25EF1cE7A5d342A3889DE9BB59939d67DFf8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIB", "tokenAddress": "0x72cc27124EA2d36AC13D502C7EBdF28cEF90c31c" }, @@ -4468,8 +6973,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0xf1B85dEC561bfe9fC61BD758e533B85a7108634e", - "poolType": "burnMint", + "pool": { + "address": "0xf1B85dEC561bfe9fC61BD758e533B85a7108634e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SHIB", "tokenAddress": "0x6F7408DAc37a36cD35B5c3Bc2829f60C30E83315" }, @@ -4477,8 +6986,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0xf8678aC9b6b0d6ff9243F88060f595d4771a5E04", - "poolType": "burnMint", + "pool": { + "address": "0xf8678aC9b6b0d6ff9243F88060f595d4771a5E04", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SHIB", "tokenAddress": "0x3D83b2253a523a211cF5679Fea1D10A58b408177" }, @@ -4486,8 +6999,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x8f3829fCB1cD380746F1643Bfaf6aC8CA9960426", - "poolType": "burnMint", + "pool": { + "address": "0x8f3829fCB1cD380746F1643Bfaf6aC8CA9960426", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SHIB", "tokenAddress": "0x1f88af31101d9eAFBe5B9Dd627beb4b3010b8c54" }, @@ -4495,8 +7012,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x3eC718a22B268d7d9Ce27D2dcAB791174D515920", - "poolType": "lockRelease", + "pool": { + "address": "0x3eC718a22B268d7d9Ce27D2dcAB791174D515920", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "SHIB", "tokenAddress": "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE" }, @@ -4504,8 +7025,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x4f36762E13b6df9e717BfC82EB750a5d86393553", - "poolType": "burnMint", + "pool": { + "address": "0x4f36762E13b6df9e717BfC82EB750a5d86393553", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIB", "tokenAddress": "0x7627D9C9b045A26672D57741C896B2A48844168D" }, @@ -4513,8 +7038,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x4Ba40931F99188af67262109FBaB2A39de8D82BA", - "poolType": "burnMint", + "pool": { + "address": "0x4Ba40931F99188af67262109FBaB2A39de8D82BA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIB", "tokenAddress": "0xf7bd92DcAad1E095f4f1f454eBEa99C2a96429e9" }, @@ -4522,8 +7051,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x0CBA02AC9C24Fe7b38123976c85Fe03Bbf4C5081", - "poolType": "burnMint", + "pool": { + "address": "0x0CBA02AC9C24Fe7b38123976c85Fe03Bbf4C5081", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SHIB", "tokenAddress": "0x13c24A28F2b1EEF8A657f661396545683D74e9e0" }, @@ -4531,8 +7064,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SHIBA INU", - "poolAddress": "0x25679A2879F6abb919c2dda665ce929D9A5214A8", - "poolType": "burnMint", + "pool": { + "address": "0x25679A2879F6abb919c2dda665ce929D9A5214A8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SHIB", "tokenAddress": "0xAE2e513aC868D27Bf8d697d165bB2e91C1AEA0F0" } @@ -4542,8 +7079,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Shipa", - "poolAddress": "0x54169D9660C21A83C68eb7AEd04AE87ff1b69D5c", - "poolType": "burnMint", + "pool": { + "address": "0x54169D9660C21A83C68eb7AEd04AE87ff1b69D5c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SHIPA", "tokenAddress": "0x74B017277BFFC58BE2D4d61097A69d584dcaF32F" }, @@ -4551,8 +7092,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Shipa", - "poolAddress": "0x67A3B613b2398b43E0B12DD6a07B30cDaCB6A61d", - "poolType": "lockRelease", + "pool": { + "address": "0x67A3B613b2398b43E0B12DD6a07B30cDaCB6A61d", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "SHIPA", "tokenAddress": "0x632d1FF1fB27d88EDeDB90e70bFC094D7932A0ad" } @@ -4562,8 +7107,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Shiro Neko", - "poolAddress": "0x8fd996312CA11849A562C78885021148F25a9841", - "poolType": "lockRelease", + "pool": { + "address": "0x8fd996312CA11849A562C78885021148F25a9841", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "SHIRO", "tokenAddress": "0xb0AC2b5a73da0e67A8e5489Ba922B3f8d582e058" }, @@ -4571,8 +7120,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Shiro Neko", - "poolAddress": "0x26a90cEeFfDfe7CD30913108C99872130c7FEE38", - "poolType": "burnMint", + "pool": { + "address": "0x26a90cEeFfDfe7CD30913108C99872130c7FEE38", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SHIRO", "tokenAddress": "0x15DD0588Dc6C75783B28905d416aE24fa234Fb60" } @@ -4582,8 +7135,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Silo Token", - "poolAddress": "0x3Fa5329dB787ac51D61DcaB9a588ceA106ad593C", - "poolType": "burnMint", + "pool": { + "address": "0x3Fa5329dB787ac51D61DcaB9a588ceA106ad593C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SILO", "tokenAddress": "0x77EEe23630deC10e96C5A8F731A9cF46FCC8CD6f" }, @@ -4591,8 +7148,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Silo Token", - "poolAddress": "0x76A82571FC85817CEEeDff3Bf71bE3c076668A14", - "poolType": "burnMint", + "pool": { + "address": "0x76A82571FC85817CEEeDff3Bf71bE3c076668A14", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SILO", "tokenAddress": "0x09f569AF991c730Cae05a392bae6490558eF2214" }, @@ -4600,8 +7161,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Silo Token", - "poolAddress": "0x95842Bb96cECfe77e8AC07BA6e6bA948B745CCCd", - "poolType": "lockRelease", + "pool": { + "address": "0x95842Bb96cECfe77e8AC07BA6e6bA948B745CCCd", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "SILO", "tokenAddress": "0xF0B2dd79324A66d2108C961d680F7616E1486bB0" }, @@ -4609,8 +7174,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Silo Token", - "poolAddress": "0x527a8902DB7548353EAf08b6522686509e32B1FE", - "poolType": "burnMint", + "pool": { + "address": "0x527a8902DB7548353EAf08b6522686509e32B1FE", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SILO", "tokenAddress": "0xb098AFC30FCE67f1926e735Db6fDadFE433E61db" } @@ -4620,8 +7189,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked Inv", - "poolAddress": "0xaCDD3f0a2bC4e61ae5cd2b96BF87CCC04aa15DCc", - "poolType": "burnMint", + "pool": { + "address": "0xaCDD3f0a2bC4e61ae5cd2b96BF87CCC04aa15DCc", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "sINV", "tokenAddress": "0x4C7b266B4bf0A8758fa85E69292eE55c212236cF" }, @@ -4629,8 +7202,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked Inv", - "poolAddress": "0xE8E17C4E16EDE9ED62580b48bf784b71197279b8", - "poolType": "burnMint", + "pool": { + "address": "0xE8E17C4E16EDE9ED62580b48bf784b71197279b8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "sINV", "tokenAddress": "0x8Bbd036d018657E454F679E7C4726F7a8ECE2773" }, @@ -4638,8 +7215,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked Inv", - "poolAddress": "0x57500aB5b2b6B5c652B3816E0D53705a7D84F060", - "poolType": "burnMint", + "pool": { + "address": "0x57500aB5b2b6B5c652B3816E0D53705a7D84F060", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "sINV", "tokenAddress": "0x1992AF61FBf8ee38741bcc57d636CAA22A1a7702" }, @@ -4647,8 +7228,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Staked Inv", - "poolAddress": "0xF57fc17729Bd2bcD1e1342917B160eB4b69EE89A", - "poolType": "lockRelease", + "pool": { + "address": "0xF57fc17729Bd2bcD1e1342917B160eB4b69EE89A", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "sINV", "tokenAddress": "0x08d23468A467d2bb86FaE0e32F247A26C7E2e994" } @@ -4658,8 +7243,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sekuya", - "poolAddress": "0x48C4215ccb6Fa0974F7e0383b965959D0e944311", - "poolType": "burnMint", + "pool": { + "address": "0x48C4215ccb6Fa0974F7e0383b965959D0e944311", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SKYA", "tokenAddress": "0x84E9aaE2081AD3135Ec82496c31e5658A31B9756" }, @@ -4667,8 +7256,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sekuya", - "poolAddress": "0xcf9f8A4697510B69ABc3303521FC9d8f68fB689d", - "poolType": "burnMint", + "pool": { + "address": "0xcf9f8A4697510B69ABc3303521FC9d8f68fB689d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SKYA", "tokenAddress": "0x623cD3a3EdF080057892aaF8D773Bbb7A5C9b6e9" }, @@ -4676,8 +7269,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sekuya", - "poolAddress": "0x78f6EB041A85eF3c1a1dC02C57b6beBfcAcBabbf", - "poolType": "burnMint", + "pool": { + "address": "0x78f6EB041A85eF3c1a1dC02C57b6beBfcAcBabbf", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SKYA", "tokenAddress": "0x623cD3a3EdF080057892aaF8D773Bbb7A5C9b6e9" }, @@ -4685,8 +7282,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sekuya Multiverse", - "poolAddress": "0x285f961842Da90AcFef2f2ab622854a0BFf12F9a", - "poolType": "burnMint", + "pool": { + "address": "0x285f961842Da90AcFef2f2ab622854a0BFf12F9a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SKYA", "tokenAddress": "0x71b690adae1eba2e1A5d8a7b51a037b39A4CF007" } @@ -4696,8 +7297,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Snow Ball", - "poolAddress": "0x5e2E4A679e9e6c484c1095388A8F829851901746", - "poolType": "burnMint", + "pool": { + "address": "0x5e2E4A679e9e6c484c1095388A8F829851901746", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SNOW", "tokenAddress": "0x19E846C0341260f516b441e0b72a078218f514b0" }, @@ -4705,8 +7310,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Snow Ball", - "poolAddress": "0xa0fFE2d845aeE8dE1DbD652881D8CAb3607fd0d5", - "poolType": "burnMint", + "pool": { + "address": "0xa0fFE2d845aeE8dE1DbD652881D8CAb3607fd0d5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SNOW", "tokenAddress": "0xD62cf77508B80d5776aaAC9CA06227fF84cC845c" }, @@ -4714,8 +7323,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Snow Ball", - "poolAddress": "0xE3C8b709C43c4Fa4D2535f354e28e6FFC2614b69", - "poolType": "lockRelease", + "pool": { + "address": "0xE3C8b709C43c4Fa4D2535f354e28e6FFC2614b69", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "SNOW", "tokenAddress": "0x2778f7E40D90DB18203Ec31C9c5F84fde6cf6763" } @@ -4725,8 +7338,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Soil", - "poolAddress": "0xF3BD0793FAD8b24B7ba58956dE9DE305D34B9098", - "poolType": "burnMint", + "pool": { + "address": "0xF3BD0793FAD8b24B7ba58956dE9DE305D34B9098", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SOIL", "tokenAddress": "0x54991328Ab43c7D5d31C19d1B9fa048E77B5cd16" }, @@ -4734,8 +7351,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Soil", - "poolAddress": "0xb88d671611d6F517d5D94193da4d5B0dB79E3A0C", - "poolType": "lockRelease", + "pool": { + "address": "0xb88d671611d6F517d5D94193da4d5B0dB79E3A0C", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "SOIL", "tokenAddress": "0x43C73b90E0C2A355784dCf0Da12f477729b31e77" } @@ -4745,8 +7366,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0xc929ad75B72593967DE83E7F7Cda0493458261D9", - "poolType": "burnMint", + "pool": { + "address": "0xc929ad75B72593967DE83E7F7Cda0493458261D9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC", "tokenAddress": "0xbc78D84Ba0c46dFe32cf2895a19939c86b81a777" }, @@ -4754,8 +7379,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x0a12ec21c43ab2b4f69693Da1b0149e7652689c0", - "poolType": "burnMint", + "pool": { + "address": "0x0a12ec21c43ab2b4f69693Da1b0149e7652689c0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x541FD749419CA806a8bc7da8ac23D346f2dF8B77" }, @@ -4763,8 +7392,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x6c2310D68F21C024FF66Cc52e65220112F35DC32", - "poolType": "burnMint", + "pool": { + "address": "0x6c2310D68F21C024FF66Cc52e65220112F35DC32", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x541FD749419CA806a8bc7da8ac23D346f2dF8B77" }, @@ -4772,8 +7405,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x99D94f528CeA3eE1791ab7B476A1FACb4297CA17", - "poolType": "burnMint", + "pool": { + "address": "0x99D94f528CeA3eE1791ab7B476A1FACb4297CA17", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x4aae823a6a0b376De6A78e74eCC5b079d38cBCf7" }, @@ -4781,8 +7418,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x4f628aF99578da6A481851779Fa297A35500C173", - "poolType": "burnMint", + "pool": { + "address": "0x4f628aF99578da6A481851779Fa297A35500C173", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x3647c54c4c2C65bC7a2D63c0Da2809B399DBBDC0" }, @@ -4790,8 +7431,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x2315f2A36af9dd75B7a4E1c6c53B11767eBfb750", - "poolType": "burnMint", + "pool": { + "address": "0x2315f2A36af9dd75B7a4E1c6c53B11767eBfb750", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x3B86Ad95859b6AB773f55f8d94B4b9d443EE931f" }, @@ -4799,8 +7444,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0xf49f81b3d2F2a79b706621FA2D5934136352140c", - "poolType": "burnMint", + "pool": { + "address": "0xf49f81b3d2F2a79b706621FA2D5934136352140c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SolvBTC", "tokenAddress": "0xaE4EFbc7736f963982aACb17EFA37fCBAb924cB3" }, @@ -4808,8 +7457,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x99D94f528CeA3eE1791ab7B476A1FACb4297CA17", - "poolType": "burnMint", + "pool": { + "address": "0x99D94f528CeA3eE1791ab7B476A1FACb4297CA17", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x541FD749419CA806a8bc7da8ac23D346f2dF8B77" }, @@ -4817,8 +7470,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0xb5829e1f8078860969950852546B947f37855ef1", - "poolType": "burnMint", + "pool": { + "address": "0xb5829e1f8078860969950852546B947f37855ef1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x541FD749419CA806a8bc7da8ac23D346f2dF8B77" }, @@ -4826,8 +7483,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f", - "poolType": "burnMint", + "pool": { + "address": "0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x74eD17608cc2B5f30a59d6aF07C9aD1B1aB3A5b1" }, @@ -4835,8 +7496,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0xFC361d7443B3E19F3720462d07480a03d60BB620", - "poolType": "burnMint", + "pool": { + "address": "0xFC361d7443B3E19F3720462d07480a03d60BB620", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC", "tokenAddress": "0xaE4EFbc7736f963982aACb17EFA37fCBAb924cB3" }, @@ -4844,8 +7509,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x3300f27EDEeEB59CC4C4203785406cBEAfEC8dF3", - "poolType": "burnMint", + "pool": { + "address": "0x3300f27EDEeEB59CC4C4203785406cBEAfEC8dF3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x7A56E1C57C7475CCf742a1832B028F0456652F97" }, @@ -4853,8 +7522,25 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x0809FC59B735e0aa90448514bBbEe0C75A080475", - "poolType": "burnMint", + "pool": { + "address": "0x0809FC59B735e0aa90448514bBbEe0C75A080475", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, + "symbol": "SolvBTC", + "tokenAddress": "0xaE4EFbc7736f963982aACb17EFA37fCBAb924cB3" + }, + "monad-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Solv BTC", + "pool": { + "address": "0x4bc35816c1D0B911940894ccd5121eC64Ffd69eb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SolvBTC", "tokenAddress": "0xaE4EFbc7736f963982aACb17EFA37fCBAb924cB3" }, @@ -4862,8 +7548,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x4b75FE6e4a53A510AbC39c7328B0b06E74a3F624", - "poolType": "burnMint", + "pool": { + "address": "0x4b75FE6e4a53A510AbC39c7328B0b06E74a3F624", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x541FD749419CA806a8bc7da8ac23D346f2dF8B77" }, @@ -4871,8 +7561,12 @@ "allowListEnabled": false, "decimals": 8, "name": "SolvBTC", - "poolAddress": "2a6KLcDkvoTVWmPDQhc15earc6hU4uwEyBQrmRfcBon4", - "poolType": "burnMint", + "pool": { + "address": "2a6KLcDkvoTVWmPDQhc15earc6hU4uwEyBQrmRfcBon4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SolvBTC", "tokenAddress": "SoLvHDFVstC74Jr9eNLTDoG4goSUsn1RENmjNtFKZvW" }, @@ -4880,8 +7574,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x6c2310D68F21C024FF66Cc52e65220112F35DC32", - "poolType": "burnMint", + "pool": { + "address": "0x6c2310D68F21C024FF66Cc52e65220112F35DC32", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x541FD749419CA806a8bc7da8ac23D346f2dF8B77" }, @@ -4889,8 +7587,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Solv BTC", - "poolAddress": "0x62FD93Fc58D94eE253542ECD5C23467F65dCdB73", - "poolType": "burnMint", + "pool": { + "address": "0x62FD93Fc58D94eE253542ECD5C23467F65dCdB73", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SolvBTC", "tokenAddress": "0x541FD749419CA806a8bc7da8ac23D346f2dF8B77" } @@ -4900,8 +7602,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SolvBTC Bera Vault", - "poolAddress": "0xF8AE5209DE22dbd06Dace938934b0D75B5E80299", - "poolType": "burnMint", + "pool": { + "address": "0xF8AE5209DE22dbd06Dace938934b0D75B5E80299", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC.BERA", "tokenAddress": "0x0F6f337B09cb5131cF0ce9df3Beb295b8e728F3B" }, @@ -4909,8 +7615,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SolvBTC Bera Vault", - "poolAddress": "0x42e15ab6098716f3Ae67e0Ff69C64b5a47304406", - "poolType": "burnMint", + "pool": { + "address": "0x42e15ab6098716f3Ae67e0Ff69C64b5a47304406", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SolvBTC.BERA", "tokenAddress": "0x0F6f337B09cb5131cF0ce9df3Beb295b8e728F3B" }, @@ -4918,8 +7628,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SolvBTC Bera Vault", - "poolAddress": "0x0Cd252108EF0CE50f95F75045a97C72A0A8d3118", - "poolType": "burnMint", + "pool": { + "address": "0x0Cd252108EF0CE50f95F75045a97C72A0A8d3118", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SolvBTC.BERA", "tokenAddress": "0x0F6f337B09cb5131cF0ce9df3Beb295b8e728F3B" }, @@ -4927,8 +7641,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SolvBTC Bera Vault", - "poolAddress": "0xD4304D2D5C9cdF63124fD2A6C814f6b4F85925D9", - "poolType": "burnMint", + "pool": { + "address": "0xD4304D2D5C9cdF63124fD2A6C814f6b4F85925D9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "SolvBTC.BERA", "tokenAddress": "0xE7C253EAD50976Caf7b0C2cbca569146A7741B50" } @@ -4938,8 +7656,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SolvBTC Jupiter", - "poolAddress": "0xb655EEd4AD8A1A7011c6C431DaE8b55a19a508B9", - "poolType": "burnMint", + "pool": { + "address": "0xb655EEd4AD8A1A7011c6C431DaE8b55a19a508B9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SolvBTC.JUP", "tokenAddress": "0x6b062AA7F5FC52b530Cb13967aE2E6bc0D8Dd3E4" }, @@ -4947,8 +7669,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SolvBTC Jupiter", - "poolAddress": "0x48731cF7e84dc94C5f84577882c14Be11a5B7456", - "poolType": "burnMint", + "pool": { + "address": "0x48731cF7e84dc94C5f84577882c14Be11a5B7456", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SolvBTC.JUP", "tokenAddress": "0x38a001e57430f781404ffF7a81DE4Bd67d1f6117" }, @@ -4956,8 +7682,12 @@ "allowListEnabled": false, "decimals": 8, "name": "SolvBTC.JUP", - "poolAddress": "HMDSmmuupoWwe9TV3nZ3qmPqAKL2tU7udghJzCywckgM", - "poolType": "burnMint", + "pool": { + "address": "HMDSmmuupoWwe9TV3nZ3qmPqAKL2tU7udghJzCywckgM", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SolvBTCJUP", "tokenAddress": "SoLvzL3ZVjofmNB5LYFrf94QtNhMUSea4DawFhnAau8" }, @@ -4965,8 +7695,12 @@ "allowListEnabled": false, "decimals": 18, "name": "SolvBTC Jupiter", - "poolAddress": "0x62FD93Fc58D94eE253542ECD5C23467F65dCdB73", - "poolType": "burnMint", + "pool": { + "address": "0x62FD93Fc58D94eE253542ECD5C23467F65dCdB73", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "SolvBTC.JUP", "tokenAddress": "0xAffEb8576b927050f5a3B6fbA43F360D2883A118" } @@ -4976,8 +7710,12 @@ "allowListEnabled": false, "decimals": 18, "name": "STABLE", - "poolAddress": "0x7169054A07c8946E45728CDe01Fee68bab5BEB82", - "poolType": "burnMint", + "pool": { + "address": "0x7169054A07c8946E45728CDe01Fee68bab5BEB82", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "STABLE", "tokenAddress": "0x8bF75bc68FD337dfd8186d731Df8b3C2CB14B9E6" }, @@ -4985,8 +7723,12 @@ "allowListEnabled": false, "decimals": 18, "name": "STABLE", - "poolAddress": "0xD5B44D00A3670533c17b6BE38156C0b1bBdBe90A", - "poolType": "burnMint", + "pool": { + "address": "0xD5B44D00A3670533c17b6BE38156C0b1bBdBe90A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "STABLE", "tokenAddress": "0x666966Ef3925B1c92fa355FDA9722899f3e73451" }, @@ -4994,8 +7736,12 @@ "allowListEnabled": false, "decimals": 18, "name": "STABLE", - "poolAddress": "0x581CED7408860a33E47CE6cA93e2cbB4bB48c9C7", - "poolType": "burnMint", + "pool": { + "address": "0x581CED7408860a33E47CE6cA93e2cbB4bB48c9C7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "STABLE", "tokenAddress": "0x60b9C41d99FE3Eb64Ecc1344baD31D87f1bceD6D" } @@ -5005,8 +7751,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stabull Finance", - "poolAddress": "0x500F6D4948Aac25074690a1c42Ae267b41a73326", - "poolType": "burnMint", + "pool": { + "address": "0x500F6D4948Aac25074690a1c42Ae267b41a73326", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "STABUL", "tokenAddress": "0x6722F882cc3A1B1034893eFA9764397C88897892" }, @@ -5014,8 +7764,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stabull Finance", - "poolAddress": "0xd2D62AB60A53Bad539CD8e43121c624B246F6302", - "poolType": "burnMint", + "pool": { + "address": "0xd2D62AB60A53Bad539CD8e43121c624B246F6302", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "STABUL", "tokenAddress": "0x6A43795941113c2F58EB487001f4f8eE74b6938A" }, @@ -5023,8 +7777,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stabull Finance", - "poolAddress": "0x057aDAdDa0C63fE48A41dEFFb13B07528b1Bee3b", - "poolType": "burnMint", + "pool": { + "address": "0x057aDAdDa0C63fE48A41dEFFb13B07528b1Bee3b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "STABUL", "tokenAddress": "0xC4420347a4791832bb7b16bF070D5C017D9fABC4" } @@ -5034,8 +7792,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lorenzo stBTC", - "poolAddress": "0x4B8BdCAdbDbb20330a6f90C8c8B1BA2E363E9BE8", - "poolType": "burnMint", + "pool": { + "address": "0x4B8BdCAdbDbb20330a6f90C8c8B1BA2E363E9BE8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "stBTC", "tokenAddress": "0xf6718b2701D4a6498eF77D7c152b2137Ab28b8A3" }, @@ -5043,8 +7805,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Lorenzo stBTC", - "poolAddress": "0x20282C8e5d2d44BaC0E37A3C78a18b3f78EE1d86", - "poolType": "burnMint", + "pool": { + "address": "0x20282C8e5d2d44BaC0E37A3C78a18b3f78EE1d86", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "stBTC", "tokenAddress": "0xf6718b2701D4a6498eF77D7c152b2137Ab28b8A3" } @@ -5054,8 +7820,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stobox Token v.2", - "poolAddress": "0x44e77d8C6Bb9999B036a6F084005E48928d18C74", - "poolType": "lockRelease", + "pool": { + "address": "0x44e77d8C6Bb9999B036a6F084005E48928d18C74", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "STBU", "tokenAddress": "0xb0c4080a8Fa7afa11a09473f3be14d44AF3f8743" }, @@ -5063,8 +7833,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stobox Token v.3", - "poolAddress": "0x44e77d8C6Bb9999B036a6F084005E48928d18C74", - "poolType": "burnMint", + "pool": { + "address": "0x44e77d8C6Bb9999B036a6F084005E48928d18C74", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "STBU", "tokenAddress": "0x1cb9bD2c6E7F4A7DE3778547d46C8D4c22abC093" }, @@ -5072,8 +7846,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stobox Token v.2", - "poolAddress": "0x44e77d8C6Bb9999B036a6F084005E48928d18C74", - "poolType": "lockRelease", + "pool": { + "address": "0x44e77d8C6Bb9999B036a6F084005E48928d18C74", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "STBU", "tokenAddress": "0xa6422E3E219ee6d4C1B18895275FE43556fd50eD" }, @@ -5081,8 +7859,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Stobox Token v.2", - "poolAddress": "0x44e77d8C6Bb9999B036a6F084005E48928d18C74", - "poolType": "lockRelease", + "pool": { + "address": "0x44e77d8C6Bb9999B036a6F084005E48928d18C74", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "STBU", "tokenAddress": "0xcf403036bc139d30080D2Cf0F5b48066F98191bB" } @@ -5092,8 +7874,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Tensorplex Staked TAO", - "poolAddress": "0x4F3eF0574095DeE6f216b9dD9f21Bfb0466a4CCD", - "poolType": "burnMint", + "pool": { + "address": "0x4F3eF0574095DeE6f216b9dD9f21Bfb0466a4CCD", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "stTAO", "tokenAddress": "0x886C0677D7BB7272C7eD8878dc03EF357aFbb5B5" }, @@ -5101,8 +7887,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Tensorplex Staked TAO", - "poolAddress": "0x43Fadc7B2929078F0f318E0bEC6b31dC2bF1C309", - "poolType": "burnMint", + "pool": { + "address": "0x43Fadc7B2929078F0f318E0bEC6b31dC2bF1C309", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "stTAO", "tokenAddress": "0x806041B6473DA60abbe1b256d9A2749A151be6C6" }, @@ -5110,8 +7900,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Tensorplex Staked TAO", - "poolAddress": "0x46083b69F70dDDbd1212e3AAc566DC3D8AdAc4C4", - "poolType": "burnMint", + "pool": { + "address": "0x46083b69F70dDDbd1212e3AAc566DC3D8AdAc4C4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "stTAO", "tokenAddress": "0x806041B6473DA60abbe1b256d9A2749A151be6C6" }, @@ -5119,8 +7913,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Tensorplex Staked TAO", - "poolAddress": "0x5c16671f7360E32982691c6A14353D8186C57A59", - "poolType": "lockRelease", + "pool": { + "address": "0x5c16671f7360E32982691c6A14353D8186C57A59", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "stTAO", "tokenAddress": "0xB60acD2057067DC9ed8c083f5aa227a244044fD6" } @@ -5130,8 +7928,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sumerian BTC", - "poolAddress": "0xd9193B4aFfA057Fa78E0b5C60fAf1bC09df3708b", - "poolType": "burnMint", + "pool": { + "address": "0xd9193B4aFfA057Fa78E0b5C60fAf1bC09df3708b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "suBTC", "tokenAddress": "0xe85411C030fB32A9D8b14Bbbc6CB19417391F711" }, @@ -5139,8 +7941,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sumerian BTC", - "poolAddress": "0x13d579664bAAb9ADcC4c6B19956f7b7EADBB036f", - "poolType": "burnMint", + "pool": { + "address": "0x13d579664bAAb9ADcC4c6B19956f7b7EADBB036f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "suBTC", "tokenAddress": "0xe85411C030fB32A9D8b14Bbbc6CB19417391F711" }, @@ -5148,8 +7954,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sumerian BTC", - "poolAddress": "0x5Be290d68db372cc487B1356649D906efC4f58Ca", - "poolType": "burnMint", + "pool": { + "address": "0x5Be290d68db372cc487B1356649D906efC4f58Ca", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "suBTC", "tokenAddress": "0xe85411C030fB32A9D8b14Bbbc6CB19417391F711" } @@ -5159,8 +7969,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sumerian ETH", - "poolAddress": "0x70544B4E4FcEd9c61BCdb6E0fFa69002cC4d374f", - "poolType": "burnMint", + "pool": { + "address": "0x70544B4E4FcEd9c61BCdb6E0fFa69002cC4d374f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "suETH", "tokenAddress": "0x1c22531AA9747d76fFF8F0A43b37954ca67d28e0" }, @@ -5168,8 +7982,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sumerian ETH", - "poolAddress": "0xafc7E9fDD13AFF368B1d8d16e04f4977e68128E1", - "poolType": "burnMint", + "pool": { + "address": "0xafc7E9fDD13AFF368B1d8d16e04f4977e68128E1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "suETH", "tokenAddress": "0x1c22531AA9747d76fFF8F0A43b37954ca67d28e0" }, @@ -5177,8 +7995,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sumerian ETH", - "poolAddress": "0xE58eDBb7Fdd5f2DD5cfAD2667e5D570E1a0a6A84", - "poolType": "burnMint", + "pool": { + "address": "0xE58eDBb7Fdd5f2DD5cfAD2667e5D570E1a0a6A84", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "suETH", "tokenAddress": "0x1c22531AA9747d76fFF8F0A43b37954ca67d28e0" } @@ -5188,16 +8010,33 @@ "allowListEnabled": false, "decimals": 18, "name": "sUSD1+", - "poolAddress": "0xa58B73a340f3c0d9d65Be8cAaB6C5EfB9331F775", - "poolType": "burnMint", + "pool": { + "address": "0xa58B73a340f3c0d9d65Be8cAaB6C5EfB9331F775", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, + "symbol": "sUSD1+", + "tokenAddress": "0x4F2760B32720F013E900DC92F65480137391199b" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "sUSD1+", + "pool": { + "address": "0xBe4fbD980712a800f5e0e7C15a70e097efaCD331", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "sUSD1+", - "tokenAddress": "0x4F2760B32720F013E900DC92F65480137391199b" + "tokenAddress": "0x8F18f2C97d2f5EC0e1d5B91c1D2ce245a9151972" }, - "mainnet": { + "plume-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "sUSD1+", - "poolAddress": "0xBe4fbD980712a800f5e0e7C15a70e097efaCD331", + "poolAddress": "0xfF36edF970d1DC4504f608bB02D0Ae0a8a80312A", "poolType": "burnMint", "symbol": "sUSD1+", "tokenAddress": "0x8F18f2C97d2f5EC0e1d5B91c1D2ce245a9151972" @@ -5208,8 +8047,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sumerian USD", - "poolAddress": "0x6C8Fee5E05E99db417DFEe0B96275B065eA20EAe", - "poolType": "burnMint", + "pool": { + "address": "0x6C8Fee5E05E99db417DFEe0B96275B065eA20EAe", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "suUSD", "tokenAddress": "0x8BF591Eae535f93a242D5A954d3Cde648b48A5A8" }, @@ -5217,8 +8060,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Sumerian USD", - "poolAddress": "0x69797ECF7ACd6CA73a8c42cfb4268F7572047346", - "poolType": "burnMint", + "pool": { + "address": "0x69797ECF7ACd6CA73a8c42cfb4268F7572047346", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "suUSD", "tokenAddress": "0x8BF591Eae535f93a242D5A954d3Cde648b48A5A8" }, @@ -5226,19 +8073,47 @@ "allowListEnabled": false, "decimals": 18, "name": "Sumerian USD", - "poolAddress": "0x67F4e731f446Ff76716E7E3c955CD5A75C1B1787", - "poolType": "burnMint", + "pool": { + "address": "0x67F4e731f446Ff76716E7E3c955CD5A75C1B1787", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "suUSD", "tokenAddress": "0x8BF591Eae535f93a242D5A954d3Cde648b48A5A8" } }, + "SWCH": { + "bsc-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "SwissCheese Token", + "poolAddress": "0xbB4bd217aF1161F973792250B59404363866B687", + "poolType": "burnMint", + "symbol": "SWCH", + "tokenAddress": "0x280aB1903a06B5badEC1D204F450Ee8D068405d8" + }, + "matic-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "SwissCheese Token", + "poolAddress": "0x5521ceE67Ce3C7ED0e0477522a0085E1af2810d1", + "poolType": "lockRelease", + "symbol": "SWCH", + "tokenAddress": "0x3ce1327867077B551ae9A6987bF10C9fd08edCE1" + } + }, "SXT": { "ethereum-mainnet-base-1": { "allowListEnabled": false, "decimals": 18, "name": "Space and Time", - "poolAddress": "0x44E787a3a81bbc03Ec2C2a7aDADC5aE7Bc925Db9", - "poolType": "burnMint", + "pool": { + "address": "0x44E787a3a81bbc03Ec2C2a7aDADC5aE7Bc925Db9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "SXT", "tokenAddress": "0xA2c22252cDc8b7cDdEe1B0b2E242818509fCf7b8" }, @@ -5246,8 +8121,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Space and Time", - "poolAddress": "0x19EE30DE803b921Ecbba64eD1787Cda6d536c26a", - "poolType": "lockRelease", + "pool": { + "address": "0x19EE30DE803b921Ecbba64eD1787Cda6d536c26a", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "SXT", "tokenAddress": "0xE6Bfd33F52d82Ccb5b37E16D3dD81f9FFDAbB195" } @@ -5257,8 +8136,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Syrup USDC", - "poolAddress": "0x660975730059246A68521a3e2FBD4740173100f5", - "poolType": "burnMint", + "pool": { + "address": "0x660975730059246A68521a3e2FBD4740173100f5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "syrupUSDC", "tokenAddress": "0x41CA7586cC1311807B4605fBB748a3B8862b42b5" }, @@ -5266,8 +8149,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Syrup USDC", - "poolAddress": "0xA36955b2Bc12Aee77FF7519482D16C7B86DBe42a", - "poolType": "burnMint", + "pool": { + "address": "0xA36955b2Bc12Aee77FF7519482D16C7B86DBe42a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "syrupUSDC", "tokenAddress": "0x660975730059246A68521a3e2FBD4740173100f5" }, @@ -5275,8 +8162,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Syrup USDC", - "poolAddress": "0x966519C334D895121B61584CAdeBc15571b62983", - "poolType": "burnMint", + "pool": { + "address": "0x966519C334D895121B61584CAdeBc15571b62983", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "syrupUSDC", "tokenAddress": "0xd31dB306E5D79F0018Ac92e08492284201493EA1" }, @@ -5284,8 +8175,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Syrup USDC", - "poolAddress": "0x20B79D39Bd44dEee4F89B1e9d0e3b945fde06491", - "poolType": "lockRelease", + "pool": { + "address": "0x20B79D39Bd44dEee4F89B1e9d0e3b945fde06491", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "syrupUSDC", "tokenAddress": "0x80ac24aA929eaF5013f6436cdA2a7ba190f5Cc0b" }, @@ -5293,19 +8188,49 @@ "allowListEnabled": false, "decimals": 6, "name": "Syrup USDC", - "poolAddress": "HrTBpF3LqSxXnjnYdR4htnBLyMHNZ6eNaDZGPundvHbm", - "poolType": "burnMint", + "pool": { + "address": "HrTBpF3LqSxXnjnYdR4htnBLyMHNZ6eNaDZGPundvHbm", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "syrupUSDC", "tokenAddress": "AvZZF1YaZDziPY2RCK4oJrRVrbN3mTD9NL24hPeaZeUj" } }, "syrupUSDT": { + "bsc-mainnet": { + "allowListEnabled": false, + "decimals": 6, + "name": "Syrup USDT", + "poolAddress": "0xEAA7E1f805747ae29d5618b568d1b044A8b37A01", + "poolType": "burnMint", + "symbol": "syrupUSDT", + "tokenAddress": "0x8E9d4cEa39299323FE8eda678cAD449718556c4e" + }, + "ethereum-mainnet-mantle-1": { + "allowListEnabled": false, + "decimals": 6, + "name": "Syrup USDT", + "pool": { + "address": "0x0aA145a62153190B8f0D3cA00c441e451529f755", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "syrupUSDT", + "tokenAddress": "0x051665f2455116e929b9972c36d23070F5054Ce0" + }, "mainnet": { "allowListEnabled": false, "decimals": 6, "name": "Syrup USDT", - "poolAddress": "0xDE76A096C5eadDdf97Af3fE15ee49d32AEDa9822", - "poolType": "lockRelease", + "pool": { + "address": "0xDE76A096C5eadDdf97Af3fE15ee49d32AEDa9822", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "syrupUSDT", "tokenAddress": "0x356B8d89c1e1239Cbbb9dE4815c39A1474d5BA7D" }, @@ -5313,8 +8238,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Syrup USDT", - "poolAddress": "0x1d952d2f6eE86Ef4940Fa648aA7477c8fF175F09", - "poolType": "burnMint", + "pool": { + "address": "0x1d952d2f6eE86Ef4940Fa648aA7477c8fF175F09", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "syrupUSDT", "tokenAddress": "0xC4374775489CB9C56003BF2C9b12495fC64F0771" } @@ -5324,8 +8253,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Treehouse ETH", - "poolAddress": "0x0C3603B0c299e680A5Af4dC83a962d66E852903B", - "poolType": "burnMint", + "pool": { + "address": "0x0C3603B0c299e680A5Af4dC83a962d66E852903B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "tETH", "tokenAddress": "0xd09ACb80C1E8f2291862c4978A008791c9167003" }, @@ -5333,8 +8266,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Treehouse ETH", - "poolAddress": "0x0C3603B0c299e680A5Af4dC83a962d66E852903B", - "poolType": "burnMint", + "pool": { + "address": "0x0C3603B0c299e680A5Af4dC83a962d66E852903B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "tETH", "tokenAddress": "0xd09ACb80C1E8f2291862c4978A008791c9167003" }, @@ -5342,8 +8279,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Treehouse ETH", - "poolAddress": "0x0C3603B0c299e680A5Af4dC83a962d66E852903B", - "poolType": "burnMint", + "pool": { + "address": "0x0C3603B0c299e680A5Af4dC83a962d66E852903B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "tETH", "tokenAddress": "0xd09ACb80C1E8f2291862c4978A008791c9167003" }, @@ -5351,8 +8292,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Treehouse ETH", - "poolAddress": "0x8113f001eA456759264317007220cBc939cA8435", - "poolType": "lockRelease", + "pool": { + "address": "0x8113f001eA456759264317007220cBc939cA8435", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "tETH", "tokenAddress": "0xD11c452fc99cF405034ee446803b6F6c1F6d5ED8" }, @@ -5360,8 +8305,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Treehouse ETH", - "poolAddress": "0x0C3603B0c299e680A5Af4dC83a962d66E852903B", - "poolType": "burnMint", + "pool": { + "address": "0x0C3603B0c299e680A5Af4dC83a962d66E852903B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "tETH", "tokenAddress": "0xd09ACb80C1E8f2291862c4978A008791c9167003" } @@ -5371,8 +8320,12 @@ "allowListEnabled": false, "decimals": 18, "name": "THENA", - "poolAddress": "0x93cAb7CB2a07477A557754a81971EFeDFa04EdAA", - "poolType": "burnMint", + "pool": { + "address": "0x93cAb7CB2a07477A557754a81971EFeDFa04EdAA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "THE", "tokenAddress": "0x9d94A7fF461e83F161c8c040E78557e31d8Cba72" }, @@ -5380,8 +8333,12 @@ "allowListEnabled": false, "decimals": 18, "name": "THENA", - "poolAddress": "0xECFF67559c0583027A5fbd85136E33bC4D66eeA0", - "poolType": "lockRelease", + "pool": { + "address": "0xECFF67559c0583027A5fbd85136E33bC4D66eeA0", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "THE", "tokenAddress": "0xF4C8E32EaDEC4BFe97E0F595AdD0f4450a863a11" }, @@ -5389,8 +8346,12 @@ "allowListEnabled": false, "decimals": 18, "name": "THENA", - "poolAddress": "0x2a9f896660E802c59a3178b2E8CB7FBaCCC04e86", - "poolType": "burnMint", + "pool": { + "address": "0x2a9f896660E802c59a3178b2E8CB7FBaCCC04e86", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "THE", "tokenAddress": "0x27DfD2D7b85e0010542da35C6EBcD59E45fc949D" } @@ -5400,8 +8361,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Polytrade", - "poolAddress": "0x7eb93143612CFB6Dda216EBE481e510F3A3b645f", - "poolType": "burnMint", + "pool": { + "address": "0x7eb93143612CFB6Dda216EBE481e510F3A3b645f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "TRADE", "tokenAddress": "0xb75Ba7eF520A5Bd0A5d01108060bE269642c4601" }, @@ -5409,8 +8374,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Polytrade", - "poolAddress": "0x2bFBA5bD4b0b1180A135Bb6a74423cCB429Fc744", - "poolType": "burnMint", + "pool": { + "address": "0x2bFBA5bD4b0b1180A135Bb6a74423cCB429Fc744", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "TRADE", "tokenAddress": "0x72e1868f8EB8f9fb86455c10e72aa4b24774a5a3" }, @@ -5418,8 +8387,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Polytrade", - "poolAddress": "0x520763c1eBDa04DAC9a6077a41CCC703FF22a9f8", - "poolType": "lockRelease", + "pool": { + "address": "0x520763c1eBDa04DAC9a6077a41CCC703FF22a9f8", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "TRADE", "tokenAddress": "0x6e5970DBd6fc7eb1f29C6D2eDF2bC4c36124C0C1" }, @@ -5427,8 +8400,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Polytrade (PoS)", - "poolAddress": "0xbE787bD62c85c2dCB92B662A5d77348eA9A7e461", - "poolType": "lockRelease", + "pool": { + "address": "0xbE787bD62c85c2dCB92B662A5d77348eA9A7e461", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "TRADE", "tokenAddress": "0x692AC1e363ae34b6B489148152b12e2785a3d8d6" } @@ -5438,8 +8415,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Treehouse Token", - "poolAddress": "0x229AE3eC539865444404c666f504Be68CeB81E02", - "poolType": "burnMint", + "pool": { + "address": "0x229AE3eC539865444404c666f504Be68CeB81E02", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "TREE", "tokenAddress": "0x77146784315Ba81904d654466968e3a7c196d1f3" }, @@ -5447,8 +8428,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Treehouse Token", - "poolAddress": "0x229AE3eC539865444404c666f504Be68CeB81E02", - "poolType": "burnMint", + "pool": { + "address": "0x229AE3eC539865444404c666f504Be68CeB81E02", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "TREE", "tokenAddress": "0x77146784315Ba81904d654466968e3a7c196d1f3" }, @@ -5456,8 +8441,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Treehouse Token", - "poolAddress": "0x407dBD0170A79Bb62a016d4555C656205BbA8a68", - "poolType": "lockRelease", + "pool": { + "address": "0x407dBD0170A79Bb62a016d4555C656205BbA8a68", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "TREE", "tokenAddress": "0x77146784315Ba81904d654466968e3a7c196d1f3" } @@ -5467,8 +8456,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Turbo", - "poolAddress": "0xeA771EB68CcfE489cdA2713F4248CD512c880453", - "poolType": "burnMint", + "pool": { + "address": "0xeA771EB68CcfE489cdA2713F4248CD512c880453", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "TURBO", "tokenAddress": "0x620a8b7Bd26b21d0d053ee9a05A593f35Bf37d8e" }, @@ -5476,8 +8469,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Turbo", - "poolAddress": "0x348540aa7b129b0F3c931FEDE811d009E0e18E60", - "poolType": "lockRelease", + "pool": { + "address": "0x348540aa7b129b0F3c931FEDE811d009E0e18E60", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "TURBO", "tokenAddress": "0xA35923162C49cF95e6BF26623385eb431ad920D3" } @@ -5487,8 +8484,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Turtle", - "poolAddress": "0x4559605E3003fdA8c059e14aF4f16ba9a004335a", - "poolType": "burnMint", + "pool": { + "address": "0x4559605E3003fdA8c059e14aF4f16ba9a004335a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "TURTLE", "tokenAddress": "0x66fD8de541c0594b4DccdFc13Bf3a390E50d3Afd" }, @@ -5496,8 +8497,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Turtle", - "poolAddress": "0x7263Bc9f9D2f94e9a3Bcb3EFB40C79C43aC0C647", - "poolType": "burnMint", + "pool": { + "address": "0x7263Bc9f9D2f94e9a3Bcb3EFB40C79C43aC0C647", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "TURTLE", "tokenAddress": "0x56aa6D651bfefA9207B35E508716466359BAe8eF" }, @@ -5505,8 +8510,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Turtle", - "poolAddress": "0xD3bD7Db2B40DBEE54cA70a34921fde8A8D2f8BbB", - "poolType": "burnMint", + "pool": { + "address": "0xD3bD7Db2B40DBEE54cA70a34921fde8A8D2f8BbB", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "TURTLE", "tokenAddress": "0x66fD8de541c0594b4DccdFc13Bf3a390E50d3Afd" } @@ -5516,8 +8525,12 @@ "allowListEnabled": false, "decimals": 6, "name": "una USDC", - "poolAddress": "0xcfd0637093193ac909f74F9de95c2d4B92Df23c4", - "poolType": "burnMint", + "pool": { + "address": "0xcfd0637093193ac909f74F9de95c2d4B92Df23c4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "una.USDC", "tokenAddress": "0x66cC3FD40612F9c591F977ce026Ef1C79520C472" }, @@ -5525,8 +8538,12 @@ "allowListEnabled": false, "decimals": 6, "name": "una USDC", - "poolAddress": "0x0c118bE814166fb720f8DDEB119F53B622787918", - "poolType": "burnMint", + "pool": { + "address": "0x0c118bE814166fb720f8DDEB119F53B622787918", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "una.USDC", "tokenAddress": "0xcdf764933B9a9ebB2C5DA904B9715F3Cf981572A" } @@ -5536,8 +8553,12 @@ "allowListEnabled": false, "decimals": 18, "name": "una WEMIX", - "poolAddress": "0x2F15F2C9d1E0945C37E3EDCD8914BBd0067e46C8", - "poolType": "burnMint", + "pool": { + "address": "0x2F15F2C9d1E0945C37E3EDCD8914BBd0067e46C8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "una.WEMIX", "tokenAddress": "0x9f1453d0fADC73aE12d4e1BD8311AA2463AE7d0D" }, @@ -5545,8 +8566,12 @@ "allowListEnabled": false, "decimals": 18, "name": "una WEMIX", - "poolAddress": "0x2b975918e804803615131e7de2ca1645B1719ec9", - "poolType": "burnMint", + "pool": { + "address": "0x2b975918e804803615131e7de2ca1645B1719ec9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "una.WEMIX", "tokenAddress": "0x98169bF9B7a44EDaD372364063b897E16eBba88e" }, @@ -5554,8 +8579,12 @@ "allowListEnabled": false, "decimals": 18, "name": "una WEMIX", - "poolAddress": "0x65030ab42BAd6E140ADD01D6998DC7d2eCb34089", - "poolType": "burnMint", + "pool": { + "address": "0x65030ab42BAd6E140ADD01D6998DC7d2eCb34089", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "una.WEMIX", "tokenAddress": "0x89F590D8f9c1a306AEB4E939Dc923C80144998Cd" }, @@ -5563,8 +8592,12 @@ "allowListEnabled": false, "decimals": 18, "name": "una WEMIX", - "poolAddress": "0xFaF7992eB0A1eff0C4cdB070c12512f18E0D6079", - "poolType": "burnMint", + "pool": { + "address": "0xFaF7992eB0A1eff0C4cdB070c12512f18E0D6079", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "una.WEMIX", "tokenAddress": "0x6ff638E48247b003E003aa3EeDDdF97BaA8f3B64" }, @@ -5572,8 +8605,12 @@ "allowListEnabled": false, "decimals": 18, "name": "una WEMIX", - "poolAddress": "0x9F02c16190691CC4ceCD53A9267Bd24e37B6d06C", - "poolType": "burnMint", + "pool": { + "address": "0x9F02c16190691CC4ceCD53A9267Bd24e37B6d06C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "una.WEMIX", "tokenAddress": "0x2624Bd0094f474713AC9c634b37A5ebef4e0b1FE" }, @@ -5581,8 +8618,12 @@ "allowListEnabled": false, "decimals": 18, "name": "una WEMIX", - "poolAddress": "0xeDb68F273FC95e1DB951580957c3fE49FF0A8cF7", - "poolType": "burnMint", + "pool": { + "address": "0xeDb68F273FC95e1DB951580957c3fE49FF0A8cF7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "una.WEMIX", "tokenAddress": "0x186d65ceD0693382713437e34EF8723FD6aa9A1E" }, @@ -5590,8 +8631,12 @@ "allowListEnabled": false, "decimals": 18, "name": "una WEMIX", - "poolAddress": "0x3B1f09b0Ac19fCd3F03A0Bdda70F65Db01626de1", - "poolType": "burnMint", + "pool": { + "address": "0x3B1f09b0Ac19fCd3F03A0Bdda70F65Db01626de1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "una.WEMIX", "tokenAddress": "0xF500208d9aB68FeA3cc41bd107811e809C0B6B83" } @@ -5601,8 +8646,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x80ab5314fa37a0c2e10bc490acd7ca83898119accaebac9e7bba61f1f164b8ed", - "poolType": "burnMint", + "pool": { + "address": "0x80ab5314fa37a0c2e10bc490acd7ca83898119accaebac9e7bba61f1f164b8ed", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "uniBTC", "tokenAddress": "0xf764dbfd6999067ac052a8e722ae359bec389bd7dba19ead586801b99b81b075" }, @@ -5610,8 +8659,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x097Ae334B90F98637899cfcaa7980B13aa497e5E", - "poolType": "burnMint", + "pool": { + "address": "0x097Ae334B90F98637899cfcaa7980B13aa497e5E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "uniBTC", "tokenAddress": "0xC3827A4BC8224ee2D116637023b124CED6db6e90" }, @@ -5619,8 +8672,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x4b75FE6e4a53A510AbC39c7328B0b06E74a3F624", - "poolType": "burnMint", + "pool": { + "address": "0x4b75FE6e4a53A510AbC39c7328B0b06E74a3F624", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "uniBTC", "tokenAddress": "0x93919784C523f39CACaa98Ee0a9d96c3F32b593e" }, @@ -5628,8 +8685,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x085e4ADc459699a8Ec60c6da5CBdBF715f23831f", - "poolType": "burnMint", + "pool": { + "address": "0x085e4ADc459699a8Ec60c6da5CBdBF715f23831f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "uniBTC", "tokenAddress": "0x236f8c0a61dA474dB21B693fB2ea7AAB0c803894" }, @@ -5637,8 +8698,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x4b75FE6e4a53A510AbC39c7328B0b06E74a3F624", - "poolType": "burnMint", + "pool": { + "address": "0x4b75FE6e4a53A510AbC39c7328B0b06E74a3F624", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "uniBTC", "tokenAddress": "0x93919784C523f39CACaa98Ee0a9d96c3F32b593e" }, @@ -5646,8 +8711,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0xF0b508c7fF394B94BCb73C19007C7102C2d9aa19", - "poolType": "burnMint", + "pool": { + "address": "0xF0b508c7fF394B94BCb73C19007C7102C2d9aa19", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "uniBTC", "tokenAddress": "0x6B2a01A5f79dEb4c2f3c0eDa7b01DF456FbD726a" }, @@ -5655,8 +8724,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x2c3D51c7B454cB045C8cEc92d2F9E717C7519106", - "poolType": "burnMint", + "pool": { + "address": "0x2c3D51c7B454cB045C8cEc92d2F9E717C7519106", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "uniBTC", "tokenAddress": "0x93919784C523f39CACaa98Ee0a9d96c3F32b593e" }, @@ -5664,8 +8737,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x085BE2297c1A1A2C2a119b731AF887DD0119D035", - "poolType": "burnMint", + "pool": { + "address": "0x085BE2297c1A1A2C2a119b731AF887DD0119D035", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "uniBTC", "tokenAddress": "0x6B2a01A5f79dEb4c2f3c0eDa7b01DF456FbD726a" }, @@ -5673,8 +8750,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x02042Df6933a2Fb8a7Bfc92117146E7CCf6b260f", - "poolType": "burnMint", + "pool": { + "address": "0x02042Df6933a2Fb8a7Bfc92117146E7CCf6b260f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "uniBTC", "tokenAddress": "0x93919784C523f39CACaa98Ee0a9d96c3F32b593e" }, @@ -5682,8 +8763,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0xBf977109Ae4Fd840d23b19454DF1C7414168E9F9", - "poolType": "burnMint", + "pool": { + "address": "0xBf977109Ae4Fd840d23b19454DF1C7414168E9F9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "uniBTC", "tokenAddress": "0xd3c8dA379d71a33BfEE8875F87Ac2748bEB1d58d" }, @@ -5691,26 +8776,47 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x85d4CfFC273b0766bFa1402d890c71DF167CC2AD", - "poolType": "burnMint", + "pool": { + "address": "0x85d4CfFC273b0766bFa1402d890c71DF167CC2AD", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "uniBTC", "tokenAddress": "0x93919784C523f39CACaa98Ee0a9d96c3F32b593e" }, - "ethereum-mainnet-optimism-1": { + "ethereum-mainnet-mode-1": { "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x99D94f528CeA3eE1791ab7B476A1FACb4297CA17", + "poolAddress": "0x5A1764254dE62FC55a08E907c712565545615dDb", "poolType": "burnMint", "symbol": "uniBTC", + "tokenAddress": "0x6B2a01A5f79dEb4c2f3c0eDa7b01DF456FbD726a" + }, + "ethereum-mainnet-optimism-1": { + "allowListEnabled": false, + "decimals": 8, + "name": "uniBTC", + "pool": { + "address": "0x99D94f528CeA3eE1791ab7B476A1FACb4297CA17", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "uniBTC", "tokenAddress": "0x93919784C523f39CACaa98Ee0a9d96c3F32b593e" }, "ethereum-mainnet-unichain-1": { "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x30782053a09599eE44C054075A36c4CA1B224Be5", - "poolType": "burnMint", + "pool": { + "address": "0x30782053a09599eE44C054075A36c4CA1B224Be5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "uniBTC", "tokenAddress": "0xd3c8dA379d71a33BfEE8875F87Ac2748bEB1d58d" }, @@ -5718,8 +8824,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x5aE00CB3da6d11d525dd7AE288673f3BCB992526", - "poolType": "burnMint", + "pool": { + "address": "0x5aE00CB3da6d11d525dd7AE288673f3BCB992526", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "uniBTC", "tokenAddress": "0xd3c8dA379d71a33BfEE8875F87Ac2748bEB1d58d" }, @@ -5727,8 +8837,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0xda57087632409A30876e978450De23A2f55ADA91", - "poolType": "burnMint", + "pool": { + "address": "0xda57087632409A30876e978450De23A2f55ADA91", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "uniBTC", "tokenAddress": "0xF9775085d726E782E83585033B58606f7731AB18" }, @@ -5736,8 +8850,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x1689C22eD5435e49071CFc208D1Ac6F2A2274490", - "poolType": "burnMint", + "pool": { + "address": "0x1689C22eD5435e49071CFc208D1Ac6F2A2274490", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "uniBTC", "tokenAddress": "0x004E9C3EF86bc1ca1f0bB5C7662861Ee93350568" }, @@ -5745,8 +8863,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "A8qxRKqAftbqatfegeiq3yTVmVTPS9DimGWHtgzjC417", - "poolType": "burnMint", + "pool": { + "address": "A8qxRKqAftbqatfegeiq3yTVmVTPS9DimGWHtgzjC417", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "uniBTC", "tokenAddress": "uniBKsEV37qLRFZD7v3Z9drX6voyiCM8WcaePqeSSLc" }, @@ -5754,8 +8876,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0x22134617Ae0f6CA8D89451e5Ae091c94f7D743DC", - "poolType": "burnMint", + "pool": { + "address": "0x22134617Ae0f6CA8D89451e5Ae091c94f7D743DC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "uniBTC", "tokenAddress": "0xC3827A4BC8224ee2D116637023b124CED6db6e90" }, @@ -5763,8 +8889,12 @@ "allowListEnabled": false, "decimals": 8, "name": "uniBTC", - "poolAddress": "0xA7ee087c961A22aa25eDdaB9c0b43b4a39EAd5ea", - "poolType": "burnMint", + "pool": { + "address": "0xA7ee087c961A22aa25eDdaB9c0b43b4a39EAd5ea", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "uniBTC", "tokenAddress": "0xF9775085d726E782E83585033B58606f7731AB18" } @@ -5774,8 +8904,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Unio Coin", - "poolAddress": "0x5eD97E6938D4074CdFC83a310de2525F0a4e6c73", - "poolType": "burnMint", + "pool": { + "address": "0x5eD97E6938D4074CdFC83a310de2525F0a4e6c73", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "UNIO", "tokenAddress": "0x01aaC2b594F7bdBeC740F0F1AA22910EbB4B74Ab" }, @@ -5783,8 +8917,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Unio Coin", - "poolAddress": "0x8AA50883f5f62EB081D16c90FdAdAD9E227206c6", - "poolType": "burnMint", + "pool": { + "address": "0x8AA50883f5f62EB081D16c90FdAdAD9E227206c6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "UNIO", "tokenAddress": "0x01aaC2b594F7bdBeC740F0F1AA22910EbB4B74Ab" }, @@ -5792,8 +8930,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Unio Coin", - "poolAddress": "0xc576D83eA5D672E220f7B099827E73685Fde5B73", - "poolType": "burnMint", + "pool": { + "address": "0xc576D83eA5D672E220f7B099827E73685Fde5B73", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "UNIO", "tokenAddress": "0x01aaC2b594F7bdBeC740F0F1AA22910EbB4B74Ab" } @@ -5803,8 +8945,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Usagi", - "poolAddress": "0x7c458207b7b0E4Eca3c54f3353b2dB00A81a04aA", - "poolType": "burnMint", + "pool": { + "address": "0x7c458207b7b0E4Eca3c54f3353b2dB00A81a04aA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USAGI", "tokenAddress": "0x760295AA772671f21cd0046d094938d09f2b380D" }, @@ -5812,8 +8958,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Usagi", - "poolAddress": "0xC488be11a33c20bd21f7940D4a5937E8A8c81fEc", - "poolType": "lockRelease", + "pool": { + "address": "0xC488be11a33c20bd21f7940D4a5937E8A8c81fEc", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "USAGI", "tokenAddress": "0x3a1adB8Ef2a37Fe127Aa62B2Fc0399a4A6AD9D79" } @@ -5823,8 +8973,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD+", - "poolAddress": "0x1a1079CBA4bf83Ef2D90997360231F9599800fB5", - "poolType": "burnMint", + "pool": { + "address": "0x1a1079CBA4bf83Ef2D90997360231F9599800fB5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USD+", "tokenAddress": "0xfc90518D5136585ba45e34ED5E1D108BD3950CFa" }, @@ -5832,8 +8986,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD+", - "poolAddress": "0x1e88d63b8805C36f96C530c37bde113361aC6Cc0", - "poolType": "burnMint", + "pool": { + "address": "0x1e88d63b8805C36f96C530c37bde113361aC6Cc0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USD+", "tokenAddress": "0x98C6616F1CC0D3E938A16200830DD55663dd7DD3" }, @@ -5841,8 +8999,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD+", - "poolAddress": "0xCE8342b8eFd4D804B97Df92bC6bb930099098fDE", - "poolType": "burnMint", + "pool": { + "address": "0xCE8342b8eFd4D804B97Df92bC6bb930099098fDE", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USD+", "tokenAddress": "0x98C6616F1CC0D3E938A16200830DD55663dd7DD3" } @@ -5852,8 +9014,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Usual USD", - "poolAddress": "0x8d20F295518B12E63F65aB7cf930AD88e8d17cbA", - "poolType": "burnMint", + "pool": { + "address": "0x8d20F295518B12E63F65aB7cf930AD88e8d17cbA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USD0", "tokenAddress": "0x758a3e0b1F842C9306B783f8A4078C6C8C03a270" }, @@ -5861,8 +9027,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Usual USD", - "poolAddress": "0x8d20F295518B12E63F65aB7cf930AD88e8d17cbA", - "poolType": "burnMint", + "pool": { + "address": "0x8d20F295518B12E63F65aB7cf930AD88e8d17cbA", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USD0", "tokenAddress": "0x758a3e0b1F842C9306B783f8A4078C6C8C03a270" }, @@ -5870,8 +9040,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Usual USD", - "poolAddress": "0xC3d39B77032114c8884276Dae0F02cdF75162782", - "poolType": "lockRelease", + "pool": { + "address": "0xC3d39B77032114c8884276Dae0F02cdF75162782", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "USD0", "tokenAddress": "0x73A15FeD60Bf67631dC6cd7Bc5B6e8da8190aCF5" } @@ -5881,8 +9055,12 @@ "allowListEnabled": false, "decimals": 18, "name": "World Liberty Financial USD", - "poolAddress": "0xEC1276CA704c612A28cb2C873dEdCEba97F65cED", - "poolType": "burnMint", + "pool": { + "address": "0xEC1276CA704c612A28cb2C873dEdCEba97F65cED", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USD1", "tokenAddress": "0x111111d2bf19e43C34263401e0CAd979eD1cdb61" }, @@ -5890,8 +9068,12 @@ "allowListEnabled": false, "decimals": 6, "name": "World Liberty Financial USD", - "poolAddress": "0x1eb155d08acc900954b6ccee01659b390399ae81ad4c582b73d41374c475caf6", - "poolType": "burnMint", + "pool": { + "address": "0x1eb155d08acc900954b6ccee01659b390399ae81ad4c582b73d41374c475caf6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "USD1", "tokenAddress": "0x05fabd1b12e39967a3c24e91b7b8f67719a6dacee74f3c8b9fb7d93e855437d2" }, @@ -5899,26 +9081,73 @@ "allowListEnabled": false, "decimals": 18, "name": "World Liberty Financial USD", - "poolAddress": "0xCe3f7378aE409e1CE0dD6fFA70ab683326b73f04", - "poolType": "burnMint", + "pool": { + "address": "0xCe3f7378aE409e1CE0dD6fFA70ab683326b73f04", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USD1", "tokenAddress": "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d" }, - "mainnet": { + "ethereum-mainnet-mantle-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "World Liberty Financial USD", + "pool": { + "address": "0xf58A2e303e519f6A1b772137995871967e30391a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "USD1", + "tokenAddress": "0x111111d2bf19e43C34263401e0CAd979eD1cdb61" + }, + "ethereum-mainnet-xlayer-1": { "allowListEnabled": false, "decimals": 18, "name": "World Liberty Financial USD", - "poolAddress": "0x36a72eD0096B414521C45E3ddC9ed657d1D9c141", + "poolAddress": "0x500E140CCb4Ca279aCF585cc53C4613a7D7BCF27", "poolType": "burnMint", "symbol": "USD1", + "tokenAddress": "0x111111d2bf19e43C34263401e0CAd979eD1cdb61" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "World Liberty Financial USD", + "pool": { + "address": "0x36a72eD0096B414521C45E3ddC9ed657d1D9c141", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "USD1", "tokenAddress": "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d" }, "monad-mainnet": { "allowListEnabled": false, "decimals": 6, "name": "World Liberty Financial USD", - "poolAddress": "0x5258D5BEB800DF857D8A4e808EE0C8c7bF567e0E", - "poolType": "burnMint", + "pool": { + "address": "0x5258D5BEB800DF857D8A4e808EE0C8c7bF567e0E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "USD1", + "tokenAddress": "0x111111d2bf19e43C34263401e0CAd979eD1cdb61" + }, + "morph-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "World Liberty Financial USD", + "pool": { + "address": "0x258Fc917b8de98b4aA0d38776E95dcce9e7EC8aC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USD1", "tokenAddress": "0x111111d2bf19e43C34263401e0CAd979eD1cdb61" }, @@ -5926,10 +9155,27 @@ "allowListEnabled": false, "decimals": 18, "name": "World Liberty Financial USD", - "poolAddress": "0x770318D51052871DeF5Eb5c452F4fd28B7960C4e", - "poolType": "burnMint", + "pool": { + "address": "0x770318D51052871DeF5Eb5c452F4fd28B7960C4e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "USD1", "tokenAddress": "0x111111d2bf19e43C34263401e0CAd979eD1cdb61" + }, + "solana-mainnet": { + "allowListEnabled": false, + "decimals": 6, + "name": "World Liberty Financial USD", + "pool": { + "address": "B4PB9qWUW6R18Gbpk5Km8mJ2GoQgCcVpgdqhU7C2n8fh", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, + "symbol": "USD1", + "tokenAddress": "USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB" } }, "USDC": { @@ -5937,8 +9183,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Bridged USDC", - "poolAddress": "0x0A3d8eD619ECF1E984488710eB2cEcE4FDbd83CA", - "poolType": "burnMint", + "pool": { + "address": "0x0A3d8eD619ECF1E984488710eB2cEcE4FDbd83CA", + "rawType": "usdc", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDC.e", "tokenAddress": "0x1f3AA82227281cA364bFb3d253B0f1af1Da6473E" }, @@ -5946,8 +9196,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "0x966519C334D895121B61584CAdeBc15571b62983", - "poolType": "usdc", + "pool": { + "address": "0x966519C334D895121B61584CAdeBc15571b62983", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.1" + }, "symbol": "USDC", "tokenAddress": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E" }, @@ -5955,8 +9209,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "0xff170aD8f1d86eFAC90CA7a2E1204bA64aC5e0f9", - "poolType": "burnMint", + "pool": { + "address": "0xff170aD8f1d86eFAC90CA7a2E1204bA64aC5e0f9", + "rawType": "usdc", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDC", "tokenAddress": "0xf8C374CE88A3BE3d374e8888349C7768B607c755" }, @@ -5964,8 +9222,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Bridged USDC (BOB)", - "poolAddress": "0x554652E7F10fB8aa3e12226213c6826F98B09CF0", - "poolType": "burnMint", + "pool": { + "address": "0x554652E7F10fB8aa3e12226213c6826F98B09CF0", + "rawType": "usdc", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDC.e", "tokenAddress": "0xe75D0fB2C24A55cA1e3F96781a2bCC7bdba058F0" }, @@ -5973,8 +9235,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "0x40530f5305d6Fd6912925C5ec2C36453B85d8F5f", - "poolType": "usdc", + "pool": { + "address": "0x40530f5305d6Fd6912925C5ec2C36453B85d8F5f", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.1" + }, "symbol": "USDC", "tokenAddress": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" }, @@ -5982,8 +9248,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "0x6378c36C44B28f4d1513e7a5510A8481a23eecda", - "poolType": "usdc", + "pool": { + "address": "0x6378c36C44B28f4d1513e7a5510A8481a23eecda", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.0" + }, "symbol": "USDC", "tokenAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" }, @@ -5991,8 +9261,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "0xE67E30B1b4F80A35852488757C3efc093903651A", - "poolType": "usdc", + "pool": { + "address": "0xE67E30B1b4F80A35852488757C3efc093903651A", + "rawType": "Usdc", + "type": "usdc", + "version": "1.6.1" + }, "symbol": "USDC", "tokenAddress": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" }, @@ -6000,8 +9274,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USDC", - "poolAddress": "0xf58A2e303e519f6A1b772137995871967e30391a", - "poolType": "usdc", + "pool": { + "address": "0xf58A2e303e519f6A1b772137995871967e30391a", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.1" + }, "symbol": "USDC", "tokenAddress": "0x078D782b760474a361dDA0AF3839290b0EF57AD6" }, @@ -6009,8 +9287,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "0x03D19033AdA17750D5BC2d8E325337D0748F9FEF", - "poolType": "usdc", + "pool": { + "address": "0x03D19033AdA17750D5BC2d8E325337D0748F9FEF", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.0" + }, "symbol": "USDC", "tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" }, @@ -6018,8 +9300,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "0x60A97bd9ACf755954Ff0fE85837224f2920a57F3", - "poolType": "usdc", + "pool": { + "address": "0x60A97bd9ACf755954Ff0fE85837224f2920a57F3", + "rawType": "Usdc", + "type": "usdc", + "version": "1.6.1" + }, "symbol": "USDC", "tokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359" }, @@ -6027,8 +9313,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "0xe26D9c68cF6d284367C5e90EC834C6Ec0051f73C", - "poolType": "burnMint", + "pool": { + "address": "0xe26D9c68cF6d284367C5e90EC834C6Ec0051f73C", + "rawType": "usdc", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USDC", "tokenAddress": "0x0B7007c13325C48911F73A2daD5FA5dCBf808aDc" }, @@ -6036,8 +9326,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "Gog2wHG7KS8St26d1fPrgNFtta6HK8Xza7SSHzgbWPr5", - "poolType": "usdc", + "pool": { + "address": "Gog2wHG7KS8St26d1fPrgNFtta6HK8Xza7SSHzgbWPr5", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.0" + }, "symbol": "USDC", "tokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }, @@ -6045,8 +9339,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Bridged USDC", - "poolAddress": "0x5937c7096b054564c6F17B7e61D9Abf1256B0593", - "poolType": "burnMint", + "pool": { + "address": "0x5937c7096b054564c6F17B7e61D9Abf1256B0593", + "rawType": "usdc", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USDC.e", "tokenAddress": "0x44bB111010DfFfb3695F9a1B66aa879976199e7b" } @@ -6056,17 +9354,34 @@ "allowListEnabled": false, "decimals": 18, "name": "Falcon USD", - "poolAddress": "0x4b66431F9E5f5Cd026ae48E617902207b43048D4", - "poolType": "burnMint", + "pool": { + "address": "0x4b66431F9E5f5Cd026ae48E617902207b43048D4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "USDf", "tokenAddress": "0xb3b02E4A9Fb2bD28CC2ff97B0aB3F6B3Ec1eE9D2" }, + "ethereum-mainnet-base-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "Falcon USD", + "poolAddress": "0x33570299e0D73f07c82d005DE75De54cf4582FCC", + "poolType": "burnMint", + "symbol": "USDf", + "tokenAddress": "0x8210c0634AB8f273806e4b7866E9Db353773c44B" + }, "mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Falcon USD", - "poolAddress": "0xEcf61D6fAA3B9faE7195AF3bc9891450C1733f78", - "poolType": "lockRelease", + "pool": { + "address": "0xEcf61D6fAA3B9faE7195AF3bc9891450C1733f78", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "USDf", "tokenAddress": "0xFa2B947eEc368f42195f24F36d2aF29f7c24CeC2" }, @@ -6074,8 +9389,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Falcon USD", - "poolAddress": "0x33570299e0D73f07c82d005DE75De54cf4582FCC", - "poolType": "burnMint", + "pool": { + "address": "0x33570299e0D73f07c82d005DE75De54cf4582FCC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USDf", "tokenAddress": "0x8210c0634AB8f273806e4b7866E9Db353773c44B" } @@ -6085,8 +9404,12 @@ "allowListEnabled": false, "decimals": 18, "name": "USDFI", - "poolAddress": "0xDB96110a1d4c447055c71227CE5908AF859c1015", - "poolType": "burnMint", + "pool": { + "address": "0xDB96110a1d4c447055c71227CE5908AF859c1015", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDFI", "tokenAddress": "0xC9f5955f6dA20e44A068f3d58FB2404f56f9a6f2" }, @@ -6094,8 +9417,12 @@ "allowListEnabled": false, "decimals": 18, "name": "USDFI", - "poolAddress": "0x28B57510597c1629ec76f95A2DAcD579e18f1436", - "poolType": "burnMint", + "pool": { + "address": "0x28B57510597c1629ec76f95A2DAcD579e18f1436", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USDFI", "tokenAddress": "0x249c48e22E95514Ca975De31f473F30c2f3C0916" }, @@ -6103,8 +9430,12 @@ "allowListEnabled": false, "decimals": 18, "name": "USDFI", - "poolAddress": "0xE727F7975bEF908C49D0591724669F05F7dAd811", - "poolType": "burnMint", + "pool": { + "address": "0xE727F7975bEF908C49D0591724669F05F7dAd811", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "USDFI", "tokenAddress": "0xa7a0B3Fe94121E366D774d60D075F6386F750884" } @@ -6114,8 +9445,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Mountain Protocol USD", - "poolAddress": "0x6a1252A0e3100fDFC3Fe65aE43D6829b6d2125Ba", - "poolType": "burnMint", + "pool": { + "address": "0x6a1252A0e3100fDFC3Fe65aE43D6829b6d2125Ba", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDM", "tokenAddress": "0x59D9356E565Ab3A36dD77763Fc0d87fEaf85508C" }, @@ -6123,8 +9458,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Mountain Protocol USD", - "poolAddress": "0x0723Bd0CE11cCFFa3D8bd1649011195fD38EF21E", - "poolType": "burnMint", + "pool": { + "address": "0x0723Bd0CE11cCFFa3D8bd1649011195fD38EF21E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDM", "tokenAddress": "0x59D9356E565Ab3A36dD77763Fc0d87fEaf85508C" }, @@ -6132,8 +9471,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Mountain Protocol USD", - "poolAddress": "0x4109f7E577596432458F8D4DC2E78637428D5614", - "poolType": "burnMint", + "pool": { + "address": "0x4109f7E577596432458F8D4DC2E78637428D5614", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDM", "tokenAddress": "0x59D9356E565Ab3A36dD77763Fc0d87fEaf85508C" }, @@ -6141,8 +9484,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Mountain Protocol USD", - "poolAddress": "0x028A4Caa308883170C024AcfC367B8B627EceeCb", - "poolType": "burnMint", + "pool": { + "address": "0x028A4Caa308883170C024AcfC367B8B627EceeCb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USDM", "tokenAddress": "0x59D9356E565Ab3A36dD77763Fc0d87fEaf85508C" }, @@ -6150,8 +9497,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Mountain Protocol USD", - "poolAddress": "0x70139902BC147754221FD59DFf8f8A16b34876F8", - "poolType": "burnMint", + "pool": { + "address": "0x70139902BC147754221FD59DFf8f8A16b34876F8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDM", "tokenAddress": "0x7715c206A14Ac93Cb1A6c0316A6E5f8aD7c9Dc31" }, @@ -6159,8 +9510,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Mountain Protocol USD", - "poolAddress": "0x4109f7E577596432458F8D4DC2E78637428D5614", - "poolType": "burnMint", + "pool": { + "address": "0x4109f7E577596432458F8D4DC2E78637428D5614", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USDM", "tokenAddress": "0x59D9356E565Ab3A36dD77763Fc0d87fEaf85508C" }, @@ -6168,8 +9523,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Mountain Protocol USD", - "poolAddress": "0xA2492283F3016b078129290BAf5293Aea4f9ae48", - "poolType": "burnMint", + "pool": { + "address": "0xA2492283F3016b078129290BAf5293Aea4f9ae48", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "USDM", "tokenAddress": "0x59D9356E565Ab3A36dD77763Fc0d87fEaf85508C" } @@ -6179,8 +9538,12 @@ "allowListEnabled": false, "decimals": 18, "name": "OpenEden Open Dollar", - "poolAddress": "0x500d4882938020E939a5666c1B4200873da7EfD3", - "poolType": "burnMint", + "pool": { + "address": "0x500d4882938020E939a5666c1B4200873da7EfD3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USDO", "tokenAddress": "0x302e52AFf9815B9D1682473DBFB9C74F9B750AA8" }, @@ -6188,8 +9551,12 @@ "allowListEnabled": false, "decimals": 18, "name": "OpenEden Open Dollar", - "poolAddress": "0x500d4882938020E939a5666c1B4200873da7EfD3", - "poolType": "burnMint", + "pool": { + "address": "0x500d4882938020E939a5666c1B4200873da7EfD3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDO", "tokenAddress": "0xaD55aebc9b8c03FC43cd9f62260391c13c23e7c0" }, @@ -6197,8 +9564,12 @@ "allowListEnabled": false, "decimals": 18, "name": "OpenEden Open Dollar", - "poolAddress": "0x017566aAD2C164011b9c6552Df3Eb7a8c5c11590", - "poolType": "burnMint", + "pool": { + "address": "0x017566aAD2C164011b9c6552Df3Eb7a8c5c11590", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "USDO", "tokenAddress": "0x87e617C7484aDE79FcD90db58BEB82B057facb48" }, @@ -6206,8 +9577,12 @@ "allowListEnabled": false, "decimals": 18, "name": "OpenEden Open Dollar", - "poolAddress": "0x500d4882938020E939a5666c1B4200873da7EfD3", - "poolType": "burnMint", + "pool": { + "address": "0x500d4882938020E939a5666c1B4200873da7EfD3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USDO", "tokenAddress": "0x8238884Ec9668Ef77B90C6dfF4D1a9F4F4823BFe" } @@ -6217,8 +9592,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenUSDT", - "poolAddress": "0xd7502CaBdb70c79382deF58FB6df3CdA69cb2A1b", - "poolType": "burnMint", + "pool": { + "address": "0xd7502CaBdb70c79382deF58FB6df3CdA69cb2A1b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "oUSDT", "tokenAddress": "0x1217BfE6c773EEC6cc4A38b5Dc45B92292B6E189" }, @@ -6226,8 +9605,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Tether USD", - "poolAddress": "0x2c3D51c7B454cB045C8cEc92d2F9E717C7519106", - "poolType": "burnMint", + "pool": { + "address": "0x2c3D51c7B454cB045C8cEc92d2F9E717C7519106", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USDT", "tokenAddress": "0xfe9f969faf8Ad72a83b761138bF25dE87eFF9DD2" }, @@ -6235,8 +9618,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenUSDT", - "poolAddress": "0xAFEd606Bd2CAb6983fC6F10167c98aaC2173D77f", - "poolType": "burnMint", + "pool": { + "address": "0xAFEd606Bd2CAb6983fC6F10167c98aaC2173D77f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "oUSDT", "tokenAddress": "0x1217BfE6c773EEC6cc4A38b5Dc45B92292B6E189" }, @@ -6244,8 +9631,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenUSDT", - "poolAddress": "0x0EEFa8b75587bcD4A909a0F3c36180D4441481a0", - "poolType": "burnMint", + "pool": { + "address": "0x0EEFa8b75587bcD4A909a0F3c36180D4441481a0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "oUSDT", "tokenAddress": "0x1217BfE6c773EEC6cc4A38b5Dc45B92292B6E189" }, @@ -6253,8 +9644,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Tether USD", - "poolAddress": "0x47Db76c9c97F4bcFd54D8872FDb848Cab696092d", - "poolType": "burnMint", + "pool": { + "address": "0x47Db76c9c97F4bcFd54D8872FDb848Cab696092d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USD₮", "tokenAddress": "0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e" }, @@ -6262,8 +9657,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenUSDT", - "poolAddress": "0xa760D20a91C076A57b270D3F7a3150421ab40591", - "poolType": "burnMint", + "pool": { + "address": "0xa760D20a91C076A57b270D3F7a3150421ab40591", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "oUSDT", "tokenAddress": "0x1217BfE6c773EEC6cc4A38b5Dc45B92292B6E189" }, @@ -6271,8 +9670,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenUSDT", - "poolAddress": "0x55aeb80Aa6Ab34aA83E1F387903F8Bb2Aa9e2F2d", - "poolType": "burnMint", + "pool": { + "address": "0x55aeb80Aa6Ab34aA83E1F387903F8Bb2Aa9e2F2d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "oUSDT", "tokenAddress": "0x1217BfE6c773EEC6cc4A38b5Dc45B92292B6E189" }, @@ -6280,8 +9683,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenUSDT", - "poolAddress": "0x6a21a19aD44542d83F7f7FF45Aa31A62a36200de", - "poolType": "burnMint", + "pool": { + "address": "0x6a21a19aD44542d83F7f7FF45Aa31A62a36200de", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "oUSDT", "tokenAddress": "0x1217BfE6c773EEC6cc4A38b5Dc45B92292B6E189" }, @@ -6289,8 +9696,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Tether USD", - "poolAddress": "0xa3532633401AbFfbd15e6be825a45FB7F141469B", - "poolType": "lockRelease", + "pool": { + "address": "0xa3532633401AbFfbd15e6be825a45FB7F141469B", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "USDT", "tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7" }, @@ -6298,8 +9709,12 @@ "allowListEnabled": false, "decimals": 6, "name": "OpenUSDT", - "poolAddress": "0x6a21a19aD44542d83F7f7FF45Aa31A62a36200de", - "poolType": "burnMint", + "pool": { + "address": "0x6a21a19aD44542d83F7f7FF45Aa31A62a36200de", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "oUSDT", "tokenAddress": "0x1217BfE6c773EEC6cc4A38b5Dc45B92292B6E189" } @@ -6309,8 +9724,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USELESS COIN", - "poolAddress": "0x6378c36C44B28f4d1513e7a5510A8481a23eecda", - "poolType": "burnMint", + "pool": { + "address": "0x6378c36C44B28f4d1513e7a5510A8481a23eecda", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USELESS", "tokenAddress": "0xbA38B3C706f7A515Ff7C8Db04Daa0A134eC46D2b" }, @@ -6318,8 +9737,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USELESS COIN", - "poolAddress": "Aunb4sACHkdsqvb5eDHngkPLNLhnA42YUMosFMYDV5pG", - "poolType": "lockRelease", + "pool": { + "address": "Aunb4sACHkdsqvb5eDHngkPLNLhnA42YUMosFMYDV5pG", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "USELESS", "tokenAddress": "Dz9mQ9NzkBcCsuGPFJ3r1bS4wgqKMHBPiVuniW8Mbonk" } @@ -6329,8 +9752,12 @@ "allowListEnabled": false, "decimals": 18, "name": "USUAL", - "poolAddress": "0x30Ea2d525eF7C234F8AA6E3a8909B88f71244cB0", - "poolType": "burnMint", + "pool": { + "address": "0x30Ea2d525eF7C234F8AA6E3a8909B88f71244cB0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "USUAL", "tokenAddress": "0x4ACD4D03af6F9cc0fB7C5f0868B7b6287D7969c5" }, @@ -6338,8 +9765,12 @@ "allowListEnabled": false, "decimals": 18, "name": "USUAL", - "poolAddress": "0x30Ea2d525eF7C234F8AA6E3a8909B88f71244cB0", - "poolType": "burnMint", + "pool": { + "address": "0x30Ea2d525eF7C234F8AA6E3a8909B88f71244cB0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "USUAL", "tokenAddress": "0x4ACD4D03af6F9cc0fB7C5f0868B7b6287D7969c5" }, @@ -6347,8 +9778,12 @@ "allowListEnabled": false, "decimals": 18, "name": "USUAL", - "poolAddress": "0x72a0203b731EdECE2DdAa506a048c0378C44366a", - "poolType": "lockRelease", + "pool": { + "address": "0x72a0203b731EdECE2DdAa506a048c0378C44366a", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "USUAL", "tokenAddress": "0xC4441c2BE5d8fA8126822B9929CA0b81Ea0DE38E" } @@ -6358,8 +9793,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USX Stablecoin", - "poolAddress": "0x193Beb1E11731B8B740b9fbbB62655553c3b4A25", - "poolType": "burnMint", + "pool": { + "address": "0x193Beb1E11731B8B740b9fbbB62655553c3b4A25", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "USX", "tokenAddress": "0xad1493B01ced4fAAc409124E667b95259F12fb05" }, @@ -6367,8 +9806,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USX", - "poolAddress": "BhqsAa1yib3KqRTDX9WfyuKQtwikoUiDNJTLYgNwBtR6", - "poolType": "lockRelease", + "pool": { + "address": "BhqsAa1yib3KqRTDX9WfyuKQtwikoUiDNJTLYgNwBtR6", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "USX", "tokenAddress": "6FrrzDk5mQARGc1TDYoyVnSyRdds1t4PbtohCD6p3tgG" } @@ -6378,17 +9821,34 @@ "allowListEnabled": false, "decimals": 18, "name": "VOOI", - "poolAddress": "0x4D275A287B86E423E01CceE66F4e3313B5F47Cf7", - "poolType": "burnMint", + "pool": { + "address": "0x4D275A287B86E423E01CceE66F4e3313B5F47Cf7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "VOOI", "tokenAddress": "0x876cEcb73c9ED1B1526F8e35C6a5a51a31BCF341" }, + "ethereum-mainnet-mantle-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "VOOI", + "poolAddress": "0xE43F2F7A4A6010AC3C07B06081Dfbf0255137912", + "poolType": "burnMint", + "symbol": "VOOI", + "tokenAddress": "0xd81a4aDea9932a6BDba0bDBc8C5Fd4C78e5A09f1" + }, "mainnet": { "allowListEnabled": false, "decimals": 18, "name": "VOOI", - "poolAddress": "0x8B8461F822FDb00943C2c7d42aa17e1CDd5626F1", - "poolType": "lockRelease", + "pool": { + "address": "0x8B8461F822FDb00943C2c7d42aa17e1CDd5626F1", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "VOOI", "tokenAddress": "0xb31561F0e2aaC72406103b1926356D756F07A481" } @@ -6398,8 +9858,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vertex", - "poolAddress": "0xF68fC9ccE79df9719c9801d345fFA38ecDCcad35", - "poolType": "burnMint", + "pool": { + "address": "0xF68fC9ccE79df9719c9801d345fFA38ecDCcad35", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "VRTX", "tokenAddress": "0xFd91eD44Fc13f7FAFF758FE6d339d5790C4a85eC" }, @@ -6407,8 +9871,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vertex", - "poolAddress": "0x387E40Ed22Ee3396288c874411B00C48f6978653", - "poolType": "lockRelease", + "pool": { + "address": "0x387E40Ed22Ee3396288c874411B00C48f6978653", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "VRTX", "tokenAddress": "0x95146881b86B3ee99e63705eC87AfE29Fcc044D9" }, @@ -6416,8 +9884,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vertex", - "poolAddress": "0xCaf4E8ED1cbdD5FB9B1359e98d9185dafE01B943", - "poolType": "burnMint", + "pool": { + "address": "0xCaf4E8ED1cbdD5FB9B1359e98d9185dafE01B943", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "VRTX", "tokenAddress": "0xFB0c734Fc3008683c5efF45bcf8128836C4D97D0" }, @@ -6425,8 +9897,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vertex", - "poolAddress": "0xdF7F1eb75E0Ae7E4867F06dF3344abcd852C6D23", - "poolType": "burnMint", + "pool": { + "address": "0xdF7F1eb75E0Ae7E4867F06dF3344abcd852C6D23", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "VRTX", "tokenAddress": "0x6CD20f11470e9C9d1458a69c8f7B330B99577EF9" }, @@ -6434,8 +9910,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vertex", - "poolAddress": "0x06Aa321d88e5bc62Ca86c54342cAeFa6F19FE526", - "poolType": "burnMint", + "pool": { + "address": "0x06Aa321d88e5bc62Ca86c54342cAeFa6F19FE526", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "VRTX", "tokenAddress": "0xd0728F5b1F53A834F8dcd1B86f62CeB8726eb0a0" }, @@ -6443,8 +9923,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vertex", - "poolAddress": "0x826Ba9cF4FE04c73A9750aD88B21b6daCb456516", - "poolType": "burnMint", + "pool": { + "address": "0x826Ba9cF4FE04c73A9750aD88B21b6daCb456516", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "VRTX", "tokenAddress": "0x5B8034F6346A81a1387EA21CDD36c48f6e05eb5f" }, @@ -6452,8 +9936,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vertex", - "poolAddress": "0x293325B3AacE7322BeB03400e302612A2FC5A4E8", - "poolType": "burnMint", + "pool": { + "address": "0x293325B3AacE7322BeB03400e302612A2FC5A4E8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "VRTX", "tokenAddress": "0xAd747e3CF4e31B8897B96C81C6C74152De52f614" } @@ -6463,8 +9951,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vision", - "poolAddress": "0x649f03D6F7ac74F6C13733212Aa5419c890d2db6", - "poolType": "burnMint", + "pool": { + "address": "0x649f03D6F7ac74F6C13733212Aa5419c890d2db6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "VSN", "tokenAddress": "0x699Ccf919C1dfdFa4C374292f42CAdC9899BF753" }, @@ -6472,8 +9964,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vision", - "poolAddress": "0x96db781A7EF341dA5ca348Ece4B824b3AdC71D55", - "poolType": "burnMint", + "pool": { + "address": "0x96db781A7EF341dA5ca348Ece4B824b3AdC71D55", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "VSN", "tokenAddress": "0x6fBBbD8bFB1cd3986B1D05e7861a0f62F87DB74b" }, @@ -6481,8 +9977,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vision", - "poolAddress": "0x1bb58BA8B6fc5a779EDB2D6421c330d464183c08", - "poolType": "burnMint", + "pool": { + "address": "0x1bb58BA8B6fc5a779EDB2D6421c330d464183c08", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "VSN", "tokenAddress": "0x31185950db028eCFc70DF6a35a4B552462A35773" }, @@ -6490,8 +9990,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Vision", - "poolAddress": "0x3DAa89A5AB49DBa691FEA66EB89aC8Cf8BeE2e35", - "poolType": "burnMint", + "pool": { + "address": "0x3DAa89A5AB49DBa691FEA66EB89aC8Cf8BeE2e35", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "VSN", "tokenAddress": "0x699Ccf919C1dfdFa4C374292f42CAdC9899BF753" } @@ -6501,9 +10005,80 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped 0G", - "poolType": "feeTokenOnly", + "pool": { + "address": "0xF6839B313671daE8c1B6AbCaB4eBd0bF41259187", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "W0G", "tokenAddress": "0x1Cd0690fF9a693f5EF2dD976660a8dAFc81A109c" + }, + "bsc-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped 0G", + "poolAddress": "0x467721aD1f05235b84b6c94E012b12C79d9EbfD7", + "poolType": "burnMint", + "symbol": "W0G", + "tokenAddress": "0x2C2d4d99F95643C8EC2EbD1d73a6Fd0273068B1e" + }, + "ethereum-mainnet-arbitrum-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped 0G", + "pool": { + "address": "0x22fF19A7307eee6bd6d38C569f8bcb40fD071Ff4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "W0G", + "tokenAddress": "0x418176040912d11d9445dd4AEc322772A42f2a59" + }, + "ethereum-mainnet-base-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped 0G", + "pool": { + "address": "0x049DF7Ed53037C58BCAB45510c153D5CD5564830", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "W0G", + "tokenAddress": "0x23cd099eB438CcA50349EE2BC809196b1ae00861" + }, + "mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped 0G", + "pool": { + "address": "0xE25a97E9e2f1Eeee81d4a7986A018AC3Ae8D857b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "W0G", + "tokenAddress": "0x4C1Dab3Be86347977F3DfC4b9688224ef2272939" + }, + "monad-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped 0G", + "poolAddress": "0x4c8A1e94C84f9043E26b3bBFf76F670A91e645A1", + "poolType": "burnMint", + "symbol": "W0G", + "tokenAddress": "0xB267Cc10fa4c54dB1fD5A6e9cAFbB98C16cC9b97" + }, + "solana-mainnet": { + "allowListEnabled": false, + "decimals": 9, + "name": "Wrapped 0G", + "poolAddress": "4owiysYefgqx68wtTzED1tm6QhtcSKKJBgKmwRMbccNZ", + "poolType": "burnMint", + "symbol": "W0G", + "tokenAddress": "gNyJyS9pQt33o4y4L3gdWZAF2XHgPrCBRQuaiCZStMe" } }, "WAB": { @@ -6511,7 +10086,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped AB", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WAB", "tokenAddress": "0x51dA03503FBBA94B9d0D88C15690D840F02F15F4" } @@ -6521,7 +10100,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped ApeCoin", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WAPE", "tokenAddress": "0x48b62137EdfA95a428D35C09E44256a739F6B557" } @@ -6531,8 +10114,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Astar Token", - "poolAddress": "0x98ef4B1Fe8fe9C73Deb07a77c9f861E8558439d7", - "poolType": "burnMint", + "pool": { + "address": "0x98ef4B1Fe8fe9C73Deb07a77c9f861E8558439d7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "ASTR", "tokenAddress": "0xF27441230EADEaC85B764610325Cc9a0D7859689" }, @@ -6540,8 +10127,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped ASTR", - "poolAddress": "0x99B41d3e1529dF578f02d68c0c11a0Ca89a522d0", - "poolType": "lockRelease", + "pool": { + "address": "0x99B41d3e1529dF578f02d68c0c11a0Ca89a522d0", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "WASTR", "tokenAddress": "0x37795FdD8C165CaB4D6c05771D564d80439CD093" }, @@ -6549,8 +10140,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Astar Token", - "poolAddress": "0x2200B5f4fA30a55359Ef0FaE04890113BD73bd16", - "poolType": "burnMint", + "pool": { + "address": "0x2200B5f4fA30a55359Ef0FaE04890113BD73bd16", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "ASTR", "tokenAddress": "0x2CAE934a1e84F693fbb78CA5ED3B0A6893259441" } @@ -6560,7 +10155,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped AVAX", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WAVAX", "tokenAddress": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7" } @@ -6570,7 +10169,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Bera", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WBERA", "tokenAddress": "0x6969696969696969696969696969696969696969" } @@ -6580,7 +10183,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BNB", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WBNB", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6588,7 +10195,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BNB", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WBNB", "tokenAddress": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c" } @@ -6598,7 +10209,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Shibarium Wrapped BONE", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WBONE", "tokenAddress": "0xC76F4c819D820369Fb2d7C1531aB3Bb18e6fE8d8" } @@ -6608,7 +10223,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BTC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WBTC", "tokenAddress": "0xfF204e2681A6fA0e2C3FaDe68a1B28fb90E4Fc5F" }, @@ -6616,7 +10235,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BTC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WBTC", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6624,7 +10247,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BTC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WBTC", "tokenAddress": "0xF6D226f9Dc15d9bB51182815b320D3fBE324e1bA" }, @@ -6632,8 +10259,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Wrapped BTC", - "poolAddress": "0xF6698064776D521b0AFE469F30C40B39B4875b93", - "poolType": "lockRelease", + "pool": { + "address": "0xF6698064776D521b0AFE469F30C40B39B4875b93", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "WBTC", "tokenAddress": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599" }, @@ -6641,8 +10272,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Wrapped Bitcoin", - "poolAddress": "0x57C6e9E48476B4d08CeAc0ba885D34f7dE71F323", - "poolType": "burnMint", + "pool": { + "address": "0x57C6e9E48476B4d08CeAc0ba885D34f7dE71F323", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "WBTC", "tokenAddress": "0xCa3Eb64F3DFd7861C76070e3d1492eE5ee20cdC3" } @@ -6652,7 +10287,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Bitcorn", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WBTCN", "tokenAddress": "0xda5dDd7270381A7C2717aD10D1c0ecB19e3CDFb2" } @@ -6662,7 +10301,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Celo", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WCELO", "tokenAddress": "0x2021B12D8138e2D63cF0895eccABC0DFc92416c6" } @@ -6672,7 +10315,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped CORE", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WCORE", "tokenAddress": "0x40375C92d9FAf44d2f9db9Bd9ba41a3317a2404f" } @@ -6682,7 +10329,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped CRO", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WCRO", "tokenAddress": "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23" } @@ -6692,8 +10343,12 @@ "allowListEnabled": false, "decimals": 18, "name": "WECOIN", - "poolAddress": "0x9766a4A5c1F7Eacc5D9aAc1086aec62137e81596", - "poolType": "lockRelease", + "pool": { + "address": "0x9766a4A5c1F7Eacc5D9aAc1086aec62137e81596", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "WECO", "tokenAddress": "0x5d37ABAFd5498B0E7af753a2E83bd4F0335AA89F" }, @@ -6701,8 +10356,12 @@ "allowListEnabled": false, "decimals": 18, "name": "WECOIN", - "poolAddress": "0xf327989Ad11388B1fd943C29eE12ba0ed06f5180", - "poolType": "burnMint", + "pool": { + "address": "0xf327989Ad11388B1fd943C29eE12ba0ed06f5180", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WECO", "tokenAddress": "0x44ca3E3649Bf8a905b6B07133BaAc43F1A00fa34" }, @@ -6710,8 +10369,12 @@ "allowListEnabled": false, "decimals": 18, "name": "WECOIN", - "poolAddress": "0x8aC68225b0E80cF7f16EA67639b455d679a158d7", - "poolType": "burnMint", + "pool": { + "address": "0x8aC68225b0E80cF7f16EA67639b455d679a158d7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "WECO", "tokenAddress": "0x54Df3076ac0CdC9bC97fA290AB9c5a88E3D23630" }, @@ -6719,8 +10382,12 @@ "allowListEnabled": false, "decimals": 18, "name": "WECOIN", - "poolAddress": "0x6e2910e4eCFE573a8e351AdAe4a0d9F095a793CC", - "poolType": "burnMint", + "pool": { + "address": "0x6e2910e4eCFE573a8e351AdAe4a0d9F095a793CC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WECO", "tokenAddress": "0x7200e56E62543Ecdba7a7f60A25e305BB88304B5" } @@ -6730,7 +10397,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x3439153EB7AF838Ad19d56E1571FBD09333C2809" }, @@ -6738,8 +10409,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Ethereum Token", - "poolAddress": "0xe96cC12AA0E2e545621bcbE1E035D91a7871fE8f", - "poolType": "burnMint", + "pool": { + "address": "0xe96cC12AA0E2e545621bcbE1E035D91a7871fE8f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "ETH", "tokenAddress": "0xEf63d4E178b3180BeEc9B0E143e0f37F4c93f4C2" }, @@ -6747,7 +10422,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6755,8 +10434,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolAddress": "0xb3deA004d4d23b543934DfFb884d699Ee7C99269", - "poolType": "lockRelease", + "pool": { + "address": "0xb3deA004d4d23b543934DfFb884d699Ee7C99269", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1" }, @@ -6764,8 +10447,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolAddress": "0x0bEB0e87661a15cEEa56D8B7ED99e583459F48bA", - "poolType": "lockRelease", + "pool": { + "address": "0x0bEB0e87661a15cEEa56D8B7ED99e583459F48bA", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6773,7 +10460,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4300000000000000000000000000000000000004" }, @@ -6781,7 +10472,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6789,8 +10484,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolAddress": "0x538dBDcC6902c3fbE109261833c77FA77e8e7f60", - "poolType": "lockRelease", + "pool": { + "address": "0x538dBDcC6902c3fbE109261833c77FA77e8e7f60", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f" }, @@ -6798,7 +10497,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6806,8 +10509,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolAddress": "0x0bEB0e87661a15cEEa56D8B7ED99e583459F48bA", - "poolType": "lockRelease", + "pool": { + "address": "0x0bEB0e87661a15cEEa56D8B7ED99e583459F48bA", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6815,7 +10522,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9" }, @@ -6823,7 +10534,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x5300000000000000000000000000000000000004" }, @@ -6831,7 +10546,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0xA51894664A773981C6C112C43ce576f315d5b1B6" }, @@ -6839,7 +10558,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6847,7 +10570,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6855,7 +10582,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6863,7 +10594,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91" }, @@ -6871,7 +10606,11 @@ "allowListEnabled": false, "decimals": 18, "name": "WETH", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x2e31ebD2eB114943630Db6ba8c7f7687bdA5835F" }, @@ -6879,15 +10618,35 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, + "jovay-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped Ether", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, + "symbol": "WETH", + "tokenAddress": "0xeA29Cbb2808CF848C185E4405Bb002F53f92a241" + }, "lisk-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6895,24 +10654,44 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolAddress": "0x011Ef1fe26D20077A59F38e9Ad155b166AD87D40", - "poolType": "lockRelease", + "pool": { + "address": "0x011Ef1fe26D20077A59F38e9Ad155b166AD87D40", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" }, - "memento-mainnet": { + "megaeth-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", "poolType": "feeTokenOnly", "symbol": "WETH", + "tokenAddress": "0x4200000000000000000000000000000000000006" + }, + "memento-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped Ether", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, + "symbol": "WETH", "tokenAddress": "0x086917568f9317b68595B7552842de816698D7BD" }, "metal-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6920,7 +10699,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x3902228D6A3d2Dc44731fD9d45FeE6a61c722D0b" }, @@ -6928,15 +10711,35 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, + "morph-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped Ether", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, + "symbol": "WETH", + "tokenAddress": "0x5300000000000000000000000000000000000011" + }, "polygon-mainnet-katana": { "allowListEnabled": false, "decimals": 18, "name": "Vault Bridge ETH", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "vbETH", "tokenAddress": "0xEE7D8BCFb72bC1880D0Cf19822eB0A2e6577aB62" }, @@ -6944,8 +10747,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Ronin Wrapped Ether", - "poolAddress": "0x16d313Bd248Bf3A9513719c1A9d188FE7Ff65cF8", - "poolType": "burnMint", + "pool": { + "address": "0x16d313Bd248Bf3A9513719c1A9d188FE7Ff65cF8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0xc99a6A985eD2Cac1ef41640596C5A5f9F4E19Ef5" }, @@ -6953,7 +10760,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6961,7 +10772,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -6969,7 +10784,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" } @@ -6979,8 +10798,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Wrapped Fragmetric Restaked SOL", - "poolAddress": "0x414024b789097c9a81Ec2D34f95B009718f44365", - "poolType": "burnMint", + "pool": { + "address": "0x414024b789097c9a81Ec2D34f95B009718f44365", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "WFRAGSOL", "tokenAddress": "0x8624b87F9b766d82CdaDDE8Cf4192df76682F946" }, @@ -6988,8 +10811,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Wrapped Fragmetric Restaked SOL", - "poolAddress": "0x789428528A842053b52cd0D77692125829406712", - "poolType": "burnMint", + "pool": { + "address": "0x789428528A842053b52cd0D77692125829406712", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "WFRAGSOL", "tokenAddress": "0x8624b87F9b766d82CdaDDE8Cf4192df76682F946" }, @@ -6997,8 +10824,12 @@ "allowListEnabled": false, "decimals": 9, "name": "Wrapped Fragmetric Restaked SOL", - "poolAddress": "5a37uszDg5q34tvCpuFikEwSYiUWD78nPr3cUFsNQ2kK", - "poolType": "lockRelease", + "pool": { + "address": "5a37uszDg5q34tvCpuFikEwSYiUWD78nPr3cUFsNQ2kK", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "wfragSOL", "tokenAddress": "WFRGSWjaz8tbAxsJitmbfRuFV2mSNwy7BMWcCwaA28U" } @@ -7008,7 +10839,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Frax", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WFRAX", "tokenAddress": "0xFc00000000000000000000000000000000000002" } @@ -7018,17 +10853,39 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Gho Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WGHO", "tokenAddress": "0x6bDc36E20D267Ff0dd6097799f82e78907105e2F" } }, + "WgUSDT": { + "stable-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped gUSDT", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, + "symbol": "WgUSDT", + "tokenAddress": "0x817997Ca8394E26CCE3dE3A076a4889b27DbF9dE" + } + }, "WHBAR": { "hedera-mainnet": { "allowListEnabled": false, "decimals": 8, "name": "Wrapped HBAR", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WHBAR", "tokenAddress": "0xb1F616b8134F602c3Bb465fB5b5e6565cCAd37Ed" } @@ -7038,8 +10895,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wrapped HLP", - "poolAddress": "0x051665f2455116e929b9972c36d23070F5054Ce0", - "poolType": "lockRelease", + "pool": { + "address": "0x051665f2455116e929b9972c36d23070F5054Ce0", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "WHLP", "tokenAddress": "0x1359b05241cA5076c9F59605214f4F84114c0dE8" }, @@ -7047,8 +10908,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wrapped HLP", - "poolAddress": "JCPtaQkKFwBbjAfBbDrDF1wHpMfoEDEXJbwDfXvgs3j3", - "poolType": "burnMint", + "pool": { + "address": "JCPtaQkKFwBbjAfBbDrDF1wHpMfoEDEXJbwDfXvgs3j3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "wHLP", "tokenAddress": "wHLPX7ChYUnbR5G8JKqPjZyeLwSY8Mdo4kXZpQubRnJ" } @@ -7058,8 +10923,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped HSK", - "poolAddress": "0xaF6db93135F5820201e9E9b048Dd5e7Ef3dCf866", - "poolType": "burnMint", + "pool": { + "address": "0xaF6db93135F5820201e9E9b048Dd5e7Ef3dCf866", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WHSK", "tokenAddress": "0xC080b24a11fdAaf01548e384757b4c905993aF1a" }, @@ -7067,8 +10936,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped HSK", - "poolAddress": "0x71821F883E8f8F4D17889bF1E0bF548c2CFD9096", - "poolType": "burnMint", + "pool": { + "address": "0x71821F883E8f8F4D17889bF1E0bF548c2CFD9096", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WHSK", "tokenAddress": "0x54b92Ae9C9b8ce75fa958191649bC20B7e6c54C7" }, @@ -7076,8 +10949,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped HSK", - "poolAddress": "0x0B004c8e028495dC94e53e432810FAa4E66EfEe1", - "poolType": "lockRelease", + "pool": { + "address": "0x0B004c8e028495dC94e53e432810FAa4E66EfEe1", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "WHSK", "tokenAddress": "0xB210D2120d57b758EE163cFfb43e73728c471Cf1" } @@ -7087,8 +10964,12 @@ "allowListEnabled": false, "decimals": 18, "name": "why", - "poolAddress": "0x5156b61beb12eCdbB6caA4a49f41Db2203943702", - "poolType": "lockRelease", + "pool": { + "address": "0x5156b61beb12eCdbB6caA4a49f41Db2203943702", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "WHY", "tokenAddress": "0x9eC02756A559700d8D9e79ECe56809f7bcC5dC27" }, @@ -7096,8 +10977,12 @@ "allowListEnabled": false, "decimals": 18, "name": "why", - "poolAddress": "0xf00986Ebb280A1B06bfDA84700ff4cEc9696E8c0", - "poolType": "burnMint", + "pool": { + "address": "0xf00986Ebb280A1B06bfDA84700ff4cEc9696E8c0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "WHY", "tokenAddress": "0x9eC02756A559700d8D9e79ECe56809f7bcC5dC27" }, @@ -7105,8 +10990,12 @@ "allowListEnabled": false, "decimals": 18, "name": "why", - "poolAddress": "0xCfee3d8CBc7dFdea23608E73b48B1b83Af8603a9", - "poolType": "burnMint", + "pool": { + "address": "0xCfee3d8CBc7dFdea23608E73b48B1b83Af8603a9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "WHY", "tokenAddress": "0x9eC02756A559700d8D9e79ECe56809f7bcC5dC27" } @@ -7116,7 +11005,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped HYPE", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WHYPE", "tokenAddress": "0x5555555555555555555555555555555555555555" } @@ -7126,7 +11019,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Klay", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WKLAY", "tokenAddress": "0x19Aac5f612f524B754CA7e7c41cbFa2E981A4432" } @@ -7136,8 +11033,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Worldcoin", - "poolAddress": "0xc751E86208F0F8aF2d5CD0e29716cA7AD98B5eF5", - "poolType": "lockRelease", + "pool": { + "address": "0xc751E86208F0F8aF2d5CD0e29716cA7AD98B5eF5", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "WLD", "tokenAddress": "0x2cFc85d8E48F8EAB294be644d9E25C3030863003" }, @@ -7145,8 +11046,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Worldcoin", - "poolAddress": "0x10c9a3c76bDbDB8600d726De621b941fd26F6058", - "poolType": "lockRelease", + "pool": { + "address": "0x10c9a3c76bDbDB8600d726De621b941fd26F6058", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "WLD", "tokenAddress": "0x163f8C2467924be0ae7B5347228CABF260318753" } @@ -7156,8 +11061,12 @@ "allowListEnabled": false, "decimals": 18, "name": "World Liberty Financial", - "poolAddress": "0xa92261171d09aea90Bbf86c75A7322519F014c78", - "poolType": "burnMint", + "pool": { + "address": "0xa92261171d09aea90Bbf86c75A7322519F014c78", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WLFI", "tokenAddress": "0x47474747477b199288bF72a1D702f7Fe0Fb1DEeA" }, @@ -7165,8 +11074,12 @@ "allowListEnabled": false, "decimals": 18, "name": "World Liberty Financial", - "poolAddress": "0xc785D05961B3C537cAC11f1D496876a255F6D650", - "poolType": "lockRelease", + "pool": { + "address": "0xc785D05961B3C537cAC11f1D496876a255F6D650", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "WLFI", "tokenAddress": "0xdA5e1988097297dCdc1f90D4dFE7909e847CBeF6" }, @@ -7174,8 +11087,12 @@ "allowListEnabled": false, "decimals": 6, "name": "World Liberty Financial", - "poolAddress": "7QziXoi8PodowR8XxGMN8TfdYnJzmQ8i4HcCk4LWovb7", - "poolType": "burnMint", + "pool": { + "address": "7QziXoi8PodowR8XxGMN8TfdYnJzmQ8i4HcCk4LWovb7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WLFI", "tokenAddress": "WLFinEv6ypjkczcS83FZqFpgFZYwQXutRbxGe7oC16g" } @@ -7185,7 +11102,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped METIS", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WMETIS", "tokenAddress": "0x75cb093E4D61d2A2e65D8e0BBb01DE8d89b53481" } @@ -7195,7 +11116,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Mantle", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WMNT", "tokenAddress": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8" } @@ -7205,9 +11130,13 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped MON", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WMON", - "tokenAddress": "0x3A704ad3E4784b935AE029171AdCF57ee7988198" + "tokenAddress": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A" } }, "WMTX": { @@ -7215,8 +11144,12 @@ "allowListEnabled": false, "decimals": 6, "name": "WorldMobileToken", - "poolAddress": "0x0C03636614fe25278786e363643Ee5D4260C9eFE", - "poolType": "burnMint", + "pool": { + "address": "0x0C03636614fe25278786e363643Ee5D4260C9eFE", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WMTX", "tokenAddress": "0xDBB5Cf12408a3Ac17d668037Ce289f9eA75439D7" }, @@ -7224,8 +11157,12 @@ "allowListEnabled": false, "decimals": 6, "name": "WorldMobileToken", - "poolAddress": "0xF32C2942Cb14Dc47DB8d0387A089948171Bb8F05", - "poolType": "burnMint", + "pool": { + "address": "0xF32C2942Cb14Dc47DB8d0387A089948171Bb8F05", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "WMTX", "tokenAddress": "0xDBB5Cf12408a3Ac17d668037Ce289f9eA75439D7" }, @@ -7233,8 +11170,12 @@ "allowListEnabled": false, "decimals": 6, "name": "WorldMobileToken", - "poolAddress": "0x7adF83556CE7141BaB0eFdA46DB40C5d5840eBe7", - "poolType": "burnMint", + "pool": { + "address": "0x7adF83556CE7141BaB0eFdA46DB40C5d5840eBe7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "WMTX", "tokenAddress": "0x3e31966d4f81C72D2a55310A6365A56A4393E98D" }, @@ -7242,8 +11183,12 @@ "allowListEnabled": false, "decimals": 6, "name": "WorldMobileToken", - "poolAddress": "0x229a1956929489870A31b01854a80EF9B0fd27c9", - "poolType": "burnMint", + "pool": { + "address": "0x229a1956929489870A31b01854a80EF9B0fd27c9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WMTX", "tokenAddress": "0xDBB5Cf12408a3Ac17d668037Ce289f9eA75439D7" }, @@ -7251,8 +11196,12 @@ "allowListEnabled": false, "decimals": 6, "name": "World Mobile Token", - "poolAddress": "4B9Yvea3RNJ7pJQfdDxz18yzPV5sKSpvQBxoMYgLnzuK", - "poolType": "burnMint", + "pool": { + "address": "4B9Yvea3RNJ7pJQfdDxz18yzPV5sKSpvQBxoMYgLnzuK", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "WMTX", "tokenAddress": "WMTXyYKUMTG3VuZA5beXuHVRLpyTwwaoP7h2i8YpuRH" } @@ -7262,7 +11211,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped NXPC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WNXPC", "tokenAddress": "0x150869eac5C58d3655f860C4316107fB626244d0" } @@ -7272,8 +11225,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped OETH", - "poolAddress": "0xbC92233eca3c53c002Ab80eAc8b6F9f84Fa27DBE", - "poolType": "burnMint", + "pool": { + "address": "0xbC92233eca3c53c002Ab80eAc8b6F9f84Fa27DBE", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "WOETH", "tokenAddress": "0xD8724322f44E5c58D7A815F542036fb17DbbF839" }, @@ -7281,8 +11238,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped OETH", - "poolAddress": "0xFE8671c82036b1afEF2Fd423d1aadeF5dC735A43", - "poolType": "burnMint", + "pool": { + "address": "0xFE8671c82036b1afEF2Fd423d1aadeF5dC735A43", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "wOETH", "tokenAddress": "0xD8724322f44E5c58D7A815F542036fb17DbbF839" }, @@ -7290,8 +11251,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped OETH", - "poolAddress": "0x75a852478792E5a99bc4cdd0aDBd97129B0d9799", - "poolType": "lockRelease", + "pool": { + "address": "0x75a852478792E5a99bc4cdd0aDBd97129B0d9799", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "wOETH", "tokenAddress": "0xDcEe70654261AF21C44c093C300eD3Bb97b78192" } @@ -7301,7 +11266,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped OKB", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WOKB", "tokenAddress": "0xe538905cf8410324e03A5A23C1c177a474D59b2b" } @@ -7311,8 +11280,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Landwolf", - "poolAddress": "0x158fbCD99c333afD5838aeF6ee3236c3e0a7041c", - "poolType": "burnMint", + "pool": { + "address": "0x158fbCD99c333afD5838aeF6ee3236c3e0a7041c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "WOLF", "tokenAddress": "0xe760fc2c7B94075Ae010216a539dcE7f91AF0e13" }, @@ -7320,8 +11293,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Landwolf", - "poolAddress": "0x89C13177406982051baC3305D14180F763422CE2", - "poolType": "burnMint", + "pool": { + "address": "0x89C13177406982051baC3305D14180F763422CE2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "WOLF", "tokenAddress": "0x77Ca224436B132CD83581826669025Ed9cfd9b94" }, @@ -7329,8 +11306,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Landwolf", - "poolAddress": "0xfaFcaC5F48A7E034fec3264A6c42F88ef705638a", - "poolType": "lockRelease", + "pool": { + "address": "0xfaFcaC5F48A7E034fec3264A6c42F88ef705638a", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "WOLF", "tokenAddress": "0x67466BE17df832165F8C80a5A120CCc652bD7E69" } @@ -7340,8 +11321,12 @@ "allowListEnabled": false, "decimals": 18, "name": "WOW", - "poolAddress": "0x0563f39D663D44B64677ead7D75CdC7ADA842eCf", - "poolType": "burnMint", + "pool": { + "address": "0x0563f39D663D44B64677ead7D75CdC7ADA842eCf", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "WOW", "tokenAddress": "0xc97Cb00245a50c607b57D9b6d2e854FcA3B33F9c" }, @@ -7349,8 +11334,12 @@ "allowListEnabled": false, "decimals": 18, "name": "WOW", - "poolAddress": "0xB858917F2dA9253736c7869eD40f1212015AF4DE", - "poolType": "lockRelease", + "pool": { + "address": "0xB858917F2dA9253736c7869eD40f1212015AF4DE", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "WOW", "tokenAddress": "0x8f4b11d923BbAA6206f3Dd3ff84e8e31bafB49b7" } @@ -7360,7 +11349,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Plume", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WPLUME", "tokenAddress": "0xEa237441c92CAe6FC17Caaf9a7acB3f953be4bd1" } @@ -7370,7 +11363,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Polygon Ecosystem Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WPOL", "tokenAddress": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270" } @@ -7380,7 +11377,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BTC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WRBTC", "tokenAddress": "0x542fDA317318eBF1d3DEAf76E0b632741A7e677d" } @@ -7390,7 +11391,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ronin", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WRON", "tokenAddress": "0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4" } @@ -7400,7 +11405,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Sonic", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "wS", "tokenAddress": "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38" } @@ -7410,8 +11419,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wisdomise", - "poolAddress": "0x862428cA8C8108486e0c6e66a897Aa0166841349", - "poolType": "burnMint", + "pool": { + "address": "0x862428cA8C8108486e0c6e66a897Aa0166841349", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WSDM", "tokenAddress": "0x5F2F8818002dc64753daeDF4A6CB2CcB757CD220" }, @@ -7419,8 +11432,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wisdomise", - "poolAddress": "0xCF241Cdd2dee05Ef1Bd7F3FdAEf1bEc143E4f87c", - "poolType": "burnMint", + "pool": { + "address": "0xCF241Cdd2dee05Ef1Bd7F3FdAEf1bEc143E4f87c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "WSDM", "tokenAddress": "0x5F2F8818002dc64753daeDF4A6CB2CcB757CD220" }, @@ -7428,8 +11445,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wisdomise", - "poolAddress": "0x8ee28906BA9E482d881d28E825118b8b8e46A4a5", - "poolType": "burnMint", + "pool": { + "address": "0x8ee28906BA9E482d881d28E825118b8b8e46A4a5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "WSDM", "tokenAddress": "0x5F2F8818002dc64753daeDF4A6CB2CcB757CD220" }, @@ -7437,8 +11458,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wisdomise", - "poolAddress": "0x2DeBF941D469709853d96Df09dEF1DD8151D44D3", - "poolType": "lockRelease", + "pool": { + "address": "0x2DeBF941D469709853d96Df09dEF1DD8151D44D3", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "WSDM", "tokenAddress": "0x5F2F8818002dc64753daeDF4A6CB2CcB757CD220" } @@ -7448,7 +11473,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped SEI", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WSEI", "tokenAddress": "0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7" } @@ -7458,7 +11487,11 @@ "allowListEnabled": false, "decimals": 9, "name": "Wrapped Solana", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WSOL", "tokenAddress": "So11111111111111111111111111111111111111112" } @@ -7468,53 +11501,104 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped stETH", - "poolAddress": "0xFEe991bB8695a336f5C4ab00062BEEd4b5783f4F", - "poolType": "burnMint", + "pool": { + "address": "0xFEe991bB8695a336f5C4ab00062BEEd4b5783f4F", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "wstETH", "tokenAddress": "0x161a128567BF0C005b58211757F7e46eed983F02" }, - "bitcoin-mainnet-bitlayer-1": { + "abstract-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped liquid staked Ether 2.0", - "poolAddress": "0xC78210649aF8A450C0f6E98107a0b614a3198359", + "poolAddress": "0x38Ad0414B523Fa344429ff14dAC305e4fB6Ab248", "poolType": "burnMint", "symbol": "wstETH", + "tokenAddress": "0x313F663E79ef202251a28F0252c254842D5ABC6a" + }, + "bitcoin-mainnet-bitlayer-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped liquid staked Ether 2.0", + "pool": { + "address": "0xC78210649aF8A450C0f6E98107a0b614a3198359", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "wstETH", "tokenAddress": "0x5659b4C62897Fa36C05780cD96c2D5c0a5602488" }, "ethereum-mainnet-ink-1": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped liquid staked Ether 2.0", - "poolAddress": "0x2dC99af320BC317c567f24eE95811dcbd5983DfD", - "poolType": "burnMint", + "pool": { + "address": "0x2dC99af320BC317c567f24eE95811dcbd5983DfD", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "wstETH", "tokenAddress": "0xE561152E8d3f618b386EF4dD6E3fb980Eb2f9e61" }, + "jovay-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped liquid staked Ether 2.0", + "poolAddress": "0x1c2F528e3BEeFF81Bc03CC63E64dB131d18be7fA", + "poolType": "burnMint", + "symbol": "wstETH", + "tokenAddress": "0x2dC99af320BC317c567f24eE95811dcbd5983DfD" + }, "mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped liquid staked Ether 2.0", - "poolAddress": "0xA586a732394A1AFfCF15b972cd47C936033C9FA7", - "poolType": "lockRelease", + "pool": { + "address": "0xA586a732394A1AFfCF15b972cd47C936033C9FA7", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "wstETH", "tokenAddress": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0" }, - "monad-mainnet": { + "megaeth-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped liquid staked Ether 2.0", - "poolAddress": "0x2f2E55517aac64c4066f6eB333b4Cb072eD00E8A", + "poolAddress": "0x15C03488B29e27d62BAf10E30b0c474bf60E0264", "poolType": "burnMint", "symbol": "wstETH", + "tokenAddress": "0x601aC63637933D88285A025C685AC4e9a92a98dA" + }, + "monad-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped liquid staked Ether 2.0", + "pool": { + "address": "0x2f2E55517aac64c4066f6eB333b4Cb072eD00E8A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, + "symbol": "wstETH", "tokenAddress": "0x10Aeaf63194db8d453d4D85a06E5eFE1dd0b5417" }, "plasma-mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped liquid staked Ether 2.0", - "poolAddress": "0xa4b1d393104a5eF340154c337009156aA0E83Bd8", - "poolType": "burnMint", + "pool": { + "address": "0xa4b1d393104a5eF340154c337009156aA0E83Bd8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "wstETH", "tokenAddress": "0x481e638105407Be40c2f2E2e006DE272d05930d0" } @@ -7524,8 +11608,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped stLINK", - "poolAddress": "0x04be180c1c3468c86EB68939aB53dbDC7306aDc7", - "poolType": "burnMint", + "pool": { + "address": "0x04be180c1c3468c86EB68939aB53dbDC7306aDc7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "wstLINK", "tokenAddress": "0x601486C8Fdc3aD22745b01c920037d6c036A38B9" }, @@ -7533,17 +11621,38 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped stLINK", - "poolAddress": "0x5406e9d1CEF8f54eb675bd41139A5E3D83bFf80c", - "poolType": "burnMint", + "pool": { + "address": "0x5406e9d1CEF8f54eb675bd41139A5E3D83bFf80c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "wstLINK", "tokenAddress": "0x3106E2e148525b3DB36795b04691D444c24972fB" }, + "ethereum-mainnet-base-1": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped stLINK", + "pool": { + "address": "0xc80088D32830Cdb869eBA08bb25Bb6D7B17467FF", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "wstLINK", + "tokenAddress": "0xF2f7901B7bbA5799493B617B06EAd1862F771297" + }, "mainnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped stLINK", - "poolAddress": "0xF6403CF6E954a43699097322e0867C63d653C2D0", - "poolType": "lockRelease", + "pool": { + "address": "0xF6403CF6E954a43699097322e0867C63d653C2D0", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "wstLINK", "tokenAddress": "0x911D86C72155c33993d594B0Ec7E6206B4C803da" }, @@ -7551,8 +11660,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped stLINK", - "poolAddress": "0x97f40E42e4aE3BA12b5856F685136f6747Fa49a5", - "poolType": "burnMint", + "pool": { + "address": "0x97f40E42e4aE3BA12b5856F685136f6747Fa49a5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "wstLINK", "tokenAddress": "0xc271A17DB5cE6F53745A3F466077Ec816bC20a9C" } @@ -7562,8 +11675,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped stPOL", - "poolAddress": "0x481242B7846FA88fA76f2Ee73157aAa3AE2B280b", - "poolType": "burnMint", + "pool": { + "address": "0x481242B7846FA88fA76f2Ee73157aAa3AE2B280b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "wstPOL", "tokenAddress": "0x9178baB5362282a861922Ce641F4f3b7D4Bb9EF3" }, @@ -7571,8 +11688,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped stPOL", - "poolAddress": "0x553636e52059B0339592f545D25a4C0A86E3a1Bc", - "poolType": "lockRelease", + "pool": { + "address": "0x553636e52059B0339592f545D25a4C0A86E3a1Bc", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "wstPOL", "tokenAddress": "0x2091d83592D79B4De5fD2ce3D98679c32A9555e6" }, @@ -7580,8 +11701,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped stPOL", - "poolAddress": "0xb4D2C033Ea68674E56F6071B0d826D03152376dB", - "poolType": "burnMint", + "pool": { + "address": "0xb4D2C033Ea68674E56F6071B0d826D03152376dB", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "wstPOL", "tokenAddress": "0x1d0347C535C88Cf6BB72df75AED34363edB4B2AE" } @@ -7591,7 +11716,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped TAC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WTAC", "tokenAddress": "0xB63B9f0eb4A6E6f191529D71d4D88cc8900Df2C9" } @@ -7601,7 +11730,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Tao", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WTAO", "tokenAddress": "0x5F3B70e0c089a1e3020B1990823Bc241a7bF3522" } @@ -7611,8 +11744,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wrapped xUSD", - "poolAddress": "0xa843652dF6Bda4d4B2894a28505963F595AEdBe3", - "poolType": "burnMint", + "pool": { + "address": "0xa843652dF6Bda4d4B2894a28505963F595AEdBe3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "wxUSD", "tokenAddress": "0x2d7e22Fb0fb7A7F0d1fef70ad8873A9ffDe18007" }, @@ -7620,8 +11757,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wrapped xUSD", - "poolAddress": "0xf6C3874a0a535B616d4528263B796255949D0135", - "poolType": "lockRelease", + "pool": { + "address": "0xf6C3874a0a535B616d4528263B796255949D0135", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "wxUSD", "tokenAddress": "0xB86fb1047A955C0186c77ff6263819b37B32440D" }, @@ -7629,8 +11770,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wrapped xUSD", - "poolAddress": "0x335CAd1ea3aB44fe800Da89Fc31e0071E044EF34", - "poolType": "burnMint", + "pool": { + "address": "0x335CAd1ea3aB44fe800Da89Fc31e0071E044EF34", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "wxUSD", "tokenAddress": "0x1EaE7Ca39192a2B6E3EA2E852A0D4D20bCe89d14" }, @@ -7638,8 +11783,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wrapped xUSD", - "poolAddress": "0x7211e50394Fa9c29373cf95987Fc381f35f8b8D8", - "poolType": "burnMint", + "pool": { + "address": "0x7211e50394Fa9c29373cf95987Fc381f35f8b8D8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "wxUSD", "tokenAddress": "0xAe770d24ec1580A13392E0B71067571351029203" }, @@ -7647,8 +11796,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wrapped xUSD", - "poolAddress": "0xCF4f83859845594aC0e7a9da26df5e47cf5474fd", - "poolType": "burnMint", + "pool": { + "address": "0xCF4f83859845594aC0e7a9da26df5e47cf5474fd", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "wxUSD", "tokenAddress": "0xe49465604e25cd5167005e0cEbD8Af461e833b83" }, @@ -7656,8 +11809,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wrapped xUSD", - "poolAddress": "0xe9bFB4fe6E403985c5f2b968f883A9590Aac54aC", - "poolType": "burnMint", + "pool": { + "address": "0xe9bFB4fe6E403985c5f2b968f883A9590Aac54aC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "wxUSD", "tokenAddress": "0xAe770d24ec1580A13392E0B71067571351029203" }, @@ -7665,8 +11822,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Wrapped xUSD", - "poolAddress": "0x04c5046A1f4E3fFf094c26dFCAA75eF293932f18", - "poolType": "burnMint", + "pool": { + "address": "0x04c5046A1f4E3fFf094c26dFCAA75eF293932f18", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "wxUSD", "tokenAddress": "0x29A0dc4f509873673B7682B60598d393A1e591b7" } @@ -7676,7 +11837,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Wemix", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WWEMIX", "tokenAddress": "0x7D72b22a74A216Af4a002a1095C8C707d6eC1C5f" } @@ -7686,7 +11851,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped XDAI", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WXDAI", "tokenAddress": "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d" } @@ -7696,7 +11865,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped XDC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WXDC", "tokenAddress": "0x951857744785E80e2De051c32EE7b25f9c458C42" } @@ -7706,7 +11879,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped XPL", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WXPL", "tokenAddress": "0x6100E367285b01F48D07953803A2d8dCA5D19873" } @@ -7716,7 +11893,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped XTZ", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WXTZ", "tokenAddress": "0xc9B53AB2679f573e480d01e0f49e2B5CFB7a3EAb" } @@ -7726,7 +11907,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped zkCRO", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "wzkCRO", "tokenAddress": "0xC1bF55EE54E16229d9b369a5502Bfe5fC9F20b6d" } @@ -7736,8 +11921,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xGold", - "poolAddress": "0xe199E1C5201CCDd3792ed902aD3f610Ce5629B59", - "poolType": "burnMint", + "pool": { + "address": "0xe199E1C5201CCDd3792ed902aD3f610Ce5629B59", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xGold", "tokenAddress": "0x281A83ee4819068C40937A066d801aAD7C6e0400" }, @@ -7745,8 +11934,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xGold", - "poolAddress": "0x055860f40533c4d9E7CD38105F4c0d1EB0593072", - "poolType": "burnMint", + "pool": { + "address": "0x055860f40533c4d9E7CD38105F4c0d1EB0593072", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "xGold", "tokenAddress": "0x5D84B92A34635e5C21b7885fB29D6a4B60287ab7" }, @@ -7754,8 +11947,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xGold", - "poolAddress": "0x2110679A2155534b7674349273741a537495C50C", - "poolType": "burnMint", + "pool": { + "address": "0x2110679A2155534b7674349273741a537495C50C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xGold", "tokenAddress": "0x3FA41d2b29c69F8DA6E2D0bFc4f83C62D6582750" }, @@ -7763,8 +11960,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xGold", - "poolAddress": "0x5B806bA13B8B66F83339A63496C2f914BDd4Eb13", - "poolType": "burnMint", + "pool": { + "address": "0x5B806bA13B8B66F83339A63496C2f914BDd4Eb13", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "xGold", "tokenAddress": "0x74FC58Ba6FE27771589Be4b405D88Ab1521CD143" }, @@ -7772,8 +11973,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xGold", - "poolAddress": "0x55585FFBd94471925252C13ade6A81604C781C5D", - "poolType": "burnMint", + "pool": { + "address": "0x55585FFBd94471925252C13ade6A81604C781C5D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xGold", "tokenAddress": "0x5E75a1aD7b10523f7ed98C1C7CA0b4A79B1bBDee" }, @@ -7781,8 +11986,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xGold", - "poolAddress": "0x9EC2F7DBEB9dC7fc72F8476D8a5770E89e13D385", - "poolType": "burnMint", + "pool": { + "address": "0x9EC2F7DBEB9dC7fc72F8476D8a5770E89e13D385", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xGold", "tokenAddress": "0xDCFdCa64194945a44F092F8eD000245146aFcDd6" } @@ -7792,8 +12001,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Dexlab", - "poolAddress": "0xbf5d2a9e48C51c5945A7975c2b294A8A3e5330f2", - "poolType": "burnMint", + "pool": { + "address": "0xbf5d2a9e48C51c5945A7975c2b294A8A3e5330f2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "XLAB", "tokenAddress": "0x5BA9bfFFB868859064C33D4f995A0828b2B1d2d3" }, @@ -7801,8 +12014,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Dexlab", - "poolAddress": "2F9v1hYeB247wJzBgjsz8zYAQUhFSPDzr1PDs6srMGtU", - "poolType": "lockRelease", + "pool": { + "address": "2F9v1hYeB247wJzBgjsz8zYAQUhFSPDzr1PDs6srMGtU", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "XLAB", "tokenAddress": "XLnpFRQ3rSWupCRjuQfx74mgVoT3ezVJKE1CogRZxhH" } @@ -7812,8 +12029,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Constellation ETH", - "poolAddress": "0x2d009c84770a3981613Ce5d1eD8F8a67BEc7411e", - "poolType": "burnMint", + "pool": { + "address": "0x2d009c84770a3981613Ce5d1eD8F8a67BEc7411e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xrETH", "tokenAddress": "0x4d26b028D8C255794671fd120a94231A80A2E2C9" }, @@ -7821,8 +12042,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Constellation ETH", - "poolAddress": "0xf50B3be14ed2cF2CfE9aC239b763088E2463C11f", - "poolType": "burnMint", + "pool": { + "address": "0xf50B3be14ed2cF2CfE9aC239b763088E2463C11f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xrETH", "tokenAddress": "0xaD09085191216a94FA1Fd2A790E48e734602a869" }, @@ -7830,8 +12055,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Constellation ETH", - "poolAddress": "0xEDe803B34B30C8De6a128DE57B855263Cd8C55bc", - "poolType": "lockRelease", + "pool": { + "address": "0xEDe803B34B30C8De6a128DE57B855263Cd8C55bc", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "xrETH", "tokenAddress": "0xBB22d59B73D7a6F3A8a83A214BECc67Eb3b511fE" } @@ -7841,8 +12070,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Constellation RPL", - "poolAddress": "0x1dBD6224Cf535F624FcB41C4Ad8c065f10BDF3E3", - "poolType": "burnMint", + "pool": { + "address": "0x1dBD6224Cf535F624FcB41C4Ad8c065f10BDF3E3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xRPL", "tokenAddress": "0xd3Bb9E4e9aE431888873d3E51b3c03dA909e868A" }, @@ -7850,8 +12083,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Constellation RPL", - "poolAddress": "0xDdEDeb125315ba7b6539A6C18478ccf8b59ACEaE", - "poolType": "burnMint", + "pool": { + "address": "0xDdEDeb125315ba7b6539A6C18478ccf8b59ACEaE", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xRPL", "tokenAddress": "0x2775DeeB4FaDCc486562CAa777dE70AD6CCD82c6" }, @@ -7859,8 +12096,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Constellation RPL", - "poolAddress": "0x8d9F0185c49752d626ef0c318B24Bba83931D639", - "poolType": "lockRelease", + "pool": { + "address": "0x8d9F0185c49752d626ef0c318B24Bba83931D639", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "xRPL", "tokenAddress": "0x1DB1Afd9552eeB28e2e36597082440598B7F1320" } @@ -7870,8 +12111,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSILO", - "poolAddress": "0x902CD33780288CD0Bfff42AE174511d378DfE728", - "poolType": "burnMint", + "pool": { + "address": "0x902CD33780288CD0Bfff42AE174511d378DfE728", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSILO", "tokenAddress": "0xbB4287da728532C78bAF246B12A10be3ace2Dc70" }, @@ -7879,8 +12124,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSILO", - "poolAddress": "0x9D1cDE77b0720D78aBBD03EdF9abF7D5E0EE4b3A", - "poolType": "burnMint", + "pool": { + "address": "0x9D1cDE77b0720D78aBBD03EdF9abF7D5E0EE4b3A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSILO", "tokenAddress": "0xf3775f959bc64923BD809085299dBC984D3e6C8A" }, @@ -7888,8 +12137,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSILO", - "poolAddress": "0xC201a236258Ec170dE5255A9507bb4f70c7caf31", - "poolType": "burnMint", + "pool": { + "address": "0xC201a236258Ec170dE5255A9507bb4f70c7caf31", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xSILO", "tokenAddress": "0xdd4c6FD31Ccf66E250790643947675153c221A91" }, @@ -7897,8 +12150,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSILO", - "poolAddress": "0x4F91b984B03B09Fdd60f9ed02279020eF930B2B0", - "poolType": "lockRelease", + "pool": { + "address": "0x4F91b984B03B09Fdd60f9ed02279020eF930B2B0", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "xSILO", "tokenAddress": "0x4451765739b2D7BCe5f8BC95Beaf966c45E1Dcc9" } @@ -7908,8 +12165,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0x2AB9cD10aC8077a554511FbcBCB0c94D833e0cC5", - "poolType": "burnMint", + "pool": { + "address": "0x2AB9cD10aC8077a554511FbcBCB0c94D833e0cC5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0xCC0966D8418d412c599A6421b760a847eB169A8c" }, @@ -7917,8 +12178,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0x3539F2E214d8BC7E611056383323aC6D1b01943c", - "poolType": "burnMint", + "pool": { + "address": "0x3539F2E214d8BC7E611056383323aC6D1b01943c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0xCC0966D8418d412c599A6421b760a847eB169A8c" }, @@ -7926,8 +12191,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0x3f2Be15aEA9F68f63ADE10440C6fE00753300b68", - "poolType": "burnMint", + "pool": { + "address": "0x3f2Be15aEA9F68f63ADE10440C6fE00753300b68", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xSolvBTC", "tokenAddress": "0xCC0966D8418d412c599A6421b760a847eB169A8c" }, @@ -7935,8 +12204,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0xf0314c4B42cd6fCA8772bDE359E0A7d3b5E70f88", - "poolType": "burnMint", + "pool": { + "address": "0xf0314c4B42cd6fCA8772bDE359E0A7d3b5E70f88", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "xSolvBTC", "tokenAddress": "0x1346b618dC92810EC74163e4c27004c921D446a5" }, @@ -7944,8 +12217,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0x0Cd252108EF0CE50f95F75045a97C72A0A8d3118", - "poolType": "burnMint", + "pool": { + "address": "0x0Cd252108EF0CE50f95F75045a97C72A0A8d3118", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0x346c574C56e1A4aAa8dc88Cda8F7EB12b39947aB" }, @@ -7953,8 +12230,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0x1b019366e7fD47425c7E3D07C18D52D77c0B72bf", - "poolType": "burnMint", + "pool": { + "address": "0x1b019366e7fD47425c7E3D07C18D52D77c0B72bf", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0xC26C9099BD3789107888c35bb41178079B282561" }, @@ -7962,8 +12243,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0xdb9E8DF31cE12817DdD1C4d2c3acef038580f586", - "poolType": "burnMint", + "pool": { + "address": "0xdb9E8DF31cE12817DdD1C4d2c3acef038580f586", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0xc99F5c922DAE05B6e2ff83463ce705eF7C91F077" }, @@ -7971,8 +12256,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0xd25987B0712FA66D05aA2F7A35bA4B01fB60D22E", - "poolType": "burnMint", + "pool": { + "address": "0xd25987B0712FA66D05aA2F7A35bA4B01fB60D22E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0xCC0966D8418d412c599A6421b760a847eB169A8c" }, @@ -7980,8 +12269,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0xDed2A972feB2AA8FE531D8C4E290C12FFE6Be9D6", - "poolType": "burnMint", + "pool": { + "address": "0xDed2A972feB2AA8FE531D8C4E290C12FFE6Be9D6", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xSolvBTC", "tokenAddress": "0xCC0966D8418d412c599A6421b760a847eB169A8c" }, @@ -7989,8 +12282,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0x97810368dE6F7213Cf54f2918A267cEa25449F81", - "poolType": "burnMint", + "pool": { + "address": "0x97810368dE6F7213Cf54f2918A267cEa25449F81", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0x2878295D69Aa3BDcf9004FCf362F0959992D801c" }, @@ -7998,8 +12295,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0xb5829e1f8078860969950852546B947f37855ef1", - "poolType": "burnMint", + "pool": { + "address": "0xb5829e1f8078860969950852546B947f37855ef1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xSolvBTC", "tokenAddress": "0xc99F5c922DAE05B6e2ff83463ce705eF7C91F077" }, @@ -8007,8 +12308,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0x99bb52AAF045F63F74d0a3FbE6Cf3e7B23aeD212", - "poolType": "burnMint", + "pool": { + "address": "0x99bb52AAF045F63F74d0a3FbE6Cf3e7B23aeD212", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0xd9D920AA40f578ab794426F5C90F6C731D159DEf" }, @@ -8016,8 +12321,25 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0x44F2B4dE683f5225704376699fD1eF3E2769107b", - "poolType": "burnMint", + "pool": { + "address": "0x44F2B4dE683f5225704376699fD1eF3E2769107b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "xSolvBTC", + "tokenAddress": "0xc99F5c922DAE05B6e2ff83463ce705eF7C91F077" + }, + "monad-mainnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "xSolvBTC", + "pool": { + "address": "0x8A76fe7fA6da27f85a626c5C53730B38D13603d7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "xSolvBTC", "tokenAddress": "0xc99F5c922DAE05B6e2ff83463ce705eF7C91F077" }, @@ -8025,8 +12347,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0xd2bdD1E01fd2F8d7d42b209c111c7b32158b5a42", - "poolType": "burnMint", + "pool": { + "address": "0xd2bdD1E01fd2F8d7d42b209c111c7b32158b5a42", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xSolvBTC", "tokenAddress": "0xCC0966D8418d412c599A6421b760a847eB169A8c" }, @@ -8034,8 +12360,12 @@ "allowListEnabled": false, "decimals": 8, "name": "xSolvBTC", - "poolAddress": "JBxSefWbahYApU5DVsqXcHugDVGFNUaaZgWh3u7wESVn", - "poolType": "burnMint", + "pool": { + "address": "JBxSefWbahYApU5DVsqXcHugDVGFNUaaZgWh3u7wESVn", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "xSolvBTC", "tokenAddress": "SoLvAiHLF7LGEaiTN5KGZt1bNnraoWTi5mjcvRoDAX4" }, @@ -8043,8 +12373,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0xEf53137aF78Afc63b312f0af64fe3c24804d2441", - "poolType": "burnMint", + "pool": { + "address": "0xEf53137aF78Afc63b312f0af64fe3c24804d2441", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0xCC0966D8418d412c599A6421b760a847eB169A8c" }, @@ -8052,8 +12386,12 @@ "allowListEnabled": false, "decimals": 18, "name": "xSolvBTC", - "poolAddress": "0x2B4d8FAD49A3276853560A9cAFaa59392a99cDbD", - "poolType": "burnMint", + "pool": { + "address": "0x2B4d8FAD49A3276853560A9cAFaa59392a99cDbD", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "xSolvBTC", "tokenAddress": "0xCC0966D8418d412c599A6421b760a847eB169A8c" } @@ -8063,8 +12401,12 @@ "allowListEnabled": false, "decimals": 18, "name": "XSwap", - "poolAddress": "0x4d87CBff8187C4B3E00FDF534cb310724536EA4c", - "poolType": "burnMint", + "pool": { + "address": "0x4d87CBff8187C4B3E00FDF534cb310724536EA4c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "XSWAP", "tokenAddress": "0x8Fe815417913a93Ea99049FC0718ee1647A2a07c" }, @@ -8072,8 +12414,12 @@ "allowListEnabled": false, "decimals": 18, "name": "XSwap", - "poolAddress": "0x916D7d960B119bb6c4AbE381f7677eCEed866d44", - "poolType": "burnMint", + "pool": { + "address": "0x916D7d960B119bb6c4AbE381f7677eCEed866d44", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "XSWAP", "tokenAddress": "0x8Fe815417913a93Ea99049FC0718ee1647A2a07c" } @@ -8083,8 +12429,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Real Estate Panama Fund", - "poolAddress": "0x38b771383823A442fF3943706d6541A253298c8e", - "poolType": "burnMint", + "pool": { + "address": "0x38b771383823A442fF3943706d6541A253298c8e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "XTFBRICK1", "tokenAddress": "0x8d944193Cdeb7c4767fB1B3c43Fb9E1E1Df3158A" }, @@ -8092,8 +12442,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Real Estate Panama Fund", - "poolAddress": "0x07f49dC315E6F567a824Db364E834E3391E976a8", - "poolType": "burnMint", + "pool": { + "address": "0x07f49dC315E6F567a824Db364E834E3391E976a8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "XTFBRICK1", "tokenAddress": "0x268Cf1A0d1723eff452a2df8208172F8768Aa001" }, @@ -8101,8 +12455,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Real Estate Panama Fund", - "poolAddress": "0x71cC4E6858bA934Da2F6F825807118160FADFDA8", - "poolType": "lockRelease", + "pool": { + "address": "0x71cC4E6858bA934Da2F6F825807118160FADFDA8", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "XTFBRICK1", "tokenAddress": "0x2D7f7da70F8c36A2ef47BAbbc4D0be4B4274F72D" } @@ -8112,8 +12470,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Avenida CLO Bond Fund", - "poolAddress": "0xDc274b09d624EE22079F187E8dFf11Bf599cd2A1", - "poolType": "burnMint", + "pool": { + "address": "0xDc274b09d624EE22079F187E8dFf11Bf599cd2A1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "XTFCLOBOND", "tokenAddress": "0x9E1B4B2e870bD894e7457D18bA620E0cf3e37F90" }, @@ -8121,8 +12483,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Avenida CLO Bond Fund", - "poolAddress": "0x8680bf9D1d132DF66d9CeDcB0a0bA068cD94998A", - "poolType": "burnMint", + "pool": { + "address": "0x8680bf9D1d132DF66d9CeDcB0a0bA068cD94998A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "XTFCLOBOND", "tokenAddress": "0xD012151eA9352f477895e0a4f88Efe15f0e8855a" }, @@ -8130,8 +12496,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Avenida CLO Bond Fund", - "poolAddress": "0x8C66197BDbeAc351590F93447A1CD4186553970E", - "poolType": "lockRelease", + "pool": { + "address": "0x8C66197BDbeAc351590F93447A1CD4186553970E", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "XTFCLOBOND", "tokenAddress": "0xe5097376a585565038D2CF05D2Eb04e9Db1902AD" } @@ -8141,8 +12511,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Yield BTC.B", - "poolAddress": "0xC78210649aF8A450C0f6E98107a0b614a3198359", - "poolType": "burnMint", + "pool": { + "address": "0xC78210649aF8A450C0f6E98107a0b614a3198359", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "YBTC.B", "tokenAddress": "0x2cd3CdB3bd68Eea0d3BE81DA707bC0c8743D7335" }, @@ -8150,8 +12524,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Yield BTC.B", - "poolAddress": "0xfed13D0c40790220fbdE712987079Eda1Ed75C51", - "poolType": "lockRelease", + "pool": { + "address": "0xfed13D0c40790220fbdE712987079Eda1Ed75C51", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "YBTC.B", "tokenAddress": "0x2cd3CdB3bd68Eea0d3BE81DA707bC0c8743D7335" }, @@ -8159,8 +12537,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Yield BTC.B", - "poolAddress": "0x448eEF4A0EF5171F9B9C973017C9621C914591Ad", - "poolType": "burnMint", + "pool": { + "address": "0x448eEF4A0EF5171F9B9C973017C9621C914591Ad", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "YBTC.B", "tokenAddress": "0x2cd3CdB3bd68Eea0d3BE81DA707bC0c8743D7335" }, @@ -8168,8 +12550,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Yield BTC.B", - "poolAddress": "0x5416050533Bc83533Fc7e7BC50A651DC7C762D07", - "poolType": "burnMint", + "pool": { + "address": "0x5416050533Bc83533Fc7e7BC50A651DC7C762D07", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "YBTC.B", "tokenAddress": "0x2cd3CdB3bd68Eea0d3BE81DA707bC0c8743D7335" }, @@ -8177,8 +12563,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Yield BTC.B", - "poolAddress": "0x9aCd2ffD56E278a560Cc4E12dCA2B7D2B3359Ac2", - "poolType": "burnMint", + "pool": { + "address": "0x9aCd2ffD56E278a560Cc4E12dCA2B7D2B3359Ac2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "YBTC.B", "tokenAddress": "0x2cd3CdB3bd68Eea0d3BE81DA707bC0c8743D7335" }, @@ -8186,8 +12576,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Yield BTC.B", - "poolAddress": "0x5416050533Bc83533Fc7e7BC50A651DC7C762D07", - "poolType": "burnMint", + "pool": { + "address": "0x5416050533Bc83533Fc7e7BC50A651DC7C762D07", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "YBTC.B", "tokenAddress": "0x2cd3CdB3bd68Eea0d3BE81DA707bC0c8743D7335" }, @@ -8195,8 +12589,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Yield BTC.B", - "poolAddress": "0xe96cC12AA0E2e545621bcbE1E035D91a7871fE8f", - "poolType": "burnMint", + "pool": { + "address": "0xe96cC12AA0E2e545621bcbE1E035D91a7871fE8f", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "YBTC.B", "tokenAddress": "0x2cd3CdB3bd68Eea0d3BE81DA707bC0c8743D7335" }, @@ -8204,8 +12602,12 @@ "allowListEnabled": false, "decimals": 8, "name": "Yield BTC.B", - "poolAddress": "FV7RjzzPxaVXEtkR9NsPREHBEzPoiVvQBtzQY97PGe3Z", - "poolType": "burnMint", + "pool": { + "address": "FV7RjzzPxaVXEtkR9NsPREHBEzPoiVvQBtzQY97PGe3Z", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "YBTC.B", "tokenAddress": "3VcKofugG1SPJmjuiEZCJL5mk1JkyqGZ19ByeMWXVWfK" } @@ -8215,8 +12617,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Yield Guild Games Token", - "poolAddress": "0x799A356069Ca6D91BBE5d0407De625A969874aE4", - "poolType": "lockRelease", + "pool": { + "address": "0x799A356069Ca6D91BBE5d0407De625A969874aE4", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "YGG", "tokenAddress": "0x25f8087EAD173b73D6e8B84329989A8eEA16CF73" }, @@ -8224,8 +12630,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Yield Guild Games Token", - "poolAddress": "0x2b200Ca34f70d39464A0881BC45fC5fb858b3d5F", - "poolType": "burnMint", + "pool": { + "address": "0x2b200Ca34f70d39464A0881BC45fC5fb858b3d5F", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "YGG", "tokenAddress": "0x1c306872bC82525d72Bf3562E8F0aA3f8F26e857" } @@ -8235,8 +12645,12 @@ "allowListEnabled": false, "decimals": 6, "name": "yesnoerror", - "poolAddress": "0xd8F5e7FAc317c638d2Fe4d07ab3f436ca6b5e5c7", - "poolType": "burnMint", + "pool": { + "address": "0xd8F5e7FAc317c638d2Fe4d07ab3f436ca6b5e5c7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "YNE", "tokenAddress": "0xE2f9db0186b13668AeC9fe0e15dbD13004ed8d6f" }, @@ -8244,8 +12658,12 @@ "allowListEnabled": false, "decimals": 6, "name": "yesnoerror", - "poolAddress": "AyxbrQHM1sPx17HKWP1x13E8PBFxpvMQiMERvoG4ub53", - "poolType": "lockRelease", + "pool": { + "address": "AyxbrQHM1sPx17HKWP1x13E8PBFxpvMQiMERvoG4ub53", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "YNE", "tokenAddress": "7D1iYWfhw2cr9yBZBFE6nZaaSUvXHqG5FizFFEZwpump" } @@ -8255,8 +12673,12 @@ "allowListEnabled": false, "decimals": 8, "name": "zBTC", - "poolAddress": "0x7B58df98a12F54813fDec73B5791642Fa35a52a4", - "poolType": "burnMint", + "pool": { + "address": "0x7B58df98a12F54813fDec73B5791642Fa35a52a4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "zBTC", "tokenAddress": "0x7F544C3a1a16059dd3bbc23AA3BC5c4f5B6969D0" }, @@ -8264,8 +12686,12 @@ "allowListEnabled": false, "decimals": 8, "name": "zBTC", - "poolAddress": "0xe3f4B78cdd20f6B8AE8644064656d3E2bF08c4B8", - "poolType": "burnMint", + "pool": { + "address": "0xe3f4B78cdd20f6B8AE8644064656d3E2bF08c4B8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "zBTC", "tokenAddress": "0x24eCd41CE6646ADa857995A682e1a5c42732cAbc" }, @@ -8273,8 +12699,12 @@ "allowListEnabled": false, "decimals": 8, "name": "zBTC", - "poolAddress": "9EvWTQvZafNxEgpt6snY2sTFT7hARk4tU5QtdRPqoisX", - "poolType": "lockRelease", + "pool": { + "address": "9EvWTQvZafNxEgpt6snY2sTFT7hARk4tU5QtdRPqoisX", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "zBTC", "tokenAddress": "zBTCug3er3tLyffELcvDNrKkCymbPWysGcWihESYfLg" }, @@ -8282,8 +12712,12 @@ "allowListEnabled": false, "decimals": 8, "name": "zBTC", - "poolAddress": "0x66d78C6AF776350F89DA8D63b66008122236ab3e", - "poolType": "burnMint", + "pool": { + "address": "0x66d78C6AF776350F89DA8D63b66008122236ab3e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "zBTC", "tokenAddress": "0x006A22D3120eaD503F0654Be855BCDfbba5Ced72" } @@ -8293,8 +12727,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zentry", - "poolAddress": "0x55c47DE8bCfA02B3989f2B6F9542900E3A2EC6c3", - "poolType": "lockRelease", + "pool": { + "address": "0x55c47DE8bCfA02B3989f2B6F9542900E3A2EC6c3", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "ZENT", "tokenAddress": "0xdBB7a34Bf10169d6d2D0d02A6cbb436cF4381BFa" }, @@ -8302,8 +12740,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zentry", - "poolAddress": "0x52fEd5115D8B7397C09eb4ce2f0a99739891D6B8", - "poolType": "burnMint", + "pool": { + "address": "0x52fEd5115D8B7397C09eb4ce2f0a99739891D6B8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "ZENT", "tokenAddress": "0x9f28c9C2dA4A833cbFaAacbf7eB62267334d7149" } @@ -8313,8 +12755,12 @@ "allowListEnabled": false, "decimals": 6, "name": "ZeUSD", - "poolAddress": "0x04c4032CBCdFDa3c676FA86B5F4b61edE6c8286b", - "poolType": "burnMint", + "pool": { + "address": "0x04c4032CBCdFDa3c676FA86B5F4b61edE6c8286b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "ZeUSD", "tokenAddress": "0x7DC9748DA8E762e569F9269f48F69A1a9F8Ea761" }, @@ -8322,8 +12768,12 @@ "allowListEnabled": false, "decimals": 6, "name": "ZeUSD", - "poolAddress": "0x99874400820c354eE07bC8b165C605632BdCeae3", - "poolType": "lockRelease", + "pool": { + "address": "0x99874400820c354eE07bC8b165C605632BdCeae3", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "ZeUSD", "tokenAddress": "0x7DC9748DA8E762e569F9269f48F69A1a9F8Ea761" } @@ -8333,8 +12783,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Token", - "poolAddress": "0x090D3978b8CaF2832b3CDB0d9d5D34EA0c6Cbd99", - "poolType": "burnMint", + "pool": { + "address": "0x090D3978b8CaF2832b3CDB0d9d5D34EA0c6Cbd99", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "ZUN", "tokenAddress": "0x346E74Dc9935a9b02Eb34fB84658a66010fA056D" }, @@ -8342,8 +12796,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Token", - "poolAddress": "0xBFCFF67cc8a236B25Fc043a4a2b8Bf5B122AdC44", - "poolType": "burnMint", + "pool": { + "address": "0xBFCFF67cc8a236B25Fc043a4a2b8Bf5B122AdC44", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "ZUN", "tokenAddress": "0x1db0Fc8933f545648b54A9eE4326209a9A259643" }, @@ -8351,8 +12809,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Token", - "poolAddress": "0xa01bBE327951B2e441Ed38638927098A272e0F5C", - "poolType": "burnMint", + "pool": { + "address": "0xa01bBE327951B2e441Ed38638927098A272e0F5C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "ZUN", "tokenAddress": "0x25193034153AfB4251a8E02a8Db0DeaeF4C876F6" }, @@ -8360,8 +12822,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Token", - "poolAddress": "0x9c79223e8ce037c39b534891b41b3f306a8FE192", - "poolType": "lockRelease", + "pool": { + "address": "0x9c79223e8ce037c39b534891b41b3f306a8FE192", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "ZUN", "tokenAddress": "0x6b5204B0Be36771253Cc38e88012E02B752f0f36" } @@ -8371,8 +12837,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Omni ETH", - "poolAddress": "0x07d7A985832369eF32F0491aA4CD44fFA9dD4200", - "poolType": "burnMint", + "pool": { + "address": "0x07d7A985832369eF32F0491aA4CD44fFA9dD4200", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "zunETH", "tokenAddress": "0xC9eE652953D8069c5eD37bbB3F8142c6243EFDA0" }, @@ -8380,8 +12850,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Omni ETH", - "poolAddress": "0x9C764e7db0962d5528Bd043109E52c477bafe5db", - "poolType": "burnMint", + "pool": { + "address": "0x9C764e7db0962d5528Bd043109E52c477bafe5db", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "zunETH", "tokenAddress": "0x24CB2B89844604C57350776D81e14765D03b91dE" }, @@ -8389,8 +12863,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Omni ETH", - "poolAddress": "0xC381C7CffD07Fa22f871ae9Ec1025Cee86693B3b", - "poolType": "burnMint", + "pool": { + "address": "0xC381C7CffD07Fa22f871ae9Ec1025Cee86693B3b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "zunETH", "tokenAddress": "0x2d691C2492e056ADCAE7cA317569af25910fC4cb" }, @@ -8398,8 +12876,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami ETH", - "poolAddress": "0xe4832022873C69E14731fd9436eb7FB9538Ae86F", - "poolType": "lockRelease", + "pool": { + "address": "0xe4832022873C69E14731fd9436eb7FB9538Ae86F", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.1" + }, "symbol": "zunETH", "tokenAddress": "0xc2e660C62F72c2ad35AcE6DB78a616215E2F2222" } @@ -8409,8 +12891,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Omni USD", - "poolAddress": "0x68b49DC715214A2D138B0d73A2fC82a87dC8F1C0", - "poolType": "burnMint", + "pool": { + "address": "0x68b49DC715214A2D138B0d73A2fC82a87dC8F1C0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "zunUSD", "tokenAddress": "0xBfEB8B6813491bb4fB823b8f451b62eF535420D1" }, @@ -8418,8 +12904,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Omni USD", - "poolAddress": "0x5800177Ab2cEFd1f7704A4e7eA8A309D98072fCb", - "poolType": "burnMint", + "pool": { + "address": "0x5800177Ab2cEFd1f7704A4e7eA8A309D98072fCb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "zunUSD", "tokenAddress": "0xD5B9dDB04f20eA773C9b56607250149B26049B1F" }, @@ -8427,8 +12917,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami Omni USD", - "poolAddress": "0xD4DC5f4573FE1E39a33C4e4aF8292b925B2E81Fd", - "poolType": "burnMint", + "pool": { + "address": "0xD4DC5f4573FE1E39a33C4e4aF8292b925B2E81Fd", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "zunUSD", "tokenAddress": "0xdC30b3bdE2734A0Bc55AF01B38943ef04aaCB423" }, @@ -8436,8 +12930,12 @@ "allowListEnabled": false, "decimals": 18, "name": "Zunami USD", - "poolAddress": "0x45af366C76a8C8f18806A8C404FE3E3bbA4F8AA3", - "poolType": "lockRelease", + "pool": { + "address": "0x45af366C76a8C8f18806A8C404FE3E3bbA4F8AA3", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "zunUSD", "tokenAddress": "0x8C0D76C9B18779665475F3E212D9Ca1Ed6A1A0e6" } diff --git a/src/config/data/ccip/v1_2_0/mainnet/verifiers.json b/src/config/data/ccip/v1_2_0/mainnet/verifiers.json new file mode 100644 index 00000000000..5bac359e6ed --- /dev/null +++ b/src/config/data/ccip/v1_2_0/mainnet/verifiers.json @@ -0,0 +1,60 @@ +{ + "mainnet": { + "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D": { + "id": "chainlink", + "name": "Chainlink", + "type": "committee" + }, + "0xF4c7E640EdA248ef95972845a62bdC74237805dB": { + "id": "lombard", + "name": "Lombard", + "type": "api" + }, + "0x768a1a3B321126A8B214d7376D48465C7f6Fa061": { + "id": "cctp", + "name": "CCTP", + "type": "api" + }, + "0xcBD48A8eB077381c3c4Eb36b402d7283aB2b11Bc": { + "id": "symbiotic", + "name": "Symbiotic", + "type": "api" + } + }, + "ethereum-mainnet-base-1": { + "0x0aA145a62153190B8f0D3cA00c441e451529f755": { + "id": "chainlink-labs", + "name": "Chainlink Labs", + "type": "committee" + }, + "0x09521B0B5BB2d4406124c0207Cf551829B45f84d": { + "id": "cctp", + "name": "CCTP", + "type": "api" + } + }, + "ethereum-mainnet-arbitrum-1": { + "0xe9c6945281028cb6530d43F998eE539dFE2a9191": { + "id": "chainlink-labs", + "name": "Chainlink Labs", + "type": "committee" + }, + "0xBF38331E34ef7f248020611bB31Be0576D06413D": { + "id": "lombard", + "name": "Lombard", + "type": "api" + } + }, + "ethereum-mainnet-optimism-1": { + "0x2edAc8B8928c4e1Ed559e619b6A8a4aaCe9Ef18A": { + "id": "cctp", + "name": "CCTP", + "type": "api" + }, + "0x76Aa17dCda9E8529149E76e9ffaE4aD1C4AD701B": { + "id": "symbiotic", + "name": "Symbiotic", + "type": "api" + } + } +} diff --git a/src/config/data/ccip/v1_2_0/testnet/chains.json b/src/config/data/ccip/v1_2_0/testnet/chains.json index f18f979bf60..b7972e9037a 100644 --- a/src/config/data/ccip/v1_2_0/testnet/chains.json +++ b/src/config/data/ccip/v1_2_0/testnet/chains.json @@ -86,6 +86,26 @@ "version": "TokenAdminRegistry 1.6.0" } }, + "arc-testnet": { + "armProxy": { + "address": "0xD610B8f58689de7755947C05342A2DFaC30ebD57", + "version": "1.0.0" + }, + "chainSelector": "3034092155422581607", + "feeTokens": ["LINK", "WUSDC"], + "registryModule": { + "address": "0x524B83ae8208490151339c626fd0E35b964483e3", + "version": "1.6.0" + }, + "router": { + "address": "0xdE4E7FED43FAC37EB21aA0643d9852f75332eab8", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0xd3e461C55676B10634a5F81b747c324B85686Dd1", + "version": "1.5.0" + } + }, "avalanche-fuji-testnet": { "armProxy": { "address": "0xAc8CFc3762a979628334a0E4C1026244498E821b", @@ -402,10 +422,30 @@ "version": "1.5.0" } }, + "dogeos-testnet-chikyu": { + "armProxy": { + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.0.0" + }, + "chainSelector": "7254999290874773717", + "feeTokens": ["LINK", "WDOGE"], + "registryModule": { + "address": "0xD610B8f58689de7755947C05342A2DFaC30ebD57", + "version": "1.6.0" + }, + "router": { + "address": "0x524B83ae8208490151339c626fd0E35b964483e3", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0xEAB080c724587fFC9F2EFF82e36EE4Fb27774959", + "version": "1.5.0" + } + }, "ethereum-testnet-holesky": { "armProxy": { "address": "0x8607115fd037d4f182b0eBaEC3cF08Df67080d05", - "version": "1.0.0" + "version": "1.5.0" }, "chainSelector": "7717148896336251131", "feeTokens": ["LINK", "WETH"], @@ -470,6 +510,46 @@ "version": "1.5.1" } }, + "ethereum-testnet-hoodi": { + "armProxy": { + "address": "0xEB5D23FD0CFcd7EB3D16ac6F3A58CAdaF44c2324", + "version": "1.0.0" + }, + "chainSelector": "10380998176179737091", + "feeTokens": ["LINK", "WETH"], + "registryModule": { + "address": "0x19e696e75ccbB3155EEbB579BFa555Fab22293bA", + "version": "1.6.0" + }, + "router": { + "address": "0xc93Dac3422660A41500a24C94BF14616995e3CA6", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0x073b3C71eb4630c4C88F1f72954fdFff30cf3f8D", + "version": "1.5.0" + } + }, + "ethereum-testnet-hoodi-morph": { + "armProxy": { + "address": "0x9A60462e4CA802E3E945663930Be0d162e662091", + "version": "1.0.0" + }, + "chainSelector": "1064004874793747259", + "feeTokens": ["LINK", "WETH"], + "registryModule": { + "address": "0x5Dc49Ec54B92F7D493bC8126c0730DA74605cc00", + "version": "1.6.0" + }, + "router": { + "address": "0xd1CBe8dF481C7a78AaaAfB0466814d13d93bd9b7", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0x65B023D3D4Ea880B835BF2CDE48B296Ee7157EcE", + "version": "1.5.0" + } + }, "ethereum-testnet-sepolia": { "armProxy": { "address": "0xba3f6251de62dED61Ff98590cB2fDf6871FbB991", @@ -966,26 +1046,6 @@ "version": "1.5.1" } }, - "etherlink-testnet": { - "armProxy": { - "address": "0xEC7088f7952ba58f268E25AC3868DF92bF462AEf", - "version": "1.0.0" - }, - "chainSelector": "1910019406958449359", - "feeTokens": ["LINK", "WXTZ"], - "registryModule": { - "address": "0xffA67C26885F6e98c010ecaD7C750D5DbdF5648d", - "version": "1.6.0" - }, - "router": { - "address": "0xa1312a58873fb9a16008E259c3eB972038ba46D9", - "version": "1.2.0" - }, - "tokenAdminRegistry": { - "address": "0x7A635FdfDC70469B6e8796Bd7dEeB3f24fd4f949", - "version": "1.5.0" - } - }, "hedera-testnet": { "armProxy": { "address": "0x0Df355104424BABfb2404600A4258CfE140a78Cf", @@ -1078,6 +1138,26 @@ "version": "1.5.1" } }, + "jovay-testnet": { + "armProxy": { + "address": "0x5Dc49Ec54B92F7D493bC8126c0730DA74605cc00", + "version": "1.0.0" + }, + "chainSelector": "945045181441419236", + "feeTokens": ["LINK", "WETH"], + "registryModule": { + "address": "0xd1CBe8dF481C7a78AaaAfB0466814d13d93bd9b7", + "version": "1.6.0" + }, + "router": { + "address": "0x2016AA303B331bd739Fd072998e579a3052500A6", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0xaCc1C3b214CA255918C9Da66Db3bcc933d57188B", + "version": "1.5.0" + } + }, "kaia-testnet-kairos": { "armProxy": { "address": "0x0a57d85E0CE3AafB22079A4c18B4Eb6D3B88BA46", @@ -1216,21 +1296,21 @@ }, "monad-testnet": { "armProxy": { - "address": "0xaBe6C62737539bEA929647187C3bF13455B33c84", + "address": "0xD610B8f58689de7755947C05342A2DFaC30ebD57", "version": "1.0.0" }, "chainSelector": "2183018362218727504", - "feeTokens": ["LINK", "WMON"], + "feeTokens": ["LINK", "WETH", "WMON"], "registryModule": { - "address": "0x4b90270eAca902fBb9B3bbFd185F82A137a29739", - "version": "1.5.0" + "address": "0x524B83ae8208490151339c626fd0E35b964483e3", + "version": "1.6.0" }, "router": { - "address": "0x5f16e51e3Dcb255480F090157DD01bA962a53E54", + "address": "0x5aD0A67f4Da0E8665a3fbf15E4215A780407Cf33", "version": "1.2.0" }, "tokenAdminRegistry": { - "address": "0x9f4fa39d257cBe5A69F4E4A22a3E8bf62CAF5218", + "address": "0xd3e461C55676B10634a5F81b747c324B85686Dd1", "version": "1.5.0" }, "tokenPoolFactory": { @@ -1377,7 +1457,7 @@ "polygon-testnet-tatara": { "armProxy": { "address": "0xAD8BeA8bC5Fe468Dc1F7BbEce59A86584407255f", - "version": "1.0.0" + "version": "1.5.0" }, "chainSelector": "9090863410735740267", "feeTokens": ["LINK", "WETH"], @@ -1398,30 +1478,6 @@ "version": "1.5.1" } }, - "ronin-testnet-saigon": { - "armProxy": { - "address": "0xf206c6D3f3810eBbD75e7B4684291b5e51023D2f", - "version": "1.0.0" - }, - "chainSelector": "13116810400804392105", - "feeTokens": ["LINK", "WRON"], - "registryModule": { - "address": "0xE31827cd24d7D419fC17E7Ff889BaF62A17991A0", - "version": "1.5.0" - }, - "router": { - "address": "0x0aCAe4e51D3DA12Dd3F45A66e8b660f740e6b820", - "version": "1.2.0" - }, - "tokenAdminRegistry": { - "address": "0x057879f376041D527a98327DE2Ec00F201c9cA25", - "version": "1.5.0" - }, - "tokenPoolFactory": { - "address": "0x9fCd83bC7F67ADa1fB51a4caBEa333c72B641bd1", - "version": "1.5.1" - } - }, "sei-testnet-atlantic": { "armProxy": { "address": "0x754aBd2496Bea05ceDE80Df8bE530f6132208c41", @@ -1488,28 +1544,24 @@ "version": "V1" } }, - "sonic-testnet-blaze": { + "sonic-testnet": { "armProxy": { - "address": "0xD3166538bd1132329d25E34B240E4D44922A07F0", + "address": "0x4F213c8374c4F223eB85d8770Fc76eAd5163FC23", "version": "1.0.0" }, - "chainSelector": "3676871237479449268", + "chainSelector": "1763698235108410440", "feeTokens": ["LINK", "WS"], "registryModule": { - "address": "0xdcF170767E0370CEB4E1fD33C79b32909C50e30E", - "version": "1.5.0" + "address": "0x4D8785d2D1Fa810C0B39A688AEB46146e79a4569", + "version": "1.6.0" }, "router": { - "address": "0x2fBd4659774D468Db5ca5bacE37869905d8EfA34", + "address": "0x5bB5906e88ED789032Cd007D37da60291846E2A3", "version": "1.2.0" }, "tokenAdminRegistry": { - "address": "0xB87d268E7E5d921c72d1D999fa6a2Bfc6A5dBC5C", + "address": "0x22af2fDb6Ec9E5AF82585Ee0efb65b5E46086841", "version": "1.5.0" - }, - "tokenPoolFactory": { - "address": "0x5931822f394baBC2AACF4588E98FC77a9f5aa8C9", - "version": "1.5.1" } }, "superseed-testnet": { @@ -1556,6 +1608,26 @@ "version": "1.5.0" } }, + "tempo-testnet": { + "armProxy": { + "address": "0xc2e1B8e9a765A19315cD9BbbD84a1BB6DC3FC335", + "version": "1.0.0" + }, + "chainSelector": "3963528237232804922", + "feeTokens": ["AlphaUSD", "BetaUSD", "LINK", "ThetaUSD", "WTEMP"], + "registryModule": { + "address": "0x7A635FdfDC70469B6e8796Bd7dEeB3f24fd4f949", + "version": "1.6.0" + }, + "router": { + "address": "0xAE7D1b3D8466718378038de45D4D376E73A04EB6", + "version": "1.2.0" + }, + "tokenAdminRegistry": { + "address": "0xEC7088f7952ba58f268E25AC3868DF92bF462AEf", + "version": "1.5.0" + } + }, "treasure-testnet-topaz": { "armProxy": { "address": "0x43f7b33Aee99208A38e4384655d35D8F0dCe7C51", diff --git a/src/config/data/ccip/v1_2_0/testnet/decom.json b/src/config/data/ccip/v1_2_0/testnet/decom.json index 0145a471b08..fc03031f678 100644 --- a/src/config/data/ccip/v1_2_0/testnet/decom.json +++ b/src/config/data/ccip/v1_2_0/testnet/decom.json @@ -1,5 +1,8 @@ { "ethereum-testnet-sepolia-zircuit-1": { "chainSelector": "4562743618362911021" + }, + "sonic-testnet-blaze": { + "chainSelector": "3676871237479449268" } } diff --git a/src/config/data/ccip/v1_2_0/testnet/lanes.json b/src/config/data/ccip/v1_2_0/testnet/lanes.json index 03d33e90789..f50339cf811 100644 --- a/src/config/data/ccip/v1_2_0/testnet/lanes.json +++ b/src/config/data/ccip/v1_2_0/testnet/lanes.json @@ -23,22 +23,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "apechain-testnet-curtis": { @@ -52,22 +37,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "aptos-testnet": { @@ -81,22 +51,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia": { "offRamp": { @@ -108,22 +63,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -135,22 +75,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -162,22 +87,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-optimism-1": { "offRamp": { @@ -189,22 +99,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ink-testnet-sepolia": { "offRamp": { @@ -217,7 +112,7 @@ "version": "1.6.0" } }, - "sonic-testnet-blaze": { + "xdai-testnet-chiado": { "offRamp": { "address": "0xc748085bd02022a9696dfa2058774f92a07401208bbd34cfd0c6d0ac0287ee45", "version": "1.6.0" @@ -227,30 +122,15 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "xdai-testnet-chiado": { "offRamp": { - "address": "0xc748085bd02022a9696dfa2058774f92a07401208bbd34cfd0c6d0ac0287ee45", + "address": "0xd04a5677Bea8A8D33E493924f429B9D788134849", "version": "1.6.0" }, "onRamp": { - "address": "0xc748085bd02022a9696dfa2058774f92a07401208bbd34cfd0c6d0ac0287ee45", + "address": "0x2016AA303B331bd739Fd072998e579a3052500A6", "enforceOutOfOrder": false, "version": "1.6.0" } @@ -278,36 +158,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia": { "offRamp": { @@ -319,50 +170,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -374,36 +182,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -415,36 +194,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-optimism-1": { "offRamp": { @@ -456,36 +206,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "monad-testnet": { "offRamp": { @@ -508,36 +229,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "polygon-testnet-tatara": { "offRamp": { @@ -571,22 +263,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "solana-devnet": { "offRamp": { @@ -609,36 +286,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "xdai-testnet-chiado": { "offRamp": { @@ -650,36 +298,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "berachain-testnet-bartio": { @@ -778,22 +397,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -831,22 +435,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "bitcoin-testnet-sepolia-bob-1": { @@ -860,22 +449,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "bsc-testnet": { @@ -889,22 +463,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "avalanche-fuji-testnet": { "offRamp": { @@ -916,36 +475,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "bitcoin-testnet-bitlayer-1": { "offRamp": { @@ -979,36 +509,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -1020,36 +521,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-blast-1": { "offRamp": { @@ -1105,36 +577,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "solana-devnet": { "offRamp": { @@ -1146,33 +589,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } - }, - "sonic-testnet-blaze": { - "offRamp": { - "address": "0xb18516F7Fe3c9CB71378fB8aE7BE7292A8f7f296", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x29AC8a55Ed7c1b75b9cD5d94a3448CAd26889F93", - "enforceOutOfOrder": false, - "version": "1.5.0" - } + "supportedTokens": ["CCIP-BnM"] }, "wemix-testnet": { "offRamp": { @@ -1184,36 +601,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "xdai-testnet-chiado": { "offRamp": { @@ -1225,36 +613,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "celo-testnet-alfajores": { @@ -1268,36 +627,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -1346,22 +676,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "cronos-zkevm-testnet-sepolia": { @@ -1377,6 +692,19 @@ } } }, + "dogeos-testnet-chikyu": { + "ethereum-testnet-sepolia": { + "offRamp": { + "address": "0x0EE4b4c364738039663203f8c713BBB797C99777", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xd1CBe8dF481C7a78AaaAfB0466814d13d93bd9b7", + "enforceOutOfOrder": false, + "version": "1.6.0" + } + } + }, "ethereum-testnet-holesky": { "bsc-testnet": { "offRamp": { @@ -1476,22 +804,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "sonic-testnet-blaze": { "offRamp": { @@ -1516,22 +829,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "ethereum-testnet-holesky-taiko-1": { @@ -1544,25 +842,32 @@ "address": "0x583047916FCa33C6b8aAE89EAF64537f35F8b657", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } } } }, + "ethereum-testnet-hoodi": { + "ethereum-testnet-sepolia": { + "offRamp": { + "address": "0x13090F92dd97d5eb6E2C42f3a4709A3a923236d4", + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] + } + }, + "ethereum-testnet-hoodi-morph": { + "ethereum-testnet-sepolia": { + "offRamp": { + "address": "0xa1312a58873fb9a16008E259c3eB972038ba46D9", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xAE7D1b3D8466718378038de45D4D376E73A04EB6", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] + } + }, "ethereum-testnet-sepolia": { "0g-testnet-galileo": { "offRamp": { @@ -1585,22 +890,7 @@ "enforceOutOfOrder": true, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "apechain-testnet-curtis": { "offRamp": { @@ -1612,22 +902,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "aptos-testnet": { "offRamp": { @@ -1638,24 +913,15 @@ "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", "enforceOutOfOrder": true, "version": "1.6.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } } }, + "arc-testnet": { + "offRamp": { + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] + }, "avalanche-fuji-testnet": { "offRamp": { "address": "0x1DEBa99dC8e2A77832461BD386d83D9FCb133137", @@ -1666,50 +932,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC"] }, "berachain-testnet-bartio": { "offRamp": { @@ -1765,22 +988,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "bitcoin-testnet-merlin": { "offRamp": { @@ -1803,22 +1011,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "bitcoin-testnet-sepolia-bob-1": { "offRamp": { @@ -1830,22 +1023,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "bsc-testnet": { "offRamp": { @@ -1857,36 +1035,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "celo-testnet-alfajores": { "offRamp": { @@ -1898,36 +1047,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "core-testnet": { "offRamp": { @@ -1950,22 +1070,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "cronos-zkevm-testnet-sepolia": { "offRamp": { @@ -1978,6 +1083,17 @@ "version": "1.5.0" } }, + "dogeos-testnet-chikyu": { + "offRamp": { + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", + "enforceOutOfOrder": true, + "version": "1.6.0" + } + }, "ethereum-testnet-holesky-fraxtal-1": { "offRamp": { "address": "0x5F1cC8907BE00716Fa0ACE019f5d90239403b83C", @@ -1988,22 +1104,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-holesky-taiko-1": { "offRamp": { @@ -2014,24 +1115,27 @@ "address": "0xbf6dfB39a35ccB747DF6ca4E5F168fe26B5aD5A6", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } } }, + "ethereum-testnet-hoodi": { + "offRamp": { + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] + }, + "ethereum-testnet-hoodi-morph": { + "offRamp": { + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] + }, "ethereum-testnet-sepolia-andromeda-1": { "offRamp": { "address": "0x46DE6201c258f5948135cd0262f91e48Cb8e3828", @@ -2042,36 +1146,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -2083,133 +1158,19 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC", "syrupUSDC"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { - "address": "0x662738DC7DE4f7eC63d9f73Cdf9BeA5A58DdcC15", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x8F35B097022135E0F46831f798a240Cc8c4b0B01", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC", "syrupUSDC"] }, "ethereum-testnet-sepolia-blast-1": { "offRamp": { @@ -2221,36 +1182,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-corn-1": { "offRamp": { @@ -2273,22 +1205,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-lens-1": { "offRamp": { @@ -2311,22 +1228,7 @@ "enforceOutOfOrder": true, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] }, "ethereum-testnet-sepolia-lisk-1": { "offRamp": { @@ -2338,63 +1240,19 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-mantle-1": { "offRamp": { - "address": "0xE41822422d4555D56a1094e083E433AF87E2CaE0", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xE73cE200D9F59C19B3DD4E45935891851116413b", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "syrupUSDT"] }, "ethereum-testnet-sepolia-mode-1": { "offRamp": { @@ -2406,36 +1264,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-optimism-1": { "offRamp": { @@ -2447,50 +1276,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC"] }, "ethereum-testnet-sepolia-polygon-zkevm-1": { "offRamp": { @@ -2502,22 +1288,7 @@ "enforceOutOfOrder": true, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] }, "ethereum-testnet-sepolia-scroll-1": { "offRamp": { @@ -2529,22 +1300,7 @@ "enforceOutOfOrder": true, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] }, "ethereum-testnet-sepolia-soneium-1": { "offRamp": { @@ -2567,36 +1323,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "USDC"] }, "ethereum-testnet-sepolia-worldchain-1": { "offRamp": { @@ -2608,22 +1335,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-xlayer-1": { "offRamp": { @@ -2635,22 +1347,7 @@ "enforceOutOfOrder": true, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] }, "ethereum-testnet-sepolia-zksync-1": { "offRamp": { @@ -2662,47 +1359,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } - }, - "etherlink-testnet": { - "offRamp": { - "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", - "enforceOutOfOrder": false, - "version": "1.6.0" - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "hedera-testnet": { "offRamp": { @@ -2714,22 +1371,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "hemi-testnet-sepolia": { "offRamp": { @@ -2752,22 +1394,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "janction-testnet-sepolia": { "offRamp": { @@ -2780,6 +1407,18 @@ "version": "1.5.0" } }, + "jovay-testnet": { + "offRamp": { + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] + }, "kaia-testnet-kairos": { "offRamp": { "address": "0x2be11937018B7C9959430EBf8AD784e1aebe1981", @@ -2812,22 +1451,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "metal-testnet": { "offRamp": { @@ -2839,22 +1463,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "mind-testnet": { "offRamp": { @@ -2877,32 +1486,17 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "monad-testnet": { "offRamp": { - "address": "0x0722A87F804475a1ae11dea7b48F4c98efF336E9", - "version": "1.5.0" + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" }, "onRamp": { - "address": "0x4241a9515Bb02D44b51F9a5a8c76B9Da84a07d43", + "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" } }, "neox-testnet-t4": { @@ -2937,22 +1531,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "syrupUSDT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["syrupUSDT"] }, "plume-testnet-sepolia": { "offRamp": { @@ -2964,22 +1543,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "polkadot-testnet-astar-shibuya": { "offRamp": { @@ -2991,36 +1555,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "167000000000000000000", - "isEnabled": true, - "rate": "100000000000000000000" - }, - "out": { - "capacity": "167000000000000000000", - "isEnabled": true, - "rate": "100000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "polygon-testnet-amoy": { "offRamp": { @@ -3032,50 +1567,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC"] }, "polygon-testnet-tatara": { "offRamp": { @@ -3098,36 +1590,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "sei-testnet-atlantic": { "offRamp": { @@ -3139,22 +1602,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "shibarium-testnet-puppynet": { "offRamp": { @@ -3166,22 +1614,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "solana-devnet": { "offRamp": { @@ -3193,77 +1626,19 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "USDC", "syrupUSDC"] }, - "sonic-testnet-blaze": { + "sonic-testnet": { "offRamp": { - "address": "0xe4288E56a0b3Ab20164f34E81b1B3cD861C39A10", - "version": "1.5.0" + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" }, "onRamp": { - "address": "0x65ACFD4253d564488DEFB9a24932757C95Af294f", + "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "superseed-testnet": { "offRamp": { @@ -3285,24 +1660,15 @@ "address": "0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE", "enforceOutOfOrder": false, "version": "1.6.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } } }, + "tempo-testnet": { + "offRamp": { + "address": "0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0", + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] + }, "treasure-testnet-topaz": { "offRamp": { "address": "0x25bDd16cD2721baB3D81043ed9742CD8F1f5bF6b", @@ -3324,36 +1690,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "167000000000000000000", - "isEnabled": true, - "rate": "100000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "xdai-testnet-chiado": { "offRamp": { @@ -3365,36 +1702,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "xdc-testnet": { "offRamp": { @@ -3406,22 +1714,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "zora-testnet": { "offRamp": { @@ -3446,36 +1739,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -3500,22 +1764,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "avalanche-fuji-testnet": { "offRamp": { @@ -3527,36 +1776,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "bitcoin-testnet-bsquared-1": { "offRamp": { @@ -3590,64 +1810,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC", "syrupUSDC"] }, "ethereum-testnet-sepolia-andromeda-1": { "offRamp": { @@ -3670,36 +1833,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-hashkey-1": { "offRamp": { @@ -3722,36 +1856,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-soneium-1": { "offRamp": { @@ -3764,17 +1869,6 @@ "version": "1.5.0" } }, - "monad-testnet": { - "offRamp": { - "address": "0xF4EbCC2c077d3939434C7Ab0572660c5A45e4df5", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, "polygon-testnet-amoy": { "offRamp": { "address": "0xB6C02E529D90B55fe64fbC27df6ad7890339A13f", @@ -3796,22 +1890,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "solana-devnet": { "offRamp": { @@ -3823,22 +1902,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "treasure-testnet-topaz": { "offRamp": { @@ -3861,36 +1925,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "xdai-testnet-chiado": { "offRamp": { @@ -3901,37 +1936,14 @@ "address": "0xEfe02eB139D2A82e38184d28E3b65bb176F26ebD", "enforceOutOfOrder": false, "version": "1.5.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } } + }, + "xdc-testnet": { + "offRamp": { + "address": "0xF4EbCC2c077d3939434C7Ab0572660c5A45e4df5", + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "ethereum-testnet-sepolia-base-1": { @@ -3945,22 +1957,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "avalanche-fuji-testnet": { "offRamp": { @@ -3972,36 +1969,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "bsc-testnet": { "offRamp": { @@ -4013,36 +1981,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "celo-testnet-alfajores": { "offRamp": { @@ -4068,72 +2007,15 @@ }, "ethereum-testnet-sepolia": { "offRamp": { - "address": "0x0ecA23Ef70B828fEDd0A84d2692cB0527B52396A", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x29A1F4ecE9246F0042A9062FB89803fA8B1830cB", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "address": "0xF4EbCC2c077d3939434C7Ab0572660c5A45e4df5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", + "enforceOutOfOrder": false, + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC", "syrupUSDC"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -4145,36 +2027,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-hashkey-1": { "offRamp": { @@ -4197,36 +2050,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-optimism-1": { "offRamp": { @@ -4238,36 +2062,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ink-testnet-sepolia": { "offRamp": { @@ -4291,17 +2086,6 @@ "version": "1.6.0" } }, - "monad-testnet": { - "offRamp": { - "address": "0xF4EbCC2c077d3939434C7Ab0572660c5A45e4df5", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, "polygon-testnet-amoy": { "offRamp": { "address": "0x9D20eF141F921048d7A4202A55711c65d316B85b", @@ -4313,20 +2097,9 @@ "version": "1.5.0" } }, - "ronin-testnet-saigon": { + "shibarium-testnet-puppynet": { "offRamp": { - "address": "0x4C14ca01eB15aE9145042F69C1aA4883e192Ed70", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x828Bfd2eBD847C59D8f5bcbBB5e7D2b24111F99e", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "shibarium-testnet-puppynet": { - "offRamp": { - "address": "0x67845BFc4101288bC6a7e14419c4eC988CF7Dd98", + "address": "0x67845BFc4101288bC6a7e14419c4eC988CF7Dd98", "version": "1.5.0" }, "onRamp": { @@ -4334,22 +2107,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "solana-devnet": { "offRamp": { @@ -4361,33 +2119,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } - }, - "sonic-testnet-blaze": { - "offRamp": { - "address": "0x04820DD20aA1f496A58Ae13c660F2098EE889A02", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x28962bE32BD4e512f5213c50aFDCb4fd9a044374", - "enforceOutOfOrder": false, - "version": "1.5.0" - } + "supportedTokens": ["CCIP-BnM"] }, "wemix-testnet": { "offRamp": { @@ -4410,36 +2142,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "ethereum-testnet-sepolia-blast-1": { @@ -4464,36 +2167,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "ethereum-testnet-sepolia-corn-1": { @@ -4531,22 +2205,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -4593,22 +2252,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] } }, "ethereum-testnet-sepolia-lens-1": { @@ -4646,22 +2290,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] }, "ethereum-testnet-sepolia-optimism-1": { "offRamp": { @@ -4673,17 +2302,6 @@ "enforceOutOfOrder": false, "version": "1.5.0" } - }, - "sonic-testnet-blaze": { - "offRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x289639CB51704043213d2E8806d19979eD8533e4", - "enforceOutOfOrder": false, - "version": "1.6.0" - } } }, "ethereum-testnet-sepolia-lisk-1": { @@ -4697,22 +2315,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "ethereum-testnet-sepolia-mantle-1": { @@ -4729,44 +2332,15 @@ }, "ethereum-testnet-sepolia": { "offRamp": { - "address": "0x4073ad4c5c120643A589b57b4482bDc1257a8575", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x73ccF98bE3C5a2CffCCA01948450E2523E73214C", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "address": "0x4d8193f845Eb3540e0BdA9451296600362E22B15", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x056A1FAb28562750a54063E37DDc66d506e320d2", + "enforceOutOfOrder": false, + "version": "1.5.0" + }, + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "syrupUSDT"] } }, "ethereum-testnet-sepolia-mode-1": { @@ -4780,36 +2354,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -4821,36 +2366,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "ethereum-testnet-sepolia-optimism-1": { @@ -4864,22 +2380,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "avalanche-fuji-testnet": { "offRamp": { @@ -4891,36 +2392,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "celo-testnet-alfajores": { "offRamp": { @@ -4943,50 +2415,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -4998,36 +2427,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -5039,36 +2439,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-hashkey-1": { "offRamp": { @@ -5092,17 +2463,6 @@ "version": "1.5.0" } }, - "monad-testnet": { - "offRamp": { - "address": "0x30D197C6F5bE050D5525dD94d01760FaCdB67e7C", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x8F5bED5F7601025b12A97b01584220C12e343986", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, "polygon-testnet-amoy": { "offRamp": { "address": "0x4cEeFa55AF23dFD27Cf926e8eFB1D1bCcD24526E", @@ -5113,36 +2473,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "shibarium-testnet-puppynet": { "offRamp": { @@ -5154,22 +2485,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "solana-devnet": { "offRamp": { @@ -5181,36 +2497,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "USDC"] }, "wemix-testnet": { "offRamp": { @@ -5222,36 +2509,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "xdai-testnet-chiado": { "offRamp": { @@ -5263,36 +2521,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "ethereum-testnet-sepolia-polygon-zkevm-1": { @@ -5306,22 +2535,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] } }, "ethereum-testnet-sepolia-scroll-1": { @@ -5346,22 +2560,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] } }, "ethereum-testnet-sepolia-soneium-1": { @@ -5410,36 +2609,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "USDC"] }, "solana-devnet": { "offRamp": { @@ -5451,22 +2621,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["USDC"] }, "sonic-testnet-blaze": { "offRamp": { @@ -5491,22 +2646,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "solana-devnet": { "offRamp": { @@ -5531,22 +2671,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] } }, "ethereum-testnet-sepolia-zksync-1": { @@ -5560,49 +2685,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } - } - }, - "etherlink-testnet": { - "ethereum-testnet-sepolia": { - "offRamp": { - "address": "0xFA5F1e092dE0907EE761fad89184B8E8AcC9089D", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x1f5EF38782b6B7C6DE489406b8EE504e46F05a18", - "enforceOutOfOrder": false, - "version": "1.6.0" - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "hedera-testnet": { @@ -5616,22 +2699,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "hemi-testnet-sepolia": { @@ -5691,22 +2759,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -5729,29 +2782,49 @@ "enforceOutOfOrder": false, "version": "1.6.0" } - }, - "sonic-testnet-blaze": { + } + }, + "janction-testnet-sepolia": { + "ethereum-testnet-sepolia": { "offRamp": { - "address": "0x113e0b87Cd20AE0038C8414Bd7aed1e4a2D8BE0d", + "address": "0xc076584925d4bc6E935f1251161e620920221dB3", "version": "1.5.0" }, "onRamp": { - "address": "0xc1EC3d311112aA526476d5B3EdDcf0a44872788E", + "address": "0x75626B538CB7bB1854F1716f8c9040D6Dc98D252", "enforceOutOfOrder": false, "version": "1.5.0" } } }, - "janction-testnet-sepolia": { + "jovay-testnet": { "ethereum-testnet-sepolia": { "offRamp": { - "address": "0xc076584925d4bc6E935f1251161e620920221dB3", - "version": "1.5.0" + "address": "0xFA5F1e092dE0907EE761fad89184B8E8AcC9089D", + "version": "1.6.0" }, "onRamp": { - "address": "0x75626B538CB7bB1854F1716f8c9040D6Dc98D252", + "address": "0x1f5EF38782b6B7C6DE489406b8EE504e46F05a18", "enforceOutOfOrder": false, - "version": "1.5.0" + "version": "1.6.0" + } + }, + "pharos-atlantic-testnet": { + "offRamp": { + "address": "0xFA5F1e092dE0907EE761fad89184B8E8AcC9089D", + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] + }, + "polygon-testnet-amoy": { + "offRamp": { + "address": "0xFA5F1e092dE0907EE761fad89184B8E8AcC9089D", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x1f5EF38782b6B7C6DE489406b8EE504e46F05a18", + "enforceOutOfOrder": false, + "version": "1.6.0" } } }, @@ -5792,22 +2865,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -5854,22 +2912,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "mind-testnet": { @@ -5896,22 +2939,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "monad-testnet": { @@ -5926,93 +2954,16 @@ "version": "1.5.0" } }, - "bsc-testnet": { - "offRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x289639CB51704043213d2E8806d19979eD8533e4", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, "ethereum-testnet-sepolia": { "offRamp": { - "address": "0xA3E6DFf295BBC809ea145D48d72fe1414f5F7646", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x43099E299B6d9f77Cda1b2756d53896fcFa2A576", - "enforceOutOfOrder": false, - "version": "1.5.0" - } - }, - "ethereum-testnet-sepolia-arbitrum-1": { - "offRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x289639CB51704043213d2E8806d19979eD8533e4", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-testnet-sepolia-base-1": { - "offRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x289639CB51704043213d2E8806d19979eD8533e4", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "ethereum-testnet-sepolia-optimism-1": { - "offRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x289639CB51704043213d2E8806d19979eD8533e4", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "polygon-testnet-tatara": { - "offRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", + "address": "0x5Dc49Ec54B92F7D493bC8126c0730DA74605cc00", "version": "1.6.0" }, "onRamp": { - "address": "0x289639CB51704043213d2E8806d19979eD8533e4", + "address": "0x65B023D3D4Ea880B835BF2CDE48B296Ee7157EcE", "enforceOutOfOrder": false, "version": "1.6.0" } - }, - "solana-devnet": { - "offRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x289639CB51704043213d2E8806d19979eD8533e4", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - }, - "sonic-testnet-blaze": { - "offRamp": { - "address": "0xb57f58f00b62b3B0038f3C2Dd455afa932d15c50", - "version": "1.5.0" - }, - "onRamp": { - "address": "0x3bA24CC1E4c12b4CAF85189C025028C856C5bdC1", - "enforceOutOfOrder": false, - "version": "1.5.0" - } } }, "neox-testnet-t4": { @@ -6039,6 +2990,17 @@ "enforceOutOfOrder": false, "version": "1.6.0" } + }, + "jovay-testnet": { + "offRamp": { + "address": "0x4D8785d2D1Fa810C0B39A688AEB46146e79a4569", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x22af2fDb6Ec9E5AF82585Ee0efb65b5E46086841", + "enforceOutOfOrder": false, + "version": "1.6.0" + } } }, "plasma-testnet": { @@ -6052,22 +3014,7 @@ "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "syrupUSDT": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["syrupUSDT"] }, "ink-testnet-sepolia": { "offRamp": { @@ -6114,22 +3061,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "polkadot-testnet-astar-shibuya": { @@ -6143,36 +3075,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "167000000000000000000", - "isEnabled": true, - "rate": "100000000000000000000" - }, - "out": { - "capacity": "167000000000000000000", - "isEnabled": true, - "rate": "100000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-soneium-1": { "offRamp": { @@ -6197,36 +3100,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "bsc-testnet": { "offRamp": { @@ -6238,36 +3112,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-holesky": { "offRamp": { @@ -6290,50 +3135,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM", "USDC"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -6367,35 +3169,17 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] + }, + "jovay-testnet": { + "offRamp": { + "address": "0x056A1FAb28562750a54063E37DDc66d506e320d2", + "version": "1.6.0" + }, + "onRamp": { + "address": "0xF4EbCC2c077d3939434C7Ab0572660c5A45e4df5", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, "memento-testnet": { @@ -6419,22 +3203,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["USDC"] }, "wemix-testnet": { "offRamp": { @@ -6446,36 +3215,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "xdai-testnet-chiado": { "offRamp": { @@ -6487,36 +3227,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "polygon-testnet-tatara": { @@ -6541,22 +3252,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia": { "offRamp": { @@ -6568,82 +3264,6 @@ "enforceOutOfOrder": false, "version": "1.5.0" } - }, - "monad-testnet": { - "offRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x289639CB51704043213d2E8806d19979eD8533e4", - "enforceOutOfOrder": false, - "version": "1.6.0" - } - }, - "solana-devnet": { - "offRamp": { - "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", - "version": "1.6.0" - }, - "onRamp": { - "address": "0x289639CB51704043213d2E8806d19979eD8533e4", - "enforceOutOfOrder": true, - "version": "1.6.0" - } - } - }, - "ronin-testnet-saigon": { - "ethereum-testnet-sepolia": { - "offRamp": { - "address": "0x77008Fbd8Ae8f395beF9c6a55905896f3Ead75e9", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xb9E5d491cf85a9D3aCa0171A511301a510a8Ed94", - "enforceOutOfOrder": false, - "version": "1.5.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } - }, - "ethereum-testnet-sepolia-base-1": { - "offRamp": { - "address": "0x7b9b74FB8fB21144c6b49DE796098E3a0dc9C1d0", - "version": "1.5.0" - }, - "onRamp": { - "address": "0xdd5803a6Ab5678213c54D8a976d16d185e9D1CA0", - "enforceOutOfOrder": false, - "version": "1.5.0" - } } }, "sei-testnet-atlantic": { @@ -6656,6 +3276,18 @@ "address": "0x1331D0CC0fC29c5B363e8A46e596eb3629fA287b", "enforceOutOfOrder": false, "version": "1.5.0" + }, + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] + }, + "ethereum-testnet-hoodi": { + "offRamp": { + "address": "0xF4EbCC2c077d3939434C7Ab0572660c5A45e4df5", + "version": "1.6.0" + }, + "onRamp": { + "address": "0x28A025d34c830BF212f5D2357C8DcAB32dD92A20", + "enforceOutOfOrder": false, + "version": "1.6.0" } }, "ethereum-testnet-sepolia": { @@ -6668,22 +3300,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "solana-devnet": { "offRamp": { @@ -6708,22 +3325,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia": { "offRamp": { @@ -6735,22 +3337,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -6762,22 +3349,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -6789,22 +3361,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-optimism-1": { "offRamp": { @@ -6816,22 +3373,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "solana-devnet": { "offRamp": { @@ -6878,22 +3420,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - }, - "out": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia": { "offRamp": { @@ -6905,50 +3432,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - }, - "out": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - } - } - }, - "syrupUSDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "USDC", "syrupUSDC"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -6960,22 +3444,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - }, - "out": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -6987,22 +3456,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - }, - "out": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-optimism-1": { "offRamp": { @@ -7014,36 +3468,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - }, - "out": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - } - } - }, - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "USDC"] }, "ethereum-testnet-sepolia-unichain-1": { "offRamp": { @@ -7055,22 +3480,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["USDC"] }, "ethereum-testnet-sepolia-worldchain-1": { "offRamp": { @@ -7126,33 +3536,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "USDC": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } - }, - "polygon-testnet-tatara": { - "offRamp": { - "address": "offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm", - "version": "1.6.0" - }, - "onRamp": { - "address": "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C", - "enforceOutOfOrder": true, - "version": "1.6.0" - } + "supportedTokens": ["USDC"] }, "sei-testnet-atlantic": { "offRamp": { @@ -7186,51 +3570,21 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - }, - "out": { - "capacity": "100000000000000", - "isEnabled": true, - "rate": "167000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, - "sonic-testnet-blaze": { - "aptos-testnet": { + "sonic-testnet": { + "ethereum-testnet-sepolia": { "offRamp": { - "address": "0xF094E1dB26Ce8C76C9fF0bD0566Bb8EEfF1b76dd", + "address": "0xbc9A4b299741CBf2A8eD5D2078A426027C31B2A3", "version": "1.6.0" }, "onRamp": { - "address": "0x384C8843411f725e800E625d5d1B659256D629dF", - "enforceOutOfOrder": true, + "address": "0xca4C185DEDabaA63876b794E77Ca7a68f08DB485", + "enforceOutOfOrder": false, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "bsc-testnet": { "offRamp": { @@ -7264,22 +3618,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -7346,22 +3685,7 @@ "enforceOutOfOrder": true, "version": "1.6.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM"] } }, "superseed-testnet": { @@ -7387,25 +3711,18 @@ "address": "0x30D197C6F5bE050D5525dD94d01760FaCdB67e7C", "enforceOutOfOrder": false, "version": "1.6.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } } } }, + "tempo-testnet": { + "ethereum-testnet-sepolia": { + "offRamp": { + "address": "0x948cfD1C48C52a93D23Ace2CfB4D2abACc0Ada29", + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] + } + }, "treasure-testnet-topaz": { "ethereum-testnet-sepolia": { "offRamp": { @@ -7441,36 +3758,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "bsc-testnet": { "offRamp": { @@ -7482,36 +3770,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia": { "offRamp": { @@ -7523,36 +3782,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -7564,36 +3794,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -7616,22 +3817,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-LnM"] }, "ethereum-testnet-sepolia-optimism-1": { "offRamp": { @@ -7643,36 +3829,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "polygon-testnet-amoy": { "offRamp": { @@ -7684,36 +3841,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "xdai-testnet-chiado": { @@ -7738,36 +3866,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "bsc-testnet": { "offRamp": { @@ -7779,36 +3878,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia": { "offRamp": { @@ -7820,36 +3890,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-arbitrum-1": { "offRamp": { @@ -7861,36 +3902,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-base-1": { "offRamp": { @@ -7902,36 +3914,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "ethereum-testnet-sepolia-optimism-1": { "offRamp": { @@ -7943,36 +3926,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] }, "plasma-testnet": { "offRamp": { @@ -7995,36 +3949,7 @@ "enforceOutOfOrder": false, "version": "1.5.0" }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - }, - "CCIP-LnM": { - "rateLimiterConfig": { - "in": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - }, - "out": { - "capacity": "100000000000000000000000", - "isEnabled": true, - "rate": "167000000000000000000" - } - } - } - } + "supportedTokens": ["CCIP-BnM", "CCIP-LnM"] } }, "xdc-testnet": { @@ -8037,23 +3962,14 @@ "address": "0x30D197C6F5bE050D5525dD94d01760FaCdB67e7C", "enforceOutOfOrder": false, "version": "1.6.0" - }, - "supportedTokens": { - "CCIP-BnM": { - "rateLimiterConfig": { - "in": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - }, - "out": { - "capacity": "0", - "isEnabled": false, - "rate": "0" - } - } - } } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "offRamp": { + "address": "0x9A60462e4CA802E3E945663930Be0d162e662091", + "version": "1.6.0" + }, + "supportedTokens": ["CCIP-BnM"] } }, "zora-testnet": { diff --git a/src/config/data/ccip/v1_2_0/testnet/tokens.json b/src/config/data/ccip/v1_2_0/testnet/tokens.json index 93eb74fcf63..1a77404dc49 100644 --- a/src/config/data/ccip/v1_2_0/testnet/tokens.json +++ b/src/config/data/ccip/v1_2_0/testnet/tokens.json @@ -1,21 +1,39 @@ { + "AlphaUSD": { + "tempo-testnet": { + "allowListEnabled": false, + "decimals": 6, + "name": "AlphaUSD", + "poolType": "feeTokenOnly", + "symbol": "AlphaUSD", + "tokenAddress": "0x20C0000000000000000000000000000000000001" + } + }, "APT": { "aptos-testnet": { "allowListEnabled": false, "decimals": 8, "name": "Aptos Coin", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "APT", "tokenAddress": "0x000000000000000000000000000000000000000000000000000000000000000A" } }, - "CCIP-BnM": { - "abstract-testnet": { + "BetaUSD": { + "tempo-testnet": { "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xAA1Bbe60dE447706e8E676edB6dbFfe8Cf7BB69a", - "poolType": "burnMint", + "pool": { + "address": "0xAA1Bbe60dE447706e8E676edB6dbFfe8Cf7BB69a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x596b8A0A2A63E5B4b2c0e201c4C27078642c8509" }, @@ -23,8 +41,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x812E0EaB33c1A34Ff651bfBD63Cd3A8AcD63b2F5", - "poolType": "burnMint", + "pool": { + "address": "0x812E0EaB33c1A34Ff651bfBD63Cd3A8AcD63b2F5", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xF48cae4B1F4EB3a1682600D4F3aFA166db5B162E" }, @@ -32,8 +54,12 @@ "allowListEnabled": false, "decimals": 8, "name": "CCIP-BnM", - "poolAddress": "0x65ad4cb3142cab5100a4eeed34e2005cbb1fcae42fc688e3c96b0c33ae16e6b9", - "poolType": "burnMint", + "pool": { + "address": "0x65ad4cb3142cab5100a4eeed34e2005cbb1fcae42fc688e3c96b0c33ae16e6b9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xa680c9935c7ea489676fa0e01f1ff8a97fadf0cb35e1e06ba1ba32ecd882fc9a" }, @@ -41,8 +67,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x10e3A37ff21c20CD802fdAF0204e2Ff04e5485ee", - "poolType": "burnMint", + "pool": { + "address": "0x10e3A37ff21c20CD802fdAF0204e2Ff04e5485ee", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4" }, @@ -50,8 +80,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x05D5c0CAA8ab3f4Fb8627956ed027039e854f16A", - "poolType": "burnMint", + "pool": { + "address": "0x05D5c0CAA8ab3f4Fb8627956ed027039e854f16A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x0643fD73C261eC4B369C3a8C5c0eC8c57485E32d" }, @@ -59,8 +93,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x71Da9f1fbc06f0C3364fA066C4aa8280886Ca79e", - "poolType": "burnMint", + "pool": { + "address": "0x71Da9f1fbc06f0C3364fA066C4aa8280886Ca79e", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xEc9c9E6A862BA7aee87731110a01A2f087EC7ECc" }, @@ -68,8 +106,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xE5AA8132cC86c2618a55723A3418EA7ED5FFf074", - "poolType": "burnMint", + "pool": { + "address": "0xE5AA8132cC86c2618a55723A3418EA7ED5FFf074", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x3B7d0d0CeC08eBF8dad58aCCa4719791378b2329" }, @@ -77,8 +119,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x9F49971B7c86E258f25f5A2E1fe740c0e1B903F1", - "poolType": "burnMint", + "pool": { + "address": "0x9F49971B7c86E258f25f5A2E1fe740c0e1B903F1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xbFA2ACd33ED6EEc0ed3Cc06bF1ac38d22b36B9e9" }, @@ -86,8 +132,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x0833975C065e821C84bE70C4935916579b5a0731", - "poolType": "burnMint", + "pool": { + "address": "0x0833975C065e821C84bE70C4935916579b5a0731", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x7e503dd1dAF90117A1b79953321043d9E6815C72" }, @@ -95,8 +145,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xe6fAb999cA267205AB4c55D4a0319794A0d0C082", - "poolType": "burnMint", + "pool": { + "address": "0xe6fAb999cA267205AB4c55D4a0319794A0d0C082", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x028E1B6f424c5A96E4bD5e1bbaB8b3C9088e5D39" }, @@ -104,8 +158,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xcF8830447D5D7A02f0f5e0406C29FA3B7E27EB57", - "poolType": "burnMint", + "pool": { + "address": "0xcF8830447D5D7A02f0f5e0406C29FA3B7E27EB57", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xdd578844095DB1837A96c353F8f237f6cDC79bED" }, @@ -113,8 +171,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xd959A5B20e0CD198eE16300977079E4b7742e3f1", - "poolType": "burnMint", + "pool": { + "address": "0xd959A5B20e0CD198eE16300977079E4b7742e3f1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x6122841A203d34Cd3087c3C19d04d101F6FaF8e8" }, @@ -122,17 +184,38 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xe3C755bE5409ACb76944B6Fee83413f080503885", - "poolType": "burnMint", + "pool": { + "address": "0xe3C755bE5409ACb76944B6Fee83413f080503885", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x54B50385e417469dbdb697f40651e8864664D992" }, + "ethereum-testnet-hoodi-morph": { + "allowListEnabled": false, + "decimals": 18, + "name": "CCIP-BnM", + "pool": { + "address": "0x693926456C8b210f56E29Bc5b4514B32A5224c88", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, + "symbol": "CCIP-BnM", + "tokenAddress": "0x69521081Fd90669b59b1Cb3F67a2229D36a7De00" + }, "ethereum-testnet-sepolia": { "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x4CcbDd6CF18800360161E4D2A519A2047176bDF0", - "poolType": "burnMint", + "pool": { + "address": "0x4CcbDd6CF18800360161E4D2A519A2047176bDF0", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xFd57b4ddBf88a4e07fF4e34C487b99af2Fe82a05" }, @@ -140,8 +223,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x01Fc8b86A16279F3f9302B20949Bd3Aba9AC7D9a", - "poolType": "burnMint", + "pool": { + "address": "0x01Fc8b86A16279F3f9302B20949Bd3Aba9AC7D9a", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x20Aa09AAb761e2E600d65c6929A9fd1E59821D3f" }, @@ -149,8 +236,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x4d27Ff41AeC442562215a2CE1407cE252807890c", - "poolType": "burnMint", + "pool": { + "address": "0x4d27Ff41AeC442562215a2CE1407cE252807890c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xA8C0c11bf64AF62CDCA6f93D3769B88BdD7cb93D" }, @@ -158,8 +249,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x3C12a7dA5234d1080C46baABC05efB8Fde00816b", - "poolType": "burnMint", + "pool": { + "address": "0x3C12a7dA5234d1080C46baABC05efB8Fde00816b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x88A2d74F47a237a62e7A51cdDa67270CE381555e" }, @@ -167,8 +262,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x8D7Db7B563606DbDA8e5FD57d0BAdcAE6914212E", - "poolType": "burnMint", + "pool": { + "address": "0x8D7Db7B563606DbDA8e5FD57d0BAdcAE6914212E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x8D122C3e8ce9C8B62b87d3551bDfD8C259Bb0771" }, @@ -176,8 +275,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xedFb4A5171A34024F5908627CE186a14d01AeF4A", - "poolType": "burnMint", + "pool": { + "address": "0xedFb4A5171A34024F5908627CE186a14d01AeF4A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xB0F91Ce2ECAa3555D4b1fD4489bD9a207a7844f0" }, @@ -185,8 +288,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x5027F0B1a3ac0c531750B96f419573B426A37eE3", - "poolType": "burnMint", + "pool": { + "address": "0x5027F0B1a3ac0c531750B96f419573B426A37eE3", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x03B2F16FC12010d2e35055092055674645C38378" }, @@ -194,8 +301,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xCa0d36eC52dA4b466f2bAd1A97C6130775870b78", - "poolType": "burnMint", + "pool": { + "address": "0xCa0d36eC52dA4b466f2bAd1A97C6130775870b78", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xEA8cA8AE1c54faB8D185FC1fd7C2d70Bee8a417e" }, @@ -203,8 +314,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x7ECBE3416d92E8d79C8e5d8EB8Aad5DdEdAa0237", - "poolType": "burnMint", + "pool": { + "address": "0x7ECBE3416d92E8d79C8e5d8EB8Aad5DdEdAa0237", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xB9d4e1141E67ECFedC8A8139b5229b7FF2BF16F5" }, @@ -212,8 +327,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x95A7B37D1958D25eD1758edc930B47e5616b7226", - "poolType": "burnMint", + "pool": { + "address": "0x95A7B37D1958D25eD1758edc930B47e5616b7226", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x8aF4204e30565DF93352fE8E1De78925F6664dA7" }, @@ -221,8 +340,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x08389B66018D77fbe1d48CA21D127E804f8a6a2C", - "poolType": "burnMint", + "pool": { + "address": "0x08389B66018D77fbe1d48CA21D127E804f8a6a2C", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x6122841A203d34Cd3087c3C19d04d101F6FaF8e8" }, @@ -230,8 +353,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xb92d527977768075926D3f6C134D3700f39AF788", - "poolType": "burnMint", + "pool": { + "address": "0xb92d527977768075926D3f6C134D3700f39AF788", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x8fdE0C794fDA5a7A303Ce216f79B9695a7714EcB" }, @@ -239,8 +366,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x979f90eC3444e7E6E8567EF26998C6328Ca637E2", - "poolType": "burnMint", + "pool": { + "address": "0x979f90eC3444e7E6E8567EF26998C6328Ca637E2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xFf6d0c1518A8104611f482eb2801CaF4f13c9dEb" }, @@ -248,8 +379,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xd3870F30fe8730A0760C02C24b2de36Ad97FAa18", - "poolType": "burnMint", + "pool": { + "address": "0xd3870F30fe8730A0760C02C24b2de36Ad97FAa18", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x01Ac06943d2B8327a7845235Ef034741eC1Da352" }, @@ -257,17 +392,38 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x4B07cd55bbD45C9df160C54C62c3933c26594C6A", - "poolType": "burnMint", + "pool": { + "address": "0x4B07cd55bbD45C9df160C54C62c3933c26594C6A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x414dbe1d58dd9BA7C84f7Fc0e4f82bc858675d37" }, + "jovay-testnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "CCIP-BnM", + "pool": { + "address": "0x2bF249E1796D5F3a293dFB0B084f52bF5D3f35CB", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, + "symbol": "CCIP-BnM", + "tokenAddress": "0xB45B9eb94F25683B47e5AFb0f74A05a58be86311" + }, "memento-testnet": { "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xefE6Aa4551184612ABe166ccEe032e0eda748e9b", - "poolType": "burnMint", + "pool": { + "address": "0xefE6Aa4551184612ABe166ccEe032e0eda748e9b", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x62325603b3550CbF763cb47F9Fe081dD977e728a" }, @@ -275,8 +431,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x996EfAb6011896Be832969D91E9bc1b3983cfdA1", - "poolType": "burnMint", + "pool": { + "address": "0x996EfAb6011896Be832969D91E9bc1b3983cfdA1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xbD6F12f358D8ee3b35B0AD612450a186bA866B72" }, @@ -284,8 +444,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x0643fD73C261eC4B369C3a8C5c0eC8c57485E32d", - "poolType": "burnMint", + "pool": { + "address": "0x0643fD73C261eC4B369C3a8C5c0eC8c57485E32d", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x56408DC41E35d3E8E92A16bc94787438df9387a1" }, @@ -293,8 +457,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x8D7Db7B563606DbDA8e5FD57d0BAdcAE6914212E", - "poolType": "burnMint", + "pool": { + "address": "0x8D7Db7B563606DbDA8e5FD57d0BAdcAE6914212E", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x225fAc4130595d1C7dabbE61A8bA9B051440b76c" }, @@ -302,8 +470,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x812cF48d7e39107f19f580104eCCf7C4F6c162EE", - "poolType": "burnMint", + "pool": { + "address": "0x812cF48d7e39107f19f580104eCCf7C4F6c162EE", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xc49ec0eB4beb48B8Da4cceC51AA9A5bD0D0A4c43" }, @@ -311,8 +483,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x4122fe199B6e489a89f54c67245Be33bf602935F", - "poolType": "burnMint", + "pool": { + "address": "0x4122fe199B6e489a89f54c67245Be33bf602935F", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xcab0EF91Bee323d1A617c0a027eE753aFd6997E4" }, @@ -320,8 +496,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x9116547A104C4Bb2531EacdC5A6695019eea5387", - "poolType": "burnMint", + "pool": { + "address": "0x9116547A104C4Bb2531EacdC5A6695019eea5387", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xc3B04ce056D8E44AA43BE1e23D554ef2AA3a9f58" }, @@ -329,8 +509,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x15A542b074B1ec3a52F2B3eC91efc15ECf6f24dC", - "poolType": "burnMint", + "pool": { + "address": "0x15A542b074B1ec3a52F2B3eC91efc15ECf6f24dC", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x88DD2416699Bad3AeC58f535BC66F7f62DE2B2EC" }, @@ -338,8 +522,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x5B0340e56135eA391ceb64f1B5df65BD838B6365", - "poolType": "burnMint", + "pool": { + "address": "0x5B0340e56135eA391ceb64f1B5df65BD838B6365", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x271F22d029c6edFc9469faE189C4F43E457F257C" }, @@ -347,8 +535,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x694f112E941472c8806b853Db714c29387396FBb", - "poolType": "burnMint", + "pool": { + "address": "0x694f112E941472c8806b853Db714c29387396FBb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x81249b4bD91A8706eE67a2f422DB82258D4947ad" }, @@ -356,17 +548,25 @@ "allowListEnabled": false, "decimals": 9, "name": "CCIP-BnM", - "poolAddress": "BqGg42v35Ghuigi4smWU9KKQTUnQb5ATocDbJikHjocS", - "poolType": "burnMint", + "pool": { + "address": "BqGg42v35Ghuigi4smWU9KKQTUnQb5ATocDbJikHjocS", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6" }, - "sonic-testnet-blaze": { + "sonic-testnet": { "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xB31e0A1A02bce6a8386C812f1dD80572f6f3a717", - "poolType": "burnMint", + "pool": { + "address": "0xB31e0A1A02bce6a8386C812f1dD80572f6f3a717", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x230c46b9a7c8929A80863bDe89082B372a4c7A99" }, @@ -374,8 +574,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x82087E24B4C5f0a1fc8A3Feef10657420A5690C4", - "poolType": "burnMint", + "pool": { + "address": "0x82087E24B4C5f0a1fc8A3Feef10657420A5690C4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x4Bc8740F54eC7CD6738f19ff00438bFE3DCbceB3" }, @@ -383,8 +587,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xD2c13079256523607EA273422f41956F9205653c", - "poolType": "burnMint", + "pool": { + "address": "0xD2c13079256523607EA273422f41956F9205653c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xF4E4057FbBc86915F4b2d63EEFFe641C03294ffc" }, @@ -392,8 +600,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0xA3Ab1330b7275402A38e02Bd22F237CD6B2c68Fb", - "poolType": "burnMint", + "pool": { + "address": "0xA3Ab1330b7275402A38e02Bd22F237CD6B2c68Fb", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "CCIP-BnM", "tokenAddress": "0xA189971a2c5AcA0DFC5Ee7a2C44a2Ae27b3CF389" }, @@ -401,8 +613,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-BnM", - "poolAddress": "0x61876F0429726D7777B46f663e1C9ab75d08Fc56", - "poolType": "burnMint", + "pool": { + "address": "0x61876F0429726D7777B46f663e1C9ab75d08Fc56", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "CCIP-BnM", "tokenAddress": "0x1350D63CAEc50778A132e1Ab85D43a3B50FD61dD" } @@ -412,8 +628,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x8e35eB0dfb39Ec5F84254C3f863986a913171E0B", - "poolType": "burnMint", + "pool": { + "address": "0x8e35eB0dfb39Ec5F84254C3f863986a913171E0B", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x70F5c5C40b873EA597776DA2C21929A8282A3b35" }, @@ -421,8 +641,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0xc3b32Cc1e0207648d174d38AfD659332D4d11341", - "poolType": "burnMint", + "pool": { + "address": "0xc3b32Cc1e0207648d174d38AfD659332D4d11341", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x79a4Fc27f69323660f5Bfc12dEe21c3cC14f5901" }, @@ -430,8 +654,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x049627974516Eb171FD91EdE659a291e17836eD7", - "poolType": "burnMint", + "pool": { + "address": "0x049627974516Eb171FD91EdE659a291e17836eD7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x7F4e739D40E58BBd59dAD388171d18e37B26326f" }, @@ -439,8 +667,12 @@ "allowListEnabled": false, "decimals": 18, "name": "CCIP-LnM", - "poolAddress": "0x658FdaC59a197D5166151640b7a673F7dF1Ba324", - "poolType": "lockRelease", + "pool": { + "address": "0x658FdaC59a197D5166151640b7a673F7dF1Ba324", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "CCIP-LnM", "tokenAddress": "0x466D489b6d36E7E3b824ef491C225F5830E81cC1" }, @@ -448,8 +680,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0xC64011eD08A2263F87AE8eF05b7d41EfC91f4AFD", - "poolType": "burnMint", + "pool": { + "address": "0xC64011eD08A2263F87AE8eF05b7d41EfC91f4AFD", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x705b364CadE0e515577F2646529e3A417473a155" }, @@ -457,8 +693,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x056B16D54bCAea1C14036Bb78Fe8338d892F0262", - "poolType": "burnMint", + "pool": { + "address": "0x056B16D54bCAea1C14036Bb78Fe8338d892F0262", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x139E99f0ab4084E14e6bb7DacA289a91a2d92927" }, @@ -466,8 +706,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0xB8937715574FC00a88408582C8406653a16495D7", - "poolType": "burnMint", + "pool": { + "address": "0xB8937715574FC00a88408582C8406653a16495D7", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0xA98FA8A008371b9408195e52734b1768c0d1Cb5c" }, @@ -475,8 +719,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x4bd6F0785Cbe5200EBc98c1496e29C279E18ABDe", - "poolType": "burnMint", + "pool": { + "address": "0x4bd6F0785Cbe5200EBc98c1496e29C279E18ABDe", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x35347A2fC1f2a4c5Eae03339040d0b83b09e6FDA" }, @@ -484,8 +732,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0xa77c73A8b6239377B2648Af55d2B4501aCB1A46A", - "poolType": "burnMint", + "pool": { + "address": "0xa77c73A8b6239377B2648Af55d2B4501aCB1A46A", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x835fcBB6770E1246CfCf52F83cDcec3177d0bb6b" }, @@ -493,8 +745,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0xcDD99Ac87b8e5B0E39f47a024f7189a74c1128E4", - "poolType": "burnMint", + "pool": { + "address": "0xcDD99Ac87b8e5B0E39f47a024f7189a74c1128E4", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0xA7EA79b9E466e8D2a440128867ed399bC78f4aaE" }, @@ -502,8 +758,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x2979C66FaBb41f67451F0BcB2A668382f92959a1", - "poolType": "burnMint", + "pool": { + "address": "0x2979C66FaBb41f67451F0BcB2A668382f92959a1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0xCdeE7708A96479f6D029741144f458B7FA807A6C" }, @@ -511,8 +771,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x31C110BaffaADc5a0eC9738cD8C6670123C1926c", - "poolType": "burnMint", + "pool": { + "address": "0x31C110BaffaADc5a0eC9738cD8C6670123C1926c", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x86f9Eed8EAD1534D87d23FbAB247D764fC725D49" }, @@ -520,8 +784,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x69B5126A10582063B17fa3b614C5Ac6b0f1D23Ba", - "poolType": "burnMint", + "pool": { + "address": "0x69B5126A10582063B17fa3b614C5Ac6b0f1D23Ba", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x044a6B4b561af69D2319A2f4be5Ec327a6975D0a" }, @@ -529,8 +797,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x036bf900C4690961ad5AE8f104547824C76583c1", - "poolType": "burnMint", + "pool": { + "address": "0x036bf900C4690961ad5AE8f104547824C76583c1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0xA4C9e2108ca478DE0B91c7D9Ba034bbc93C22Ecc" }, @@ -538,8 +810,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x08aa3aeB96bd89D0228f2d3373A5cEE453F7a304", - "poolType": "burnMint", + "pool": { + "address": "0x08aa3aeB96bd89D0228f2d3373A5cEE453F7a304", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x0298e204F9131d45EEb436D693f32C6eA1190622" }, @@ -547,8 +823,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x48d73fcEc510aCED85E7aC288A896AB614C73Af2", - "poolType": "burnMint", + "pool": { + "address": "0x48d73fcEc510aCED85E7aC288A896AB614C73Af2", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0xd70f29744f03F10b7EC2443Bd294B7E62D654c5b" }, @@ -556,8 +836,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x06f1097Ec4376964fE32153F72ea39CA35679992", - "poolType": "burnMint", + "pool": { + "address": "0x06f1097Ec4376964fE32153F72ea39CA35679992", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "LnM", "tokenAddress": "0xBf8eA19505ab7Eb266aeD435B11bd56321BFB5c5" }, @@ -565,8 +849,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x2B758a239f6B8Fb422d069B1b04A7b8c2A60209D", - "poolType": "burnMint", + "pool": { + "address": "0x2B758a239f6B8Fb422d069B1b04A7b8c2A60209D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0xB9d4e1141E67ECFedC8A8139b5229b7FF2BF16F5" }, @@ -574,8 +862,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0xb15799a06A69cf4E825F3b0F3082903E09E0Ecc1", - "poolType": "burnMint", + "pool": { + "address": "0xb15799a06A69cf4E825F3b0F3082903E09E0Ecc1", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.0" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x3d357fb52253e86c8Ee0f80F5FfE438fD9503FF2" }, @@ -583,8 +875,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0x17a9049600902Ba429B3A5761d02A9C4E052eE40", - "poolType": "burnMint", + "pool": { + "address": "0x17a9049600902Ba429B3A5761d02A9C4E052eE40", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x04B1F917a3ba69Fa252564414DdAFc82fA1B5178" }, @@ -592,8 +888,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0xC212AD0E6EBE962a3626509A0efE363380c30F46", - "poolType": "burnMint", + "pool": { + "address": "0xC212AD0E6EBE962a3626509A0efE363380c30F46", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0xcb342aE3D65E3fEDF8F912B0432e2B8F88514d5D" }, @@ -601,8 +901,12 @@ "allowListEnabled": false, "decimals": 18, "name": "clCCIP-LnM", - "poolAddress": "0xe036d1B13B108f1f5DFF25EB2e66538a8DcC07c9", - "poolType": "burnMint", + "pool": { + "address": "0xe036d1B13B108f1f5DFF25EB2e66538a8DcC07c9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "clCCIP-LnM", "tokenAddress": "0x30DeCD269277b8094c00B0bacC3aCaF3fF4Da7fB" } @@ -612,7 +916,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Frax Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "frxETH", "tokenAddress": "0xFC00000000000000000000000000000000000006" } @@ -622,7 +930,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xd211Bd4ff8fd68C16016C5c7a66b6e10F6227C49" }, @@ -630,7 +942,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x6641415a61bCe80D97a715054d1334360Ab833Eb" }, @@ -638,7 +954,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xa787B3E0471b718bBfEaA59B502fd0C4EBd7b74E" }, @@ -646,23 +966,43 @@ "allowListEnabled": false, "decimals": 8, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x3d5d565c271d6b9c52f1a963f2b7bddad3453b0de2ace5e254b8db6549cc335e" }, - "avalanche-fuji-testnet": { + "arc-testnet": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", "poolType": "feeTokenOnly", "symbol": "LINK", + "tokenAddress": "0x3F1f176e347235858DD6Db905DDBA09Eaf25478a" + }, + "avalanche-fuji-testnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, + "symbol": "LINK", "tokenAddress": "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846" }, "berachain-testnet-bartio": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x52CEEed7d3f8c6618e4aaD6c6e555320d0D83271" }, @@ -670,7 +1010,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x56E16E648c51609A14Eb14B99BAB771Bee797045" }, @@ -678,7 +1022,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x2A5bACb2440BC17D53B7b9Be73512dDf92265e48" }, @@ -686,7 +1034,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x7311DED199CC28D80E58e81e8589aa160199FCD2" }, @@ -694,7 +1046,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x436a1907D9e6a65E6db73015F08f9C66F6B63E45" }, @@ -702,7 +1058,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xB904d5b9a1e74F6576fFF550EeE75Eaa68e2dd50" }, @@ -710,7 +1070,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x39dD98CcCC3a51b2c0007e23517488e363581264" }, @@ -718,7 +1082,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xcd2AfB2933391E35e8682cbaaF75d9CA7339b183" }, @@ -726,7 +1094,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06" }, @@ -734,7 +1106,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x32E08557B14FaD8908025619797221281D439071" }, @@ -742,7 +1118,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x6C475841d1D7871940E93579E5DBaE01634e17aA" }, @@ -750,7 +1130,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x2896e619Fa7c831A7E52b87EffF4d671bEc6B262" }, @@ -758,23 +1142,43 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xB96217A159cB11Bc51E87c8CAe46C7dF8826A827" }, - "ethereum-testnet-holesky": { + "dogeos-testnet-chikyu": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", "poolType": "feeTokenOnly", "symbol": "LINK", + "tokenAddress": "0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" + }, + "ethereum-testnet-holesky": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, + "symbol": "LINK", "tokenAddress": "0x685cE6742351ae9b618F383883D6d1e0c5A31B4B" }, "ethereum-testnet-holesky-fraxtal-1": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xb192c5Fb8e33694F0CFD4357806a63dc59feEBEF" }, @@ -782,23 +1186,55 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x01fcdEedbA59bc68b0914D92277678dAB6827e2c" }, - "ethereum-testnet-sepolia": { + "ethereum-testnet-hoodi": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", "poolType": "feeTokenOnly", "symbol": "LINK", + "tokenAddress": "0x76c00B055414de203B79B4955E28119BF459033e" + }, + "ethereum-testnet-hoodi-morph": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, + "symbol": "LINK", + "tokenAddress": "0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" + }, + "ethereum-testnet-sepolia": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, + "symbol": "LINK", "tokenAddress": "0x779877A7B0D9E8603169DdbD7836e478b4624789" }, "ethereum-testnet-sepolia-andromeda-1": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x9870D6a0e05F867EAAe696e106741843F7fD116D" }, @@ -806,7 +1242,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xb1D4538B4571d411F07960EF2838Ce337FE1E80E" }, @@ -814,7 +1254,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xE4aB69C077896252FAFBD49EFD26B5D171A32410" }, @@ -822,7 +1266,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x02c359ebf98fc8BF793F970F9B8302bb373BdF32" }, @@ -830,7 +1278,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x996EfAb6011896Be832969D91E9bc1b3983cfdA1" }, @@ -838,7 +1290,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x8418c4d7e8e17ab90232DC72150730E6c4b84F57" }, @@ -846,7 +1302,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xa75cCA5b404ec6F4BB6EC4853D177FE7057085c8" }, @@ -854,7 +1314,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x7f1b9eE544f9ff9bB521Ab79c205d79C55250a36" }, @@ -862,7 +1326,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xF64E6E064a71B45514691D397ad4204972cD6508" }, @@ -870,7 +1338,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x6641415a61bCe80D97a715054d1334360Ab833Eb" }, @@ -878,7 +1350,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x22bdEdEa0beBdD7CfFC95bA53826E55afFE9DE04" }, @@ -886,7 +1362,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x925a4bfE64AE2bFAC8a02b35F78e60C29743755d" }, @@ -894,7 +1374,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xE4aB69C077896252FAFBD49EFD26B5D171A32410" }, @@ -902,7 +1386,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x5576815a38A3706f37bf815b261cCc7cCA77e975" }, @@ -910,7 +1398,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x231d45b53C905c3d6201318156BDC725c9c3B9B1" }, @@ -918,7 +1410,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x7ea13478Ea3961A0e8b538cb05a9DF0477c79Cd2" }, @@ -926,7 +1422,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xda40816f278Cd049c137F6612822D181065EBfB4" }, @@ -934,7 +1434,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xC82Ea35634BcE95C394B6BC00626f827bB0F4801" }, @@ -942,7 +1446,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x724593f6FCb0De4E6902d4C55D7C74DaA2AF0E55" }, @@ -950,7 +1458,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x23A1aFD896c8c8876AF46aDc38521f4432658d1e" }, @@ -958,7 +1470,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xE02E6E94d4a5E215F308bDd564a1B6f13AA56950" }, @@ -966,7 +1482,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x90a386d59b9A6a4795a011e8f032Fc21ED6FEFb6" }, @@ -974,7 +1494,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x5246409a2e09134824c4E709602205B176491e57" }, @@ -982,7 +1506,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x3423C922911956b1Ccbc2b5d4f38216a6f4299b4" }, @@ -990,15 +1518,35 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x7311DED199CC28D80E58e81e8589aa160199FCD2" }, + "jovay-testnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, + "symbol": "LINK", + "tokenAddress": "0xd3e461C55676B10634a5F81b747c324B85686Dd1" + }, "kaia-testnet-kairos": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xAF3243f975afe2269Da8Ffa835CA3A8F8B6A5A36" }, @@ -1006,7 +1554,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x4d03398C2588D92B220578dAEde29814E41c8033" }, @@ -1014,7 +1566,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" }, @@ -1022,7 +1578,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x7ECBE3416d92E8d79C8e5d8EB8Aad5DdEdAa0237" }, @@ -1030,7 +1590,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xE0352dEd874c3E72d922CE533E136385fBE4a9B4" }, @@ -1038,7 +1602,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x7ECBE3416d92E8d79C8e5d8EB8Aad5DdEdAa0237" }, @@ -1046,15 +1614,23 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", - "tokenAddress": "0x6fE981Dbd557f81ff66836af0932cba535Cbc343" + "tokenAddress": "0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" }, "neox-testnet-t4": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x7F85bAC57B5D4b81F866F495c30AB8C8c453f6FD" }, @@ -1062,7 +1638,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x2f79e049f552E600D5d8118923278Aa0fCD67179" }, @@ -1070,7 +1650,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" }, @@ -1078,7 +1662,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xB97e3665AEAF96BDD6b300B2e0C93C662104A068" }, @@ -1086,7 +1674,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xe74037112db8807B3B4B3895F5790e5bc1866a29" }, @@ -1094,7 +1686,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x0Fd9e8d3aF1aaee056EB9e802c3A762a667b1904" }, @@ -1102,7 +1698,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0x29261B6Fb93097885bEB714ee253Da63A52dFc46" }, @@ -1110,7 +1710,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x5bB50A6888ee6a67E22afFDFD9513be7740F1c15" }, @@ -1118,7 +1722,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0xA9d21ed8260DE08fF39DC5e7B65806d4e1CB817B" }, @@ -1126,7 +1734,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0x44637eEfD71A090990f89faEC7022fc74B2969aD" }, @@ -1134,23 +1746,35 @@ "allowListEnabled": false, "decimals": 9, "name": "Chainlink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "LinkhB3afbBKb2EQQu7s7umdZceV3wcvAUJhQAfQ23L" }, - "sonic-testnet-blaze": { + "sonic-testnet": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", - "tokenAddress": "0xd8C1eEE32341240A62eC8BC9988320bcC13c8580" + "tokenAddress": "0x19e696e75ccbB3155EEbB579BFa555Fab22293bA" }, "superseed-testnet": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xA3063eE34d9B4E407DF0E153c9bE679680e3A956" }, @@ -1158,23 +1782,43 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" }, - "treasure-testnet-topaz": { + "tempo-testnet": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", "poolType": "feeTokenOnly", "symbol": "LINK", + "tokenAddress": "0x384C8843411f725e800E625d5d1B659256D629dF" + }, + "treasure-testnet-topaz": { + "allowListEnabled": false, + "decimals": 18, + "name": "ChainLink Token", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, + "symbol": "LINK", "tokenAddress": "0x0FE9fAAF3e26f756443fd8f92F6711989a8e0fF5" }, "wemix-testnet": { "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "LINK", "tokenAddress": "0x3580c7A817cCD41f7e02143BFa411D4EeAE78093" }, @@ -1182,7 +1826,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xDCA67FD8324990792C0bfaE95903B8A64097754F" }, @@ -1190,7 +1838,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "LINK", "tokenAddress": "0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" }, @@ -1198,7 +1850,11 @@ "allowListEnabled": false, "decimals": 18, "name": "ChainLink Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "LINK", "tokenAddress": "0xBEDDEB2DF8904cdBCFB6Bf29b91d122D5Ae4eb7e" } @@ -1208,7 +1864,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped A0GI", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WA0GI", "tokenAddress": "0x1Cd0690fF9a693f5EF2dD976660a8dAFc81A109c" } @@ -1218,8 +1878,12 @@ "allowListEnabled": false, "decimals": 6, "name": "S-USDCircle", - "poolAddress": "0x98C80d0235Eaae38200720Ae86e2D6a62b3B19c9", - "poolType": "lockRelease", + "pool": { + "address": "0x98C80d0235Eaae38200720Ae86e2D6a62b3B19c9", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.5.0" + }, "symbol": "syrupUSDCircle", "tokenAddress": "0xb1206B74F612F478c12A647D12E7e822AF5D8244" }, @@ -1227,8 +1891,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Syrup USDC", - "poolAddress": "0xB2F73a7540A000b383e8a9ffb3BdEECc4709Dc4D", - "poolType": "burnMint", + "pool": { + "address": "0xB2F73a7540A000b383e8a9ffb3BdEECc4709Dc4D", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "syrupUSDC", "tokenAddress": "0xbc9A4b299741CBf2A8eD5D2078A426027C31B2A3" }, @@ -1236,8 +1904,12 @@ "allowListEnabled": false, "decimals": 6, "name": "Syrup USDC", - "poolAddress": "0xB6bD6e3e56a8E28CCbE44b6442cA8b586B964Af8", - "poolType": "burnMint", + "pool": { + "address": "0xB6bD6e3e56a8E28CCbE44b6442cA8b586B964Af8", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "syrupUSDC", "tokenAddress": "0x183F67cE6CCCeaBB5D79c69C2d92e78111736B62" }, @@ -1245,39 +1917,68 @@ "allowListEnabled": false, "decimals": 6, "name": "Syrup USDC", - "poolAddress": "B3rp2RHbuZeDeSSZLXww3EbaMr1TVtn9kF2a2FAobnxi", - "poolType": "burnMint", + "pool": { + "address": "B3rp2RHbuZeDeSSZLXww3EbaMr1TVtn9kF2a2FAobnxi", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, "symbol": "syrupUSDC", "tokenAddress": "95Er6pcK2agiTa2Jctp1BBnQtuDfX1d78XSTZKWZyXKk" } }, "syrupUSDT": { - "ethereum-testnet-sepolia": { + "bsc-testnet": { "allowListEnabled": false, "decimals": 6, "name": "Syrup USDT Demo", - "poolAddress": "0x83703f6601eDF05Bf9A30F03ba1F1B195BFdDEe9", - "poolType": "lockRelease", + "pool": { + "address": "0x83703f6601eDF05Bf9A30F03ba1F1B195BFdDEe9", + "rawType": "LockRelease", + "type": "lockRelease", + "version": "1.6.1" + }, "symbol": "syrupUSDT", "tokenAddress": "0x7679CBe9aE66298114AC6dAC73487B63ac023c0b" }, - "plasma-testnet": { + "ethereum-testnet-sepolia-mantle-1": { + "allowListEnabled": false, + "decimals": 6, + "name": "Syrup USDT", + "pool": { + "address": "0x4F213c8374c4F223eB85d8770Fc76eAd5163FC23", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.5.1" + }, + "symbol": "syrupUSDT", + "tokenAddress": "0x7e4Df3e1bB9b5E42dc334670F1844cD6037b8685" + }, + "ethereum-testnet-sepolia": { "allowListEnabled": false, "decimals": 6, "name": "Syrup USDT", - "poolAddress": "0x9F367a290B4Cc64d0F85B3783d332256b26143B9", - "poolType": "burnMint", + "pool": { + "address": "0x9F367a290B4Cc64d0F85B3783d332256b26143B9", + "rawType": "BurnMint", + "type": "burnMint", + "version": "1.6.1" + }, "symbol": "syrupUSDT", - "tokenAddress": "0x2282DA461850d900ba7E777b6D4161a415860931" + "tokenAddress": "0x7679CBe9aE66298114AC6dAC73487B63ac023c0b" } }, - "USDC": { - "avalanche-fuji-testnet": { + "ThetaUSD": { + "tempo-testnet": { "allowListEnabled": false, "decimals": 6, "name": "USDC", - "poolAddress": "0x2f79e049f552E600D5d8118923278Aa0fCD67179", - "poolType": "usdc", + "pool": { + "address": "0x2f79e049f552E600D5d8118923278Aa0fCD67179", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.1" + }, "symbol": "USDC", "tokenAddress": "0x5425890298aed601595a70AB815c96711a31Bc65" }, @@ -1285,8 +1986,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USDC", - "poolAddress": "0x02eef4b366225362180d704C917c50f6c46af9e0", - "poolType": "usdc", + "pool": { + "address": "0x02eef4b366225362180d704C917c50f6c46af9e0", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.0" + }, "symbol": "USDC", "tokenAddress": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" }, @@ -1294,8 +1999,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "0xeA2912f446Ff28663D2E5A971da751A84E409292", - "poolType": "usdc", + "pool": { + "address": "0xeA2912f446Ff28663D2E5A971da751A84E409292", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.0" + }, "symbol": "USDC", "tokenAddress": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" }, @@ -1303,8 +2012,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USDC", - "poolAddress": "0x63d023db6e9b2a838Cf4cc54903d2C2D825A2967", - "poolType": "usdc", + "pool": { + "address": "0x63d023db6e9b2a838Cf4cc54903d2C2D825A2967", + "rawType": "Usdc", + "type": "usdc", + "version": "1.6.1" + }, "symbol": "USDC", "tokenAddress": "0x036CbD53842c5426634e7929541eC2318f3dCF7e" }, @@ -1312,8 +2025,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USDC", - "poolAddress": "0x8E9066E66bF1B8A4eAF2344589De9ff82CE47C2d", - "poolType": "usdc", + "pool": { + "address": "0x8E9066E66bF1B8A4eAF2344589De9ff82CE47C2d", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.0" + }, "symbol": "USDC", "tokenAddress": "0x5fd84259d66Cd46123540766Be93DFE6D43130D7" }, @@ -1321,8 +2038,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USDC", - "poolAddress": "0xB45B9eb94F25683B47e5AFb0f74A05a58be86311", - "poolType": "usdc", + "pool": { + "address": "0xB45B9eb94F25683B47e5AFb0f74A05a58be86311", + "rawType": "Usdc", + "type": "usdc", + "version": "1.6.1" + }, "symbol": "USDC", "tokenAddress": "0x31d0220469e10c4E71834a79b1f276d740d3768F" }, @@ -1330,8 +2051,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USDC", - "poolAddress": "0x4F213c8374c4F223eB85d8770Fc76eAd5163FC23", - "poolType": "usdc", + "pool": { + "address": "0x4F213c8374c4F223eB85d8770Fc76eAd5163FC23", + "rawType": "Usdc", + "type": "usdc", + "version": "1.6.1" + }, "symbol": "USDC", "tokenAddress": "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582" }, @@ -1339,8 +2064,12 @@ "allowListEnabled": false, "decimals": 6, "name": "USD Coin", - "poolAddress": "7hCNZAWQNSq49CCA1KtjLuZbK5cWguRSVVsJcMa3C5zL", - "poolType": "usdc", + "pool": { + "address": "7hCNZAWQNSq49CCA1KtjLuZbK5cWguRSVVsJcMa3C5zL", + "rawType": "Usdc", + "type": "usdc", + "version": "1.5.1" + }, "symbol": "USDC", "tokenAddress": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" } @@ -1350,7 +2079,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped ApeCoin", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WAPE", "tokenAddress": "0x1762A2B15f63ca4E1165A9385cB40412CF545aC3" } @@ -1360,7 +2093,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped AVAX", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WAVAX", "tokenAddress": "0xd00ae08403B9bbb9124bB305C09058E32C39A48c" } @@ -1370,7 +2107,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Bera", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WBERA", "tokenAddress": "0x7507c1dc16935B82698e4C63f2746A2fCf994dF8" } @@ -1380,7 +2121,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BNB", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WBNB", "tokenAddress": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd" } @@ -1390,7 +2135,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Shibarium Wrapped BONE", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WBONE", "tokenAddress": "0x41c3F37587EBcD46C0F85eF43E38BcfE1E70Ab56" } @@ -1400,7 +2149,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BTC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WBTC", "tokenAddress": "0x3e57d6946f893314324C975AA9CEBBdF3232967E" }, @@ -1408,7 +2161,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BTC TOKEN", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WBTC", "tokenAddress": "0x233631132FD56c8f86D1FC97F0b82420a8d20af3" }, @@ -1416,7 +2173,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1424,7 +2185,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Bitcoin", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WBTC", "tokenAddress": "0x1A6357313BA1B6bc92e7325A9BAf241Ca3e493dD" } @@ -1434,7 +2199,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Bitcorn", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WBTCN", "tokenAddress": "0xda5dDd7270381A7C2717aD10D1c0ecB19e3CDFb2" } @@ -1444,7 +2213,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Celo", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WCELO", "tokenAddress": "0x99604d0e2EfE7ABFb58BdE565b5330Bb46Ab3Dca" } @@ -1454,7 +2227,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped CORE", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WCORE", "tokenAddress": "0x7Ce5fCfFd1296d870b3578809B31D8CA8bF5aC3d" } @@ -1464,17 +2241,35 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped CRO", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WCRO", "tokenAddress": "0x5C50653Ada833D649a718ba4D1Fb9e2EE49c202d" } }, + "WDOGE": { + "dogeos-testnet-chikyu": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped Doge", + "poolType": "feeTokenOnly", + "symbol": "WDOGE", + "tokenAddress": "0xF6BDB158A5ddF77F1B83bC9074F6a472c58D78aE" + } + }, "WETH": { "abstract-testnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x9EDCde0257F2386Ce177C3a7FCdd97787F0D841d" }, @@ -1482,7 +2277,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1490,7 +2289,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1498,7 +2301,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x94373a4919B3240D86eA41593D5eBa789FEF3848" }, @@ -1506,15 +2313,43 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0xae2C46ddb314B9Ba743C6dEE4878F151881333D9" }, + "ethereum-testnet-hoodi": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped ETH", + "poolType": "feeTokenOnly", + "symbol": "WETH", + "tokenAddress": "0xF0b60c40554fE9d385EB5F1Ec03471f0d66EC589" + }, + "ethereum-testnet-hoodi-morph": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped Ether", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, + "symbol": "WETH", + "tokenAddress": "0x5300000000000000000000000000000000000011" + }, "ethereum-testnet-sepolia": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x097D90c9d3E0B50Ca60e1ae45F6A81010f9FB534" }, @@ -1522,7 +2357,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0xE591bf0A0CF924A0674d7792db046B23CEbF5f34" }, @@ -1530,7 +2369,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1538,7 +2381,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000023" }, @@ -1546,7 +2393,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000001" }, @@ -1554,7 +2405,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x06565ed324Ee9fb4DB0FF80B7eDbE4Cb007555a3" }, @@ -1562,7 +2417,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1570,7 +2429,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1578,7 +2441,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1586,7 +2453,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x1CE28d5C81B229c77C5651feB49c4C489f8c52C4" }, @@ -1594,7 +2465,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x5300000000000000000000000000000000000004" }, @@ -1602,7 +2477,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1610,7 +2489,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1618,7 +2501,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1626,7 +2513,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4317b2eCD41851173175005783322D29E9bAee9E" }, @@ -1634,7 +2525,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x0C8aFD1b58aa2A5bAd2414B861D8A7fF898eDC3A" }, @@ -1642,7 +2537,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1650,15 +2549,35 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, + "jovay-testnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped Ether", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, + "symbol": "WETH", + "tokenAddress": "0xFe06d41BA962A74209845f938c387b363a931505" + }, "megaeth-testnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0xa787B3E0471b718bBfEaA59B502fd0C4EBd7b74E" }, @@ -1666,7 +2585,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x85Be6b6ff4e61C3bEB0Fb73a2A9dC3A80e279c86" }, @@ -1674,7 +2597,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1682,7 +2609,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x12e3b49DF7dD40792EFbB1B3eAB1295951Bad5EE" }, @@ -1690,23 +2621,43 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, - "plasma-testnet": { + "monad-testnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", "poolType": "feeTokenOnly", "symbol": "WETH", + "tokenAddress": "0xdE4E7FED43FAC37EB21aA0643d9852f75332eab8" + }, + "plasma-testnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped Ether", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, + "symbol": "WETH", "tokenAddress": "0xc2e1B8e9a765A19315cD9BbbD84a1BB6DC3FC335" }, "polygon-testnet-tatara": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1714,7 +2665,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" }, @@ -1722,7 +2677,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WETH", "tokenAddress": "0x4200000000000000000000000000000000000006" } @@ -1732,7 +2691,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Frax Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "wfrxETH", "tokenAddress": "0xFC00000000000000000000000000000000000006" } @@ -1742,7 +2705,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped GAS v10", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WGAS10", "tokenAddress": "0x1CE16390FD09040486221e912B87551E4e44Ab17" } @@ -1752,7 +2719,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Grass", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WGRASS", "tokenAddress": "0xeee5a340Cdc9c179Db25dea45AcfD5FE8d4d3eB8" } @@ -1762,7 +2733,11 @@ "allowListEnabled": false, "decimals": 8, "name": "Wrapped HBAR", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WHBAR", "tokenAddress": "0xb1F616b8134F602c3Bb465fB5b5e6565cCAd37Ed" } @@ -1772,7 +2747,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Hashkey", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WHSK", "tokenAddress": "0x2896e619Fa7c831A7E52b87EffF4d671bEc6B262" } @@ -1782,7 +2761,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ether", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WETH", "tokenAddress": "0xF04fcEC93DEB6191B704a0ec5d0FFF2A8B2c39be" } @@ -1792,7 +2775,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped MAGIC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WMAGIC", "tokenAddress": "0x095ded714d42cBD5fb2E84A0FfbFb140E38dC9E1" } @@ -1802,7 +2789,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Metis", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WMETIS", "tokenAddress": "0x5c48e07062aC4E2Cf4b9A768a711Aef18e8fbdA0" } @@ -1812,7 +2803,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Mantle", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WMNT", "tokenAddress": "0x19f5557E23e9914A18239990f6C70D68FDF0deD5" } @@ -1822,9 +2817,13 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Monad", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WMON", - "tokenAddress": "0x760AfE86e5de5fa0Ee542fc7B7B713e1c5425701" + "tokenAddress": "0xFb8bf4c1CC7a94c73D209a149eA2AbEa852BC541" } }, "WOKB": { @@ -1832,7 +2831,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped OKB", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WOKB", "tokenAddress": "0xa7b9C3a116b20bEDDdBE4d90ff97157f67F0bD97" } @@ -1842,7 +2845,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Pharos", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WPHRS", "tokenAddress": "0x838800b758277CC111B2d48Ab01e5E164f8E9471" } @@ -1852,7 +2859,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Plume", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WPLUME", "tokenAddress": "0xC1FD14775c8665B31c7154074f537338774351EB" } @@ -1862,7 +2873,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Polygon Ecosystem Token", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WPOL", "tokenAddress": "0x360ad4f9a9A8EFe9A8DCB5f461c4Cc1047E1Dcf9" } @@ -1872,7 +2887,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped RBTC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WRBTC", "tokenAddress": "0x09B6Ca5E4496238a1F176aEA6bB607db96C2286E" } @@ -1882,19 +2901,27 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Ron", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WRON", "tokenAddress": "0xA959726154953bAe111746E265E6d754F48570E6" } }, "WS": { - "sonic-testnet-blaze": { + "sonic-testnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped S", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WS", - "tokenAddress": "0x917FE4b784d1895187Df169aeCc687C03ba12662" + "tokenAddress": "0x4C344A0E257bF949D67A89be8B4516306D90E23E" } }, "WSBY": { @@ -1902,7 +2929,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped Shibuya", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.1" + }, "symbol": "WSBY", "tokenAddress": "0xbd5F3751856E11f3e80dBdA567Ef91Eb7e874791" } @@ -1912,7 +2943,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped SEI", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WSEI", "tokenAddress": "0x3921eA6Cf927BE80211Bb57f19830700285b0AdA" } @@ -1922,7 +2957,11 @@ "allowListEnabled": false, "decimals": 9, "name": "Wrapped Solana", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WSOL", "tokenAddress": "So11111111111111111111111111111111111111112" } @@ -1932,7 +2971,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped TAC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WTAC", "tokenAddress": "0xCf61405b7525F09f4E7501fc831fE7cbCc823d4c" } @@ -1942,17 +2985,45 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped BNB", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WBNB", "tokenAddress": "0x4200000000000000000000000000000000000006" } }, + "WTEMP": { + "tempo-testnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "WTEMP", + "poolType": "feeTokenOnly", + "symbol": "WTEMP", + "tokenAddress": "0xe875EB5437E55B74D18f6C090a5A14e4804dB2d9" + } + }, + "WUSDC": { + "arc-testnet": { + "allowListEnabled": false, + "decimals": 18, + "name": "Wrapped USDC", + "poolType": "feeTokenOnly", + "symbol": "WUSDC", + "tokenAddress": "0xbf4B839A7939a52acbF8fC52D5Bd5BFE69a064EA" + } + }, "WWEMIX": { "wemix-testnet": { "allowListEnabled": false, "decimals": 18, "name": "Wrapped Wemix", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WWEMIX", "tokenAddress": "0xbE3686643c05f00eC46e73da594c78098F7a9Ae7" } @@ -1962,7 +3033,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped XDAI", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WXDAI", "tokenAddress": "0x18c8a7ec7897177E4529065a7E7B0878358B3BfF" } @@ -1972,7 +3047,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped XDC", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "WXDC", "tokenAddress": "0x56408DC41E35d3E8E92A16bc94787438df9387a1" } @@ -1982,7 +3061,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped XPL", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WXPL", "tokenAddress": "0x6100E367285b01F48D07953803A2d8dCA5D19873" } @@ -1992,7 +3075,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped XTZ", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.5.0" + }, "symbol": "WXTZ", "tokenAddress": "0xB1Ea698633d57705e93b0E40c1077d46CD6A51d8" } @@ -2002,7 +3089,11 @@ "allowListEnabled": false, "decimals": 18, "name": "Wrapped zkCRO", - "poolType": "feeTokenOnly", + "pool": { + "rawType": "FeeTokenOnly", + "type": "feeTokenOnly", + "version": "1.6.1" + }, "symbol": "wzkCRO", "tokenAddress": "0xeD73b53197189BE3Ff978069cf30eBc28a8B5837" } diff --git a/src/config/data/ccip/v1_2_0/testnet/verifiers.json b/src/config/data/ccip/v1_2_0/testnet/verifiers.json new file mode 100644 index 00000000000..2614058b4bd --- /dev/null +++ b/src/config/data/ccip/v1_2_0/testnet/verifiers.json @@ -0,0 +1,55 @@ +{ + "ethereum-testnet-sepolia": { + "0x91339eb99C4c2Be9A071203DD99E014A3189FD29": { + "id": "chainlink", + "name": "Chainlink", + "type": "committee" + }, + "0x56c4b06A0F59AcFAAb58FEA0d7Ca4090695F683f": { + "id": "lombard", + "name": "Lombard", + "type": "api" + }, + "0x051665f2455116e929b9972c36d23070F5054Ce0": { + "id": "cctp", + "name": "CCTP", + "type": "api" + } + }, + "ethereum-testnet-sepolia-base-1": { + "0x7EEdf2DBC74924Cb1f23fC8845CD35bF18b697de": { + "id": "chainlink-labs", + "name": "Chainlink Labs", + "type": "committee" + }, + "0xD3ED6fC9fd22412764ac2Ef64fB664b9393dF9F2": { + "id": "cctp", + "name": "CCTP", + "type": "api" + } + }, + "ethereum-testnet-sepolia-arbitrum-1": { + "0xa132F089492CcE5f1D79483a9e4552f37266ed01": { + "id": "chainlink-labs", + "name": "Chainlink Labs", + "type": "committee" + }, + "0xb0B4b5847E35033766d5B49CD9C0fC40F459321F": { + "id": "lombard", + "name": "Lombard", + "type": "api" + } + }, + "ethereum-testnet-sepolia-optimism-1": { + "0x0B8B717f8D65DeC5c9e440A9eD51f48887E83c1b": { + "id": "cctp", + "name": "CCTP", + "type": "api" + }, + "0x34E63B2B9491570FCc01CC0b288569851EF47B27": { + "id": "symbiotic", + "name": "Symbiotic", + "type": "api" + } + } +} diff --git a/src/config/data/chain-to-technology.json b/src/config/data/chain-to-technology.json index 9ca8dd73405..a36e3254605 100644 --- a/src/config/data/chain-to-technology.json +++ b/src/config/data/chain-to-technology.json @@ -54,6 +54,7 @@ "CORN_MAINNET": "CORN", "CORN_TESTNET": "CORN", "ETHEREUM_HOLESKY": "ETHEREUM", + "ETHEREUM_HOODI": "ETHEREUM", "ASTAR_MAINNET": "ASTAR", "ASTAR_SHIBUYA": "ASTAR", "ZIRCUIT_MAINNET": "ZIRCUIT", @@ -67,7 +68,8 @@ "SHIBARIUM_MAINNET": "SHIBARIUM", "SHIBARIUM_PUPPYNET": "SHIBARIUM", "SONIC_MAINNET": "SONIC", - "SONIC_BLAZE": "SONIC", + "SONIC_TESTNET": "SONIC", + "SONIC_TESTNET_BLAZE": "SONIC", "BOB_MAINNET": "BOB", "BOB_SEPOLIA": "BOB", "BOTANIX_TESTNET": "BOTANIX", @@ -104,6 +106,7 @@ "MIND_NETWORK_TESTNET": "MIND_NETWORK", "MIND_NETWORK_MAINNET": "MIND_NETWORK", "MEGAETH_TESTNET": "MEGAETH", + "MEGAETH_MAINNET": "MEGAETH", "0G_GALILEO_TESTNET": "0G", "0G_MAINNET": "0G", "TAIKO_MAINNET": "TAIKO", @@ -157,5 +160,13 @@ "AB_CHAIN_MAINNET": "AB_CHAIN", "MONAD_MAINNET": "MONAD", "NEXON_HENESYS_MAINNET": "HENESYS", - "PHAROS_ATLANTIC_TESTNET": "PHAROS" + "PHAROS_ATLANTIC_TESTNET": "PHAROS", + "MORPH_MAINNET": "MORPH", + "MORPH_HOODI_TESTNET": "MORPH", + "JOVAY_MAINNET": "JOVAY", + "JOVAY_TESTNET": "JOVAY", + "STABLE_MAINNET": "STABLE", + "TEMPO_TESTNET": "TEMPO", + "ARC_NETWORK_TESTNET": "ARC_NETWORK", + "DOGE_OS_CHIKYU_TESTNET": "DOGE_OS" } diff --git a/src/config/data/chains.json b/src/config/data/chains.json index 20b7de2156b..81650749b87 100644 --- a/src/config/data/chains.json +++ b/src/config/data/chains.json @@ -39,6 +39,18 @@ "symbol": "ETH", "decimals": 18 } + }, + "ETHEREUM_HOODI": { + "chainId": 560048, + "title": "Ethereum Hoodi", + "explorer": { + "baseUrl": "https://hoodi.etherscan.io/" + }, + "nativeCurrency": { + "name": "Hoodi Ether", + "symbol": "ETH", + "decimals": 18 + } } } }, @@ -730,10 +742,10 @@ } }, "XLAYER_TESTNET": { - "chainId": 195, + "chainId": 1952, "title": "X Layer Testnet", "explorer": { - "baseUrl": "https://www.oklink.com/xlayer-test" + "baseUrl": "https://web3.okx.com/explorer/x-layer-testnet" }, "nativeCurrency": { "name": "X Layer Global Utility Token in testnet", @@ -1070,9 +1082,21 @@ "decimals": 18 } }, - "SONIC_BLAZE": { + "SONIC_TESTNET": { + "chainId": 14601, + "title": "Sonic Testnet", + "explorer": { + "baseUrl": "https://explorer.testnet.soniclabs.com" + }, + "nativeCurrency": { + "name": "Sonic", + "symbol": "S", + "decimals": 18 + } + }, + "SONIC_TESTNET_BLAZE": { "chainId": 57054, - "title": "Sonic Blaze", + "title": "Sonic Blaze Testnet", "explorer": { "baseUrl": "https://testnet.sonicscan.org" }, @@ -1653,6 +1677,18 @@ "icon": "/assets/chains/megaeth.svg", "chainType": "evm", "chains": { + "MEGAETH_MAINNET": { + "chainId": 4326, + "title": "MegaETH Mainnet", + "explorer": { + "baseUrl": "https://megaeth.blockscout.com/" + }, + "nativeCurrency": { + "name": "MegaETH Ether", + "symbol": "ETH", + "decimals": 18 + } + }, "MEGAETH_TESTNET": { "chainId": 6342, "title": "MegaETH Testnet", @@ -2429,7 +2465,7 @@ "chainId": 964, "title": "Bittensor EVM", "explorer": { - "baseUrl": "https://taostats.io/" + "baseUrl": "https://evm.taostats.io/" }, "nativeCurrency": { "name": "TAO", @@ -2514,5 +2550,143 @@ } } } + }, + "MORPH": { + "title": "Morph", + "icon": "/assets/chains/morph.svg", + "chainType": "evm", + "chains": { + "MORPH_MAINNET": { + "chainId": 2818, + "title": "Morph", + "explorer": { + "baseUrl": "https://explorer.morphl2.io" + }, + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + } + }, + "MORPH_HOODI_TESTNET": { + "chainId": 2910, + "title": "Morph Hoodi", + "explorer": { + "baseUrl": "https://explorer-hoodi.morphl2.io" + }, + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + } + } + } + }, + "JOVAY": { + "title": "Jovay", + "icon": "/assets/chains/jovay.svg", + "chainType": "evm", + "chains": { + "JOVAY_MAINNET": { + "chainId": 5734951, + "title": "Jovay", + "explorer": { + "baseUrl": "https://explorer.jovay.io/l2" + }, + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + } + }, + "JOVAY_TESTNET": { + "chainId": 2019775, + "title": "Jovay Sepolia Testnet", + "explorer": { + "baseUrl": "https://sepolia-explorer.jovay.io/l2" + }, + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + } + } + } + }, + "STABLE": { + "title": "Stable", + "icon": "/assets/chains/stable.svg", + "chainType": "evm", + "chains": { + "STABLE_MAINNET": { + "chainId": 988, + "title": "Stable", + "explorer": { + "baseUrl": "https://stablescan.xyz/" + }, + "nativeCurrency": { + "name": "gasUSDT", + "symbol": "gUSDT", + "decimals": 18 + } + } + } + }, + "TEMPO": { + "title": "Tempo", + "icon": "/assets/chains/tempo.svg", + "chainType": "evm", + "chains": { + "TEMPO_TESTNET": { + "chainId": 42429, + "title": "Tempo", + "explorer": { + "baseUrl": "https://explore.tempo.xyz" + }, + "nativeCurrency": { + "name": "USD", + "symbol": "USD", + "decimals": 18 + } + } + } + }, + "ARC_NETWORK": { + "title": "Arc Network", + "icon": "/assets/chains/arc.svg", + "chainType": "evm", + "chains": { + "ARC_NETWORK_TESTNET": { + "chainId": 5042002, + "title": "Arc Network Testnet", + "explorer": { + "baseUrl": "https://testnet.arcscan.app" + }, + "nativeCurrency": { + "name": "USDC", + "symbol": "USDC", + "decimals": 18 + } + } + } + }, + "DOGE_OS": { + "title": "DogeOS", + "icon": "/assets/chains/dogeos.svg", + "chainType": "evm", + "chains": { + "DOGE_OS_CHIKYU_TESTNET": { + "chainId": 6281971, + "title": "DogeOS Chikyu Testnet", + "explorer": { + "baseUrl": "https://blockscout.testnet.dogeos.com" + }, + "nativeCurrency": { + "name": "DogeOS", + "symbol": "DOGE", + "decimals": 18 + } + } + } } } diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts index 3d537eb6c0c..2465c32bc77 100644 --- a/src/config/sidebar.ts +++ b/src/config/sidebar.ts @@ -81,6 +81,11 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { title: "Service Quotas", url: "cre/service-quotas", }, + { + title: "Supported Networks", + url: "cre/supported-networks", + highlightAsCurrent: ["cre/supported-networks-ts", "cre/supported-networks-go"], + }, { title: "Support & Feedback", url: "cre/support-feedback", @@ -135,7 +140,11 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { "cre/getting-started/part-4-writing-onchain-go", ], }, - { title: "Conclusion & Next Steps", url: "cre/getting-started/conclusion" }, + { + title: "Before You Build", + url: "cre/getting-started/before-you-build", + highlightAsCurrent: ["cre/getting-started/before-you-build-ts", "cre/getting-started/before-you-build-go"], + }, ], }, { @@ -248,11 +257,11 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { ], }, { - title: "Supported Networks", - url: "cre/guides/workflow/using-evm-client/supported-networks", + title: "Forwarder Directory", + url: "cre/guides/workflow/using-evm-client/forwarder-directory", highlightAsCurrent: [ - "cre/guides/workflow/using-evm-client/supported-networks-ts", - "cre/guides/workflow/using-evm-client/supported-networks-go", + "cre/guides/workflow/using-evm-client/forwarder-directory-ts", + "cre/guides/workflow/using-evm-client/forwarder-directory-go", ], }, ], @@ -287,6 +296,20 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { }, ], }, + { + title: "Confidential API Interactions (Experimental)", + url: "cre/guides/workflow/using-confidential-http-client", + children: [ + { + title: "Making Confidential Requests", + url: "cre/guides/workflow/using-confidential-http-client/making-requests", + highlightAsCurrent: [ + "cre/guides/workflow/using-confidential-http-client/making-requests-ts", + "cre/guides/workflow/using-confidential-http-client/making-requests-go", + ], + }, + ], + }, { title: "Secrets", url: "cre/guides/workflow/secrets", @@ -309,6 +332,15 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { }, ], }, + { + title: "Using Time in Workflows", + url: "cre/guides/workflow/time-in-workflows", + highlightAsCurrent: ["cre/guides/workflow/time-in-workflows-ts", "cre/guides/workflow/time-in-workflows-go"], + }, + { + title: "Using Randomness in Workflows", + url: "cre/guides/workflow/using-randomness", + }, ], }, { @@ -391,6 +423,11 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { { title: "Overview", url: "cre/capabilities" }, { title: "Triggers", url: "cre/capabilities/triggers" }, { title: "HTTP", url: "cre/capabilities/http" }, + { + title: "Confidential HTTP (Experimental)", + url: "cre/capabilities/confidential-http", + highlightAsCurrent: ["cre/capabilities/confidential-http-ts", "cre/capabilities/confidential-http-go"], + }, { title: "EVM Read & Write", url: "cre/capabilities/evm-read-write" }, ], }, @@ -406,18 +443,15 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { url: "cre/concepts/non-determinism", highlightAsCurrent: ["cre/concepts/non-determinism-go", "cre/concepts/non-determinism-ts"], }, - { - title: "Time in CRE", - url: "cre/concepts/time-in-cre", - }, - { - title: "Random in CRE", - url: "cre/concepts/random-in-cre", - }, { title: "TypeScript Runtime Environment", url: "cre/concepts/typescript-wasm-runtime", }, + { + title: "Finality & Confidence Levels", + url: "cre/concepts/finality", + highlightAsCurrent: ["cre/concepts/finality-go", "cre/concepts/finality-ts"], + }, ], }, { @@ -518,6 +552,14 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { url: "cre/reference/sdk/http-client", highlightAsCurrent: ["cre/reference/sdk/http-client-ts", "cre/reference/sdk/http-client-go"], }, + { + title: "Confidential HTTP Client (Experimental)", + url: "cre/reference/sdk/confidential-http-client", + highlightAsCurrent: [ + "cre/reference/sdk/confidential-http-client-ts", + "cre/reference/sdk/confidential-http-client-go", + ], + }, { title: "Consensus & Aggregation", url: "cre/reference/sdk/consensus", @@ -548,7 +590,21 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { title: "Feed Types", url: "data-feeds/feed-types", children: [ - { title: "Price Feeds", url: "data-feeds/price-feeds" }, + { + title: "Price Feeds", + url: "data-feeds/price-feeds", + }, + { + title: "Tokenized Equity Feeds", + url: "data-feeds/tokenized-equity-feeds", + children: [ + { + title: "Provider Catalog", + url: "data-feeds/tokenized-equity-feeds/providers", + children: [{ title: "Ondo Finance", url: "data-feeds/tokenized-equity-feeds/ondo" }], + }, + ], + }, { title: "SmartData", url: "data-feeds/smartdata", @@ -596,6 +652,10 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { title: "Selecting Quality Data Feeds", url: "data-feeds/selecting-data-feeds", }, + { + title: "Deprecating Feeds", + url: "data-feeds/deprecating-feeds", + }, ], }, { @@ -869,32 +929,49 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { title: "Report Schema v11 (RWA Advanced)", url: "data-streams/reference/report-schema-v11", }, + { + title: "Handling Market Events", + url: "data-streams/rwa-streams/handling-market-events", + highlightAsCurrent: ["data-streams/rwa-streams/handling-market-events-v11"], + }, + { + title: "24/5 US Equities User Guide", + url: "data-streams/rwa-streams/24-5-us-equities-user-guide", + }, ], }, { - title: "Net Asset Value (NAV)", - url: "data-streams/nav-streams", + title: "SmartData", + url: "data-streams/smartdata-streams", children: [ { - title: "Report Schema v9 (NAV)", + title: "Report Schema v9 (SmartData)", url: "data-streams/reference/report-schema-v9", }, ], }, { title: "Tokenized Asset", - url: "data-streams/backed-streams", + url: "data-streams/tokenized-asset-streams", children: [ { title: "Report Schema v10 (Tokenized Asset)", url: "data-streams/reference/report-schema-v10", }, + { + title: "Handling Stock Splits", + url: "data-streams/tokenized-asset-streams/handling-stock-splits", + }, ], }, { title: "Market Hours", url: "data-streams/market-hours", }, + { + title: "Deprecating Streams", + url: "data-streams/deprecating-streams", + }, ], }, { @@ -936,6 +1013,10 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { title: "Best Practices", url: "data-streams/concepts/best-practices", }, + { + title: "Calculated Streams", + url: "data-streams/concepts/calculated-streams", + }, { title: "Liquidity-Weighted Bid and Ask prices", url: "data-streams/concepts/liquidity-weighted-prices", @@ -1723,6 +1804,7 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = { }, ], [SIDEBAR_SECTIONS.CCIP]: CCIP_SIDEBAR_CONTENT, + [SIDEBAR_SECTIONS.CHAINLINK_LOCAL]: [ { section: "Chainlink Local", diff --git a/src/config/sidebar/__tests__/__snapshots__/ccip-dynamic.test.ts.snap b/src/config/sidebar/__tests__/__snapshots__/ccip-dynamic.test.ts.snap index 029002b33c8..38c6b3a814d 100644 --- a/src/config/sidebar/__tests__/__snapshots__/ccip-dynamic.test.ts.snap +++ b/src/config/sidebar/__tests__/__snapshots__/ccip-dynamic.test.ts.snap @@ -278,6 +278,47 @@ exports[`CCIP Sidebar Configuration Snapshot should match the expected sidebar s "title": "Manual execution", "url": "ccip/concepts/manual-execution", }, + { + "children": [ + { + "title": "Overview", + "url": "ccip/concepts/rate-limit-management/overview", + }, + { + "title": "How Rate Limits Work", + "url": "ccip/concepts/rate-limit-management/how-rate-limits-work", + }, + { + "title": "Prerequisites and Permissions", + "url": "ccip/concepts/rate-limit-management/prerequisites-and-permissions", + }, + { + "title": "Inspect Current Rate Limits", + "url": "ccip/concepts/rate-limit-management/inspect-current-rate-limits", + }, + { + "title": "Token Units and Decimals", + "url": "ccip/concepts/rate-limit-management/token-units-and-decimals", + }, + { + "title": "Update Rate Limits", + "url": "ccip/concepts/rate-limit-management/update-rate-limits", + }, + { + "title": "Emergency Actions", + "url": "ccip/concepts/rate-limit-management/emergency-actions", + }, + { + "title": "Common Scenarios", + "url": "ccip/concepts/rate-limit-management/common-scenarios", + }, + { + "title": "Executing with a Multisig", + "url": "ccip/concepts/rate-limit-management/executing-with-a-multisig", + }, + ], + "title": "Rate Limit Management", + }, { "chainTypes": [ "evm", @@ -381,13 +422,6 @@ exports[`CCIP Sidebar Configuration Snapshot should match the expected sidebar s "title": "Checking CCIP Message Status", "url": "ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain", }, - { - "chainTypes": [ - "evm", - ], - "title": "Get Supported Tokens", - "url": "ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens", - }, ], "title": "Using CCIP CLI", "url": "ccip/tutorials/evm/offchain/ccip-tools", diff --git a/src/config/sidebar/ccip-dynamic.ts b/src/config/sidebar/ccip-dynamic.ts index 77a458a94fd..e015b1e1521 100644 --- a/src/config/sidebar/ccip-dynamic.ts +++ b/src/config/sidebar/ccip-dynamic.ts @@ -253,6 +253,57 @@ export const CCIP_SIDEBAR_CONTENT: SectionEntry[] = [ url: "ccip/concepts/manual-execution", // Universal }, + // NEW: Rate Limit Management folder + children (Universal) + { + title: "Rate Limit Management", + children: [ + { + title: "Overview", + url: "ccip/concepts/rate-limit-management/overview", + // Universal + }, + { + title: "How Rate Limits Work", + url: "ccip/concepts/rate-limit-management/how-rate-limits-work", + // Universal + }, + { + title: "Prerequisites and Permissions", + url: "ccip/concepts/rate-limit-management/prerequisites-and-permissions", + // Universal + }, + { + title: "Inspect Current Rate Limits", + url: "ccip/concepts/rate-limit-management/inspect-current-rate-limits", + // Universal + }, + { + title: "Token Units and Decimals", + url: "ccip/concepts/rate-limit-management/token-units-and-decimals", + // Universal + }, + { + title: "Update Rate Limits", + url: "ccip/concepts/rate-limit-management/update-rate-limits", + // Universal + }, + { + title: "Emergency Actions", + url: "ccip/concepts/rate-limit-management/emergency-actions", + // Universal + }, + { + title: "Common Scenarios", + url: "ccip/concepts/rate-limit-management/common-scenarios", + // Universal + }, + { + title: "Executing with a Multisig", + url: "ccip/concepts/rate-limit-management/executing-with-a-multisig", + // Universal + }, + ], + }, { title: "Best Practices", url: "ccip/concepts/best-practices/evm", @@ -333,11 +384,11 @@ export const CCIP_SIDEBAR_CONTENT: SectionEntry[] = [ url: "ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain", chainTypes: ["evm"], }, - { - title: "Get Supported Tokens", - url: "ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens", - chainTypes: ["evm"], - }, + // { + // title: "Get Supported Tokens", + // url: "ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens", + // chainTypes: ["evm"], + // }, ], }, ], diff --git a/src/config/types.ts b/src/config/types.ts index 006611c42bb..9196be69c2b 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -45,7 +45,6 @@ export type SupportedTechnology = | "MERLIN" | "FRAXTAL" | "HEDERA" - | "UNICHAIN" | "HEMI" | "APECHAIN" | "CRONOS" @@ -77,6 +76,12 @@ export type SupportedTechnology = | "AB_CHAIN" | "PHAROS" | "HENESYS" + | "MORPH" + | "JOVAY" + | "STABLE" + | "TEMPO" + | "ARC_NETWORK" + | "DOGE_OS" export type ChainType = "evm" | "solana" | "aptos" @@ -86,6 +91,7 @@ export type SupportedChain = | "ETHEREUM_MAINNET" | "ETHEREUM_SEPOLIA" | "ETHEREUM_HOLESKY" + | "ETHEREUM_HOODI" | "BNB_MAINNET" | "BNB_TESTNET" | "POLYGON_MAINNET" @@ -139,7 +145,8 @@ export type SupportedChain = | "SHIBARIUM_MAINNET" | "SHIBARIUM_PUPPYNET" | "SONIC_MAINNET" - | "SONIC_BLAZE" + | "SONIC_TESTNET" + | "SONIC_TESTNET_BLAZE" | "BOB_MAINNET" | "BOB_SEPOLIA" | "WORLD_MAINNET" @@ -189,6 +196,7 @@ export type SupportedChain = | "MIND_NETWORK_TESTNET" | "MIND_NETWORK_MAINNET" | "MEGAETH_TESTNET" + | "MEGAETH_MAINNET" | "TAIKO_MAINNET" | "TAIKO_HEKLA" | "PLUME_MAINNET" @@ -242,6 +250,14 @@ export type SupportedChain = | "MONAD_MAINNET" | "NEXON_HENESYS_MAINNET" | "PHAROS_ATLANTIC_TESTNET" + | "MORPH_MAINNET" + | "MORPH_HOODI_TESTNET" + | "JOVAY_MAINNET" + | "JOVAY_TESTNET" + | "STABLE_MAINNET" + | "TEMPO_TESTNET" + | "ARC_NETWORK_TESTNET" + | "DOGE_OS_CHIKYU_TESTNET" export type ExplorerInfo = { baseUrl: string diff --git a/src/config/web3Providers.ts b/src/config/web3Providers.ts index 4e4aacb95ef..d674e5ad47d 100644 --- a/src/config/web3Providers.ts +++ b/src/config/web3Providers.ts @@ -48,6 +48,7 @@ export const chainToProvider: Record<SupportedChain, () => Provider> = { SONEIUM_MAINNET: () => new JsonRpcProvider("https://rpc.soneium.org"), SONEIUM_MINATO: () => new JsonRpcProvider("https://rpc.minato.soneium.org"), ETHEREUM_HOLESKY: () => new JsonRpcProvider("https://ethereum-holesky-rpc.publicnode.com"), + ETHEREUM_HOODI: () => new JsonRpcProvider("https://rpc.hoodi.ethpandaops.io"), ASTAR_MAINNET: () => new JsonRpcProvider("https://rpc.astar.network"), ASTAR_SHIBUYA: () => new JsonRpcProvider("https://evm.shibuya.astar.network/"), ZIRCUIT_MAINNET: () => new JsonRpcProvider("https://zircuit1-mainnet.liquify.com"), @@ -61,13 +62,14 @@ export const chainToProvider: Record<SupportedChain, () => Provider> = { SHIBARIUM_MAINNET: () => new JsonRpcProvider("https://www.shibrpc.com"), SHIBARIUM_PUPPYNET: () => new JsonRpcProvider("https://puppynet.shibrpc.com"), SONIC_MAINNET: () => new JsonRpcProvider("https://rpc.ankr.com/sonic_mainnet"), - SONIC_BLAZE: () => new JsonRpcProvider("https://rpc.ankr.com/sonic_blaze_testnet"), + SONIC_TESTNET: () => new JsonRpcProvider("https://rpc.testnet.soniclabs.com"), + SONIC_TESTNET_BLAZE: () => new JsonRpcProvider("https://rpc.blaze.soniclabs.com"), BOB_MAINNET: () => new JsonRpcProvider("https://rpc.gobob.xyz"), BOB_SEPOLIA: () => new JsonRpcProvider("https://bob-sepolia.rpc.gobob.xyz"), WORLD_MAINNET: () => new JsonRpcProvider("https://worldchain.drpc.org"), WORLD_SEPOLIA: () => new JsonRpcProvider("https://worldchain-sepolia.gateway.tenderly.co"), XLAYER_MAINNET: () => new JsonRpcProvider("https://rpc.xlayer.tech"), - XLAYER_TESTNET: () => new JsonRpcProvider("https://testrpc.xlayer.tech"), + XLAYER_TESTNET: () => new JsonRpcProvider("https://testrpc.xlayer.tech/terigon"), BITLAYER_MAINNET: () => new JsonRpcProvider("https://rpc.bitlayer.org"), BITLAYER_TESTNET: () => new JsonRpcProvider("https://testnet-rpc.bitlayer-rpc.com"), INK_MAINNET: () => new JsonRpcProvider("https://rpc-qnd.inkonchain.com"), @@ -109,6 +111,7 @@ export const chainToProvider: Record<SupportedChain, () => Provider> = { MIND_NETWORK_TESTNET: () => new JsonRpcProvider("https://rpc-testnet.mindnetwork.xyz"), MIND_NETWORK_MAINNET: () => new JsonRpcProvider("https://rpc-mainnet.mindnetwork.xyz"), MEGAETH_TESTNET: () => new JsonRpcProvider("https://carrot.megaeth.com/rpc"), + MEGAETH_MAINNET: () => new JsonRpcProvider("https://timothy.megaeth.com/rpc"), "0G_GALILEO_TESTNET": () => new JsonRpcProvider("https://evmrpc-testnet.0g.ai/"), "0G_MAINNET": () => new JsonRpcProvider("https://evmrpc.0g.ai/"), TAIKO_MAINNET: () => new JsonRpcProvider("https://rpc.mainnet.taiko.xyz"), @@ -164,6 +167,14 @@ export const chainToProvider: Record<SupportedChain, () => Provider> = { MONAD_MAINNET: () => new JsonRpcProvider("https://rpc3.monad.xyz"), NEXON_HENESYS_MAINNET: () => new JsonRpcProvider("https://henesys-rpc.msu.io/"), PHAROS_ATLANTIC_TESTNET: () => new JsonRpcProvider("https://atlantic.dplabs-internal.com/"), + MORPH_MAINNET: () => new JsonRpcProvider("https://rpc.morphl2.io"), + MORPH_HOODI_TESTNET: () => new JsonRpcProvider("https://rpc-hoodi.morphl2.io/"), + JOVAY_MAINNET: () => new JsonRpcProvider("https://rpc.jovay.io"), + JOVAY_TESTNET: () => new JsonRpcProvider("https://api.zan.top/public/jovay-testnet"), + STABLE_MAINNET: () => new JsonRpcProvider("https://rpc.stable.xyz"), + TEMPO_TESTNET: () => new JsonRpcProvider("https://rpc.testnet.tempo.xyz"), + ARC_NETWORK_TESTNET: () => new JsonRpcProvider("https://rpc.testnet.arc.network"), + DOGE_OS_CHIKYU_TESTNET: () => new JsonRpcProvider("https://rpc.testnet.dogeos.com/"), } export const getRpcUrlForChain = (chain: SupportedChain): string => { diff --git a/src/content.config.ts b/src/content.config.ts index 10fa1b090e7..bb9b9e18c17 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -60,6 +60,8 @@ const baseFrontmatter = z whatsnext: z.record(z.string(), z.string()).optional(), isMdx: z.boolean().optional(), isIndex: z.boolean().optional(), + disableDefaultStyles: z.boolean().optional(), + hideTitle: z.boolean().optional(), metadata, datafeedtype: z.string().optional(), fileExtension: z.string().optional(), diff --git a/src/content/ccip/api-reference/evm/v1.6.0/burn-mint-erc20.mdx b/src/content/ccip/api-reference/evm/v1.6.0/burn-mint-erc20.mdx index 15cb71d1781..79a37204df2 100644 --- a/src/content/ccip/api-reference/evm/v1.6.0/burn-mint-erc20.mdx +++ b/src/content/ccip/api-reference/evm/v1.6.0/burn-mint-erc20.mdx @@ -15,7 +15,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" An ERC20-compliant token contract that extends the standard functionality with controlled minting and burning capabilities through role-based access control. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) <Aside> diff --git a/src/content/ccip/api-reference/evm/v1.6.0/i-type-and-version.mdx b/src/content/ccip/api-reference/evm/v1.6.0/i-type-and-version.mdx index 692edb3aa2c..94508bad3b6 100644 --- a/src/content/ccip/api-reference/evm/v1.6.0/i-type-and-version.mdx +++ b/src/content/ccip/api-reference/evm/v1.6.0/i-type-and-version.mdx @@ -15,7 +15,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" An interface that provides type and version information for contracts. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/interfaces/ITypeAndVersion.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/interfaces/ITypeAndVersion.sol) ## Functions diff --git a/src/content/ccip/api-reference/evm/v1.6.0/ownable-2-step-msg-sender.mdx b/src/content/ccip/api-reference/evm/v1.6.0/ownable-2-step-msg-sender.mdx index 2b4154b19cf..a525dad5c0c 100644 --- a/src/content/ccip/api-reference/evm/v1.6.0/ownable-2-step-msg-sender.mdx +++ b/src/content/ccip/api-reference/evm/v1.6.0/ownable-2-step-msg-sender.mdx @@ -28,7 +28,7 @@ This prevents accidental transfers to incorrect or inaccessible addresses. </Aside> -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/access/Ownable2StepMsgSender.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/access/Ownable2StepMsgSender.sol) ## Functions diff --git a/src/content/ccip/api-reference/evm/v1.6.0/ownable-2-step.mdx b/src/content/ccip/api-reference/evm/v1.6.0/ownable-2-step.mdx index 09c32e43444..663d4c15508 100644 --- a/src/content/ccip/api-reference/evm/v1.6.0/ownable-2-step.mdx +++ b/src/content/ccip/api-reference/evm/v1.6.0/ownable-2-step.mdx @@ -15,7 +15,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" A minimal contract that implements 2-step ownership transfer and nothing more. It's made to be minimal to reduce the impact of the bytecode size on any contract that inherits from it. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/access/Ownable2Step.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/access/Ownable2Step.sol) <Aside type="note"> This contract implements a secure two-step ownership transfer process: diff --git a/src/content/ccip/api-reference/evm/v1.6.1/burn-mint-erc20.mdx b/src/content/ccip/api-reference/evm/v1.6.1/burn-mint-erc20.mdx index 85833541e3d..01028653d99 100644 --- a/src/content/ccip/api-reference/evm/v1.6.1/burn-mint-erc20.mdx +++ b/src/content/ccip/api-reference/evm/v1.6.1/burn-mint-erc20.mdx @@ -15,7 +15,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" An ERC20-compliant token contract that extends the standard functionality with controlled minting and burning capabilities through role-based access control. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) <Aside> diff --git a/src/content/ccip/api-reference/evm/v1.6.1/i-type-and-version.mdx b/src/content/ccip/api-reference/evm/v1.6.1/i-type-and-version.mdx index 4b21696ded4..d482e169764 100644 --- a/src/content/ccip/api-reference/evm/v1.6.1/i-type-and-version.mdx +++ b/src/content/ccip/api-reference/evm/v1.6.1/i-type-and-version.mdx @@ -15,7 +15,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" An interface that provides type and version information for contracts. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/interfaces/ITypeAndVersion.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/interfaces/ITypeAndVersion.sol) ## Functions diff --git a/src/content/ccip/api-reference/evm/v1.6.1/ownable-2-step-msg-sender.mdx b/src/content/ccip/api-reference/evm/v1.6.1/ownable-2-step-msg-sender.mdx index a7728514163..8de7673cf59 100644 --- a/src/content/ccip/api-reference/evm/v1.6.1/ownable-2-step-msg-sender.mdx +++ b/src/content/ccip/api-reference/evm/v1.6.1/ownable-2-step-msg-sender.mdx @@ -28,7 +28,7 @@ This prevents accidental transfers to incorrect or inaccessible addresses. </Aside> -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/access/Ownable2StepMsgSender.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/access/Ownable2StepMsgSender.sol) ## Functions diff --git a/src/content/ccip/api-reference/evm/v1.6.1/ownable-2-step.mdx b/src/content/ccip/api-reference/evm/v1.6.1/ownable-2-step.mdx index 09d5d9a4247..ed078a04c47 100644 --- a/src/content/ccip/api-reference/evm/v1.6.1/ownable-2-step.mdx +++ b/src/content/ccip/api-reference/evm/v1.6.1/ownable-2-step.mdx @@ -15,7 +15,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" A minimal contract that implements 2-step ownership transfer and nothing more. It's made to be minimal to reduce the impact of the bytecode size on any contract that inherits from it. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/access/Ownable2Step.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/access/Ownable2Step.sol) <Aside type="note"> This contract implements a secure two-step ownership transfer process: diff --git a/src/content/ccip/api-reference/svm/v1.6.0/base-token-pool.mdx b/src/content/ccip/api-reference/svm/v1.6.0/base-token-pool.mdx index c62adb2ece1..731b67b7a3a 100644 --- a/src/content/ccip/api-reference/svm/v1.6.0/base-token-pool.mdx +++ b/src/content/ccip/api-reference/svm/v1.6.0/base-token-pool.mdx @@ -12,7 +12,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" ## Base Token Pool Library -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/base-token-pool) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/base-token-pool) The Base Token Pool library provides foundational components and shared functionality for CCIP token pool implementations on SVM-based blockchains. This library is not deployable as a standalone program but serves as a dependency for concrete token pool implementations like BurnMint and Lock-Release pools. diff --git a/src/content/ccip/api-reference/svm/v1.6.0/burn-mint-token-pool.mdx b/src/content/ccip/api-reference/svm/v1.6.0/burn-mint-token-pool.mdx index 73d3230e020..11549669b4d 100644 --- a/src/content/ccip/api-reference/svm/v1.6.0/burn-mint-token-pool.mdx +++ b/src/content/ccip/api-reference/svm/v1.6.0/burn-mint-token-pool.mdx @@ -12,7 +12,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" ## BurnMint Token Pool -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/burnmint-token-pool) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/burnmint-token-pool) Below is a complete API reference for the CCIP BurnMint Token Pool program instructions. This pool implementation burns tokens on the source chain and mints them on the destination chain. diff --git a/src/content/ccip/api-reference/svm/v1.6.0/lock-release-token-pool.mdx b/src/content/ccip/api-reference/svm/v1.6.0/lock-release-token-pool.mdx index 529553d1547..e4b2d38d413 100644 --- a/src/content/ccip/api-reference/svm/v1.6.0/lock-release-token-pool.mdx +++ b/src/content/ccip/api-reference/svm/v1.6.0/lock-release-token-pool.mdx @@ -12,7 +12,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" ## Lock-Release Token Pool -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/lockrelease-token-pool) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/lockrelease-token-pool) The Lock-Release Token Pool program implements a token pool that uses a lock/release strategy for cross-chain transfers. When tokens are sent cross-chain, they are locked in the pool on the source chain and released from the pool on the destination chain. diff --git a/src/content/ccip/api-reference/svm/v1.6.0/receiver.mdx b/src/content/ccip/api-reference/svm/v1.6.0/receiver.mdx index 538c5d0ccbe..074ce402a7e 100644 --- a/src/content/ccip/api-reference/svm/v1.6.0/receiver.mdx +++ b/src/content/ccip/api-reference/svm/v1.6.0/receiver.mdx @@ -12,7 +12,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" ## Receiver -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/example-ccip-receiver) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/example-ccip-receiver) Below is a complete API reference for the `ccip_receive` instruction that must be implemented by any Solana program wishing to receive CCIP messages. diff --git a/src/content/ccip/api-reference/svm/v1.6.0/router.mdx b/src/content/ccip/api-reference/svm/v1.6.0/router.mdx index 7ec9e046dbd..f54d0fc8e26 100644 --- a/src/content/ccip/api-reference/svm/v1.6.0/router.mdx +++ b/src/content/ccip/api-reference/svm/v1.6.0/router.mdx @@ -12,7 +12,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" ## Router -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/ccip-router) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/ccip-router) Below is a complete API reference for the CCIP Router program instructions. diff --git a/src/content/ccip/billing.mdx b/src/content/ccip/billing.mdx index 9c6ecdc2ae9..d8facd6b324 100644 --- a/src/content/ccip/billing.mdx +++ b/src/content/ccip/billing.mdx @@ -76,7 +76,7 @@ This cost is only relevant if the destination blockchain is a [L2 layer](https:/ ### Network fee -The fee paid to RMN node operators running the [Decentralized Oracle Network](/ccip/concepts/architecture/key-concepts#decentralized-oracle-network-don): +The fee paid to node operators running the [Decentralized Oracle Network](/ccip/concepts/architecture/key-concepts#decentralized-oracle-network-don): #### Token transfers or programmable token transfers diff --git a/src/content/ccip/ccip-execution-latency.mdx b/src/content/ccip/ccip-execution-latency.mdx index 67d9f7d725c..b744e2caa3f 100644 --- a/src/content/ccip/ccip-execution-latency.mdx +++ b/src/content/ccip/ccip-execution-latency.mdx @@ -151,6 +151,7 @@ This section provides an overview of the finality methods CCIP uses to determine | Metis | Finality tag | 2 hours | | Mind Network | Finality tag | 1 hour | | Mode | Finality tag | 37 minutes | +| Monad | [Block depth](#block-depth) (120 blocks) | 48 seconds | | OP | Finality tag | 20 minutes | | Polygon | [Block depth](#block-depth) (500 blocks) | 17 minutes | | Polygon zkEVM | Finality tag | 2 hours | diff --git a/src/content/ccip/concepts/architecture/index.mdx b/src/content/ccip/concepts/architecture/index.mdx index 7b271641134..771bde0354f 100644 --- a/src/content/ccip/concepts/architecture/index.mdx +++ b/src/content/ccip/concepts/architecture/index.mdx @@ -4,8 +4,7 @@ date: Last Modified title: "CCIP Architecture" metadata: description: "Learn about the core architecture of Chainlink CCIP. Explore key concepts, onchain components (EVM/Solana/Aptos), and offchain systems for cross-chain communication." - image: "/images/ccip/concepts/architecture/ccip-offchain-architecture.jpg" - excerpt: "ccip architecture, cross‑chain infrastructure, on‑chain components, off‑chain systems, decentralized oracle networks, risk management network, EVM smart contracts, Solana programs, router, onramp, offramp" + excerpt: "ccip architecture, cross‑chain infrastructure, on‑chain components, off‑chain systems, decentralized oracle networks, EVM smart contracts, Solana programs, router, onramp, offramp" datePublished: "2025-05-19T11:22:47Z" lastModified: "2025-06-09T15:41:42Z" isIndex: true @@ -16,4 +15,4 @@ This section explains the core architecture of the Cross-Chain Interoperability - **[Overview](/ccip/concepts/architecture/overview)**: Get a high-level summary of the CCIP architecture. - **[Key Concepts](/ccip/concepts/architecture/key-concepts)**: Understand the essential terms and components within the CCIP ecosystem. - **[Onchain Components](/ccip/concepts/architecture/onchain)**: Explore the on‑chain components, including EVM smart contracts and Solana programs, and Aptos modules, that operate directly on blockchains. -- **[Offchain Components](/ccip/concepts/architecture/offchain)**: Discover the offchain systems, like the Risk Management Network and Decentralized Oracle Network, that support CCIP operations. +- **[Offchain Components](/ccip/concepts/architecture/offchain/overview)**: Discover the offchain systems that support CCIP operations. diff --git a/src/content/ccip/concepts/architecture/offchain/overview.mdx b/src/content/ccip/concepts/architecture/offchain/overview.mdx index 5a103c91acf..22fa7f72529 100644 --- a/src/content/ccip/concepts/architecture/offchain/overview.mdx +++ b/src/content/ccip/concepts/architecture/offchain/overview.mdx @@ -12,13 +12,21 @@ metadata: estimatedTime: "25 minutes" --- -import { ClickToZoom } from "@components" +import { Aside, ClickToZoom } from "@components" CCIP's offchain architecture includes the following: - **Decentralized Oracle Networks (DONs)**: Running offchain consensus using the Offchain Reporting Protocol (OCR). - **Interaction Components**: Managing communication between the CCIP DONs. +<Aside type="note"> + Based on user demand, CCIP's architecture is evolving to provide enhanced support for modular security and + configurable compliance capabilities. As part of this transition, the Risk Management Network is being adapted to + align with this broader, more flexible architecture. Please see the [onchain + architecture](/ccip/concepts/architecture/onchain/evm/components#rmn-contract) for more information on the current + functionality of the Risk Management Network. +</Aside> + ## Components ### CCIP Decentralized Oracle Networks @@ -27,7 +35,6 @@ With the CCIP v1.6 architecture, there is a single DON called the Role DON that 1. **Commit OCR Plugin** - Coordinates observations from multiple source chains. - - Requests blessings from the RMN (when applicable) and posts a Commit Report on the destination chain. 1. **Executing OCR Plugin** - Monitors pending executions on the destination chain. diff --git a/src/content/ccip/concepts/architecture/onchain/aptos/components.mdx b/src/content/ccip/concepts/architecture/onchain/aptos/components.mdx index 26ccfc690c2..57df428aed2 100644 --- a/src/content/ccip/concepts/architecture/onchain/aptos/components.mdx +++ b/src/content/ccip/concepts/architecture/onchain/aptos/components.mdx @@ -85,18 +85,9 @@ When the Router forwards a `ccip_send` request, the OnRamp performs the followin - If the message involves token transfers, it initiates a secure callback pattern by calling the `Token Admin Dispatcher`. - The dispatcher uses the `Token Admin Registry` to store the message context (sender, receiver, etc.) before invoking the correct `Token Pool` to `lock_or_burn` the assets. -- **Nonce Management** - - For ordered messages, it calls the `Nonce Manager` to retrieve and increment the sender's nonce for that destination. - - **Event Emission** - Generates a unique `messageId` and emits a `CCIPMessageSent` event containing the complete, sequenced message details. -## Nonce Manager - -The `ccip::nonce_manager` module enables optional strict message ordering. It tracks outbound nonces on a per-sender and per-destination-chain basis. - -When out-of-order execution is disabled for a message, the `OnRamp` module uses the `Nonce Manager` to assign an incrementing nonce, which is then verified by the `OffRamp` on the destination chain. - ## OffRamp The `ccip_offramp::offramp` module is an internal CCIP module that operates on the destination chain. It is the primary module that the offchain DONs interact with to deliver messages to Aptos. diff --git a/src/content/ccip/concepts/architecture/onchain/evm/components.mdx b/src/content/ccip/concepts/architecture/onchain/evm/components.mdx index 13da78e8086..e720da295ec 100644 --- a/src/content/ccip/concepts/architecture/onchain/evm/components.mdx +++ b/src/content/ccip/concepts/architecture/onchain/evm/components.mdx @@ -81,7 +81,7 @@ When the Router forwards a `ccipSend()` request to the OnRamp, the contract perf - If the message involves token transfers, it retrieves the correct Token Pool from the Token Admin Registry. - Initiates calls to lock or burn the token, based on the token handling mechanism. 1. **Nonce Management** - - Uses the Nonce Manager to ensure messages requiring in-order execution are processed in the correct order. + - Uses the Nonce Manager to ensure messages requiring in-order execution are processed in the correct order. Note: In-Order enforcement using Nonce Manager will be deprecated in early 2026. 1. **Message ID Generation** - Returns a unique message ID to the Router. 1. **Event Emission** @@ -151,17 +151,6 @@ The FeeQuoter is an internal CCIP smart contract that calculates and returns CCI For additional details on how CCIP fees are calculated, refer to the [CCIP Billing page](/ccip/billing). -## NonceManager - -The NonceManager helps order messages in CCIP by tracking outbound nonces on the source blockchain and inbound nonces on the destination blockchain. It ensures strict ordering when the message's extraArgs parameter requires ordering, thus providing a flexible design. - -1. **Ordered Messages** - - **Non-zero Nonces:** When an OnRamp identifies a message that must preserve ordering, it increments and assigns a non-zero outbound nonce. - - **Inbound Validation:** On the destination blockchain, the OffRamp checks that the incoming message's nonce matches the expected inbound nonce. If there is a mismatch, the message is skipped or deferred for later retry. -1. **Out-of-Order Messages** - - **Zero Nonces:** For messages marked "out of order," the OnRamp sets the nonce to **0**. - - **No Sequence Checks:** Because `nonce == 0` indicates no ordering, the OffRamp does not validate or increment inbound nonces. These messages can execute immediately without waiting for earlier messages. - ## Token Admin Registry The Token Admin Registry is a user-facing CCIP smart contract that maintains a one-to-one mapping between token addresses and their corresponding token pool addresses on a given chain. The OnRamp and OffRamp contracts use the Token Admin Registry to retrieve a token's configured token pool address to call the appropriate functions: diff --git a/src/content/ccip/concepts/architecture/onchain/svm/components.mdx b/src/content/ccip/concepts/architecture/onchain/svm/components.mdx index a151c817efd..5f73c87c26c 100644 --- a/src/content/ccip/concepts/architecture/onchain/svm/components.mdx +++ b/src/content/ccip/concepts/architecture/onchain/svm/components.mdx @@ -64,7 +64,7 @@ This section provides more detail on the Onchain components. **Additional Resources**: -- CCIP provides program examples for a Sender/Receiver in the [Programs folder](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs). +- CCIP provides program examples for a Sender/Receiver in the [Programs folder](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs). ## Router @@ -188,7 +188,7 @@ The FeeQuoter is a central component in Chainlink CCIP that maintains token and - Token Pools are deployed by token developers and exist independently of the core CCIP programs. - Token Pools are programs that interact with SPL token programs. -- Token pools follow standard models (Lock/Release and Burn/Mint), with audited code available in the [CCIP repository](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs). +- Token pools follow standard models (Lock/Release and Burn/Mint), with audited code available in the [CCIP repository](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs). - For tokens requiring bespoke logic before burn/mint/lock/release, custom pools can be built on top of the base pools. More details are available in the CCT documentation. ## Risk Management Network diff --git a/src/content/ccip/concepts/best-practices/evm.mdx b/src/content/ccip/concepts/best-practices/evm.mdx index 70c1146ed6f..dba6b64e2d7 100644 --- a/src/content/ccip/concepts/best-practices/evm.mdx +++ b/src/content/ccip/concepts/best-practices/evm.mdx @@ -4,7 +4,7 @@ date: Last Modified title: "CCIP Best Practices (EVM)" metadata: description: "Comprehensive security guide for CCIP on EVM chains covering message verification, gas optimization, token administration, liquidity management, multi-signature protection, and chain-specific considerations for building secure cross-chain applications." - image: "/images/ccip/ccip-hl-v1.6.gif" + image: "/images/ccip/ccip-hl-v1.6.png" excerpt: "ccip evm best practices ethereum security message verification gas limit optimization token administration liquidity management multi-signature contracts ccip receiver extra args defensive programming" datePublished: "2025-05-19T11:22:47Z" lastModified: "2025-05-19T11:22:47Z" @@ -82,7 +82,7 @@ The `allowOutOfOrderExecution` parameter enables you to control the execution or - **When `allowOutOfOrderExecution` is Optional:** - You can set `allowOutOfOrderExecution` to either `true` or `false`, depending on your application's requirements. - **`true`:** Messages can be executed in any order relative to other messages from the same sender. If a previous message has not yet been executed on the destination chain, it does not block the execution of subsequent messages. - - **`false`:** Messages are executed in order. CCIP ensures that preceding messages are processed before executing the current message. + - **`false`:** Messages are executed in order. CCIP ensures that preceding messages are processed before executing the current message. Note: Functionality for `allowOutofOrderExecution` = `false` (ie., enforcing In-Order cross-chain messages) is being deprecated in early 2026. - **When `allowOutOfOrderExecution` is Required:** - You **must** set `allowOutOfOrderExecution` to `true`. This setting acknowledges that messages may be executed out of order. If set to `false`, the message will revert and will not be processed. diff --git a/src/content/ccip/concepts/best-practices/index.mdx b/src/content/ccip/concepts/best-practices/index.mdx deleted file mode 100644 index 6b982993140..00000000000 --- a/src/content/ccip/concepts/best-practices/index.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -section: ccip -date: Last Modified -title: "CCIP Best Practices" -metadata: - description: "Explore best practices for using Chainlink CCIP securely and effectively on both EVM-compatible and SVM-based blockchains like Solana." - image: "/images/ccip/ccip-hl-v1.6.gif" - excerpt: "ccip best practices cross-chain security message verification token administration liquidity management multi-signature evm guidelines svm guidelines smart contract security solana security" - datePublished: "2025-05-19T11:22:47Z" - lastModified: "2025-05-19T11:22:47Z" -isIndex: true ---- - -This section outlines recommended practices for using Chainlink CCIP effectively and securely across different blockchain families. Learn about security considerations, message verification, token administration, liquidity management, multi-signature patterns, and blockchain-specific guidelines to build robust cross-chain applications on EVM-compatible chains, Solana, and Aptos. diff --git a/src/content/ccip/concepts/cross-chain-token/svm/token-pools.mdx b/src/content/ccip/concepts/cross-chain-token/svm/token-pools.mdx index 91605966cab..078ebc97c58 100644 --- a/src/content/ccip/concepts/cross-chain-token/svm/token-pools.mdx +++ b/src/content/ccip/concepts/cross-chain-token/svm/token-pools.mdx @@ -55,7 +55,7 @@ Before diving into the technical details, it's important to understand your thre **Who should use this:** Projects that need control over upgrade timing or have specific governance requirements. -**How it works:** You compile and deploy the Chainlink-provided [BurnMint](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/burnmint-token-pool) or [LockRelease](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/lockrelease-token-pool) programs to your chosen address, retaining upgrade authority. +**How it works:** You compile and deploy the Chainlink-provided [BurnMint](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/burnmint-token-pool) or [LockRelease](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/lockrelease-token-pool) programs to your chosen address, retaining upgrade authority. ### Approach 3: Custom Token Pools @@ -75,7 +75,7 @@ Before diving into the technical details, it's important to understand your thre Before implementing token pools, you need to choose the appropriate [token handling mechanism](/ccip/concepts/cross-chain-token/overview#token-handling-mechanisms) for your cross-chain token transfers. This strategic decision determines which combination of token pools you'll deploy on source and destination blockchains. -The table below summarizes the different token handling mechanisms and the [recommended token pools](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs) to deploy for each scenario, ensuring a seamless token transfer process. +The table below summarizes the different token handling mechanisms and the [recommended token pools](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs) to deploy for each scenario, ensuring a seamless token transfer process. | Token Handling Mechanism | Source Blockchain Token Pool Type | Destination Blockchain Token Pool Type | How it Works | | ------------------------ | --------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -506,7 +506,7 @@ Understanding who can call which instructions is critical for secure pool operat - You have operational capacity to monitor and maintain pool liquidity levels - Your token participates in [Lock and Mint/Burn and Unlock](/ccip/concepts/cross-chain-token/overview#burn-and-unlock) or [Lock and Unlock](/ccip/concepts/cross-chain-token/overview#lock-and-unlock) token handling mechanisms -Both pool types are built on the shared [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/base-token-pool) foundation, which provides common functionality including [rate limiting](/ccip/concepts/cross-chain-token/overview#token-pool-rate-limits), allowlists, cross-chain configuration, and event handling. +Both pool types are built on the shared [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/base-token-pool) foundation, which provides common functionality including [rate limiting](/ccip/concepts/cross-chain-token/overview#token-pool-rate-limits), allowlists, cross-chain configuration, and event handling. ## Next Steps: Pool Configuration @@ -588,7 +588,7 @@ When CCIP interacts with your custom token pools, it expects the presence of the #### Integration with Base Token Pool -All custom token pools should integrate the [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/base-token-pool) library for core functionality: +All custom token pools should integrate the [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/base-token-pool) library for core functionality: - **Ownership management**: Pool ownership and proposed ownership transfers - **Rate limiting**: Inbound and outbound rate limit controls per destination chain @@ -642,9 +642,9 @@ All standard token pools (BurnMint, LockRelease) automatically call [`to_svm_tok **Implementation References:** -- [BurnMint Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/burnmint-token-pool) - Standard burn/mint implementation -- [LockRelease Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/lockrelease-token-pool) - Standard lock/release implementation -- [Base Token Pool Library](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/base-token-pool) - Shared functionality foundation +- [BurnMint Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/burnmint-token-pool) - Standard burn/mint implementation +- [LockRelease Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/lockrelease-token-pool) - Standard lock/release implementation +- [Base Token Pool Library](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/base-token-pool) - Shared functionality foundation **Testing and Validation:** diff --git a/src/content/ccip/concepts/index.mdx b/src/content/ccip/concepts/index.mdx index ee298def9ff..d0617da379d 100644 --- a/src/content/ccip/concepts/index.mdx +++ b/src/content/ccip/concepts/index.mdx @@ -13,7 +13,7 @@ isIndex: true This section explores the foundational concepts of the Cross-Chain Interoperability Protocol (CCIP). Understanding these concepts will help you effectively build and deploy secure cross-chain applications. -- **[Architecture](/ccip/concepts/architecture)**: Understand the core components and structure of CCIP, including onchain and offchain systems. +- **[Architecture](/ccip/concepts/architecture/overview)**: Understand the core components and structure of CCIP, including onchain and offchain systems. - **[Cross-Chain Token Standard](/ccip/concepts/cross-chain-token)**: Learn about the Cross-Chain Token (CCT) standard that enables secure token transfers across different blockchains. - **[Best Practices](/ccip/concepts/best-practices)**: Discover recommended guidelines for using CCIP effectively and securely on both EVM and SVM blockchains. - **[Manual Execution](/ccip/concepts/manual-execution)**: Learn why some CCIP messages might require manual execution and how to handle these situations. diff --git a/src/content/ccip/concepts/manual-execution.mdx b/src/content/ccip/concepts/manual-execution.mdx index 278b7ea1daf..f5746053712 100644 --- a/src/content/ccip/concepts/manual-execution.mdx +++ b/src/content/ccip/concepts/manual-execution.mdx @@ -20,11 +20,11 @@ whatsnext: import { Aside, ClickToZoom, CopyText } from "@components" <Aside type="note" title="Prerequisites"> - Read the CCIP [Concepts](/ccip/concepts) and [Architecture](/ccip/concepts/architecture) pages to understand all the - concepts discussed on this page. + Read the CCIP [Concepts](/ccip/concepts) and [Architecture](/ccip/concepts/architecture/overview) pages to understand + all the concepts discussed on this page. </Aside> -In general, messages are successfully delivered and processed via CCIP as described in the [Architecture](/ccip/concepts/architecture) page. However, some exceptional conditions might require users to manually execute the transaction on the destination blockchain: +In general, messages are successfully delivered and processed via CCIP as described in the [Architecture](/ccip/concepts/architecture/overview) page. However, some exceptional conditions might require users to manually execute the transaction on the destination blockchain: - The receiver contract on the destination blockchain reverted due to an unhandled exception such as a logical error. - For token pools, if the combined execution of the required functions (`balanceOf` checks and `releaseOrMint`) exceeds the default gas limit of **90,000 gas** on the destination blockchain, CCIP execution will fail. Read the Token pools [common requirements](/ccip/concepts/cross-chain-token/evm/token-pools#common-requirements) to learn more. diff --git a/src/content/ccip/concepts/rate-limit-management/common-scenarios.mdx b/src/content/ccip/concepts/rate-limit-management/common-scenarios.mdx new file mode 100644 index 00000000000..c5a29fd7db8 --- /dev/null +++ b/src/content/ccip/concepts/rate-limit-management/common-scenarios.mdx @@ -0,0 +1,109 @@ +--- +section: ccip +date: Last Modified +title: "Common Scenarios" +--- + +This page provides worked configuration scenarios for common rate limit use cases. These examples illustrate how capacity and refill values are calculated and applied for different token types and operational goals. + +All scenarios assume: + +- you have the `rateLimitAdmin` role +- you have inspected the current configuration +- you have validated token units and decimals + +These scenarios are examples, not defaults. Values must always be recalculated for the specific token, lane, and risk tolerance. + +## Scenario: 18-decimal tokens + +This scenario applies to tokens with **18 decimals**, such as LINK or ETH. + +### When to use this + +Use this pattern when managing rate limits for an 18-decimal token and you want to allow a bounded amount of value to flow steadily between two chains. + +### Example configuration + +Assumptions: + +- desired inbound capacity: 20 tokens +- desired outbound capacity: 10 tokens +- refill rate: 0.1 tokens per second + +Converted to base units: + +- inbound capacity: `20 × 10^18 = 20000000000000000000` +- outbound capacity (90% of inbound): `10 × 10^18 = 10000000000000000000` +- refill rate: `0.1 × 10^18 = 100000000000000000` + +Inbound and outbound limits are configured separately for each token pool, with values swapped appropriately on each side of the lane. + +## Scenario: 6-decimal tokens + +This scenario applies to tokens with **6 decimals**, such as USDC or USDT. + +### When to use this + +Use this pattern when configuring rate limits for stablecoins or other low-decimal tokens. + +### Example configuration + +Assumptions: + +- desired inbound capacity: 2000 tokens +- desired outbound capacity: 1000 tokens +- inbound refill rate: 5 tokens per second +- outbound refill rate: 10 tokens per second + +Converted to base units: + +- inbound capacity: `2000 × 10^6 = 2000000000` +- outbound capacity (90% of inbound): `1000 × 10^6 = 1000000000` +- inbound refill rate: `5 × 10^6 = 5000000` +- outbound refill rate: `10 × 10^6 = 10000000` + +As with 18-decimal tokens, inbound and outbound configurations must be applied on both sides of the lane. + +## Scenario: pausing a lane + +This scenario demonstrates how to effectively pause transfers on a specific lane using rate limits. + +### When to use this + +Use this pattern during incidents, investigations, or maintenance when transfers must be temporarily halted. + +### Configuration pattern + +To lock down a lane: + +- enable the rate limit +- set capacity to `1` +- set refill rate to `1` + +Apply this configuration to **both inbound and outbound** limits for the lane. + +This allows only a negligible transfer before capacity is exhausted, causing subsequent transfers to fail. + +## Scenario: removing rate limits + +This scenario demonstrates how to remove rate limits entirely for a lane. + +### When to use this + +Use this pattern only when you intentionally want transfers to be unconstrained by rate limits. + +### Configuration pattern + +To remove rate limits: + +- set `isEnabled` to `false` +- set `capacity` to `0` +- set `rate` to `0` + +Apply this configuration to both inbound and outbound limits. + +## Important notes + +- Scenario values must always be recalculated for the specific token and lane +- Do not copy example values without adjusting for decimals and desired behavior +- Changes take effect immediately once the transaction is confirmed diff --git a/src/content/ccip/concepts/rate-limit-management/emergency-actions.mdx b/src/content/ccip/concepts/rate-limit-management/emergency-actions.mdx new file mode 100644 index 00000000000..793ece7030f --- /dev/null +++ b/src/content/ccip/concepts/rate-limit-management/emergency-actions.mdx @@ -0,0 +1,67 @@ +--- +section: ccip +date: Last Modified +title: "Emergency Actions (Incident Response Only)" +--- + +This page describes emergency actions that can be taken to **contain or halt cross-chain transfers on a specific CCIP lane** using rate limit configuration. + +These actions are intended for **incident response, maintenance, or risk containment** scenarios. They should not be used for routine configuration. + +## When to use emergency actions + +You may need to take emergency action if: + +- abnormal or unexpected transfer activity is detected +- a misconfiguration or incident is under investigation +- maintenance requires temporarily stopping transfers on a lane + +Emergency actions are scoped to a **specific token pool and lane**. They do not pause CCIP globally. + +## Locking down a lane with minimal values + +To effectively stop bridging activity on a lane, you can configure rate limits with **very small capacity and refill values**. + +Because rate limits cannot be set to zero while enabled, the practical approach is to set: + +- **capacity** to the smallest transferable unit (for example, `1`) +- **rate** to `1` + +This configuration allows only a negligible transfer before the bucket is depleted, causing subsequent transfers to fail. + +## Example configuration + +Conceptually, a lane can be locked down by calling `setChainRateLimiterConfig` with the following values: + +```solidity +outboundConfig = [true, 1, 1]; +inboundConfig = [true, 1, 1]; +``` + +Both inbound and outbound limits should be set to ensure transfers are blocked in both directions. + +## Important considerations + +When locking down a lane: + +- transfers may still succeed for a minimal amount before capacity is exhausted +- behavior depends on the token’s smallest unit +- the change takes effect immediately after the transaction is confirmed + +This approach is intended to **contain activity**, not to permanently disable rate limits. + +## Restoring normal operation + +To resume normal transfers, update the inbound and outbound rate limit configuration with appropriate capacity and refill values. + +Always revalidate token units and existing configuration before restoring service. + +## What this page does not cover + +This page does not cover: + +- routine rate limit tuning +- worked examples for different token decimals +- fully removing rate limits + +Those topics are covered in the [common scenarios](/ccip/concepts/rate-limit-management/common-scenarios) section. diff --git a/src/content/ccip/concepts/rate-limit-management/executing-with-a-multisig.mdx b/src/content/ccip/concepts/rate-limit-management/executing-with-a-multisig.mdx new file mode 100644 index 00000000000..79ca4c0849a --- /dev/null +++ b/src/content/ccip/concepts/rate-limit-management/executing-with-a-multisig.mdx @@ -0,0 +1,151 @@ +--- +section: ccip +date: Last Modified +title: "Executing with a Multisig" +--- + +Rate limit changes are commonly executed from a **multisig wallet** to reduce operational risk and ensure changes are reviewed before being applied on-chain. + +This page describes the high-level execution model for multisig-based updates and points to tooling that can be used to submit transactions safely. + +## Why use a multisig + +Managing CCIP rate limits directly affects cross-chain transfer availability. Using a multisig helps: + +- require multiple reviewers before changes are executed +- reduce the risk of accidental misconfiguration +- provide an auditable record of approvals + +For this reason, the `rateLimitAdmin` role is typically assigned to a multisig wallet rather than to an individual account. + +## What the multisig submits + +Regardless of the interface used, a multisig ultimately submits a transaction that calls: + +- the token pool contract address +- the `setChainRateLimiterConfig` function +- the selected remote chain selector +- inbound and outbound configuration tuples + +The multisig does not change how rate limits work on-chain; it only controls how the transaction is approved and submitted. + +## Building the transaction + +To build a rate limit update transaction using a multisig: + +- identify the correct token pool contract address +- prepare the `setChainRateLimiterConfig` function call +- supply the remote chain selector +- enter the inbound and outbound configuration values as tuples + +Configuration tuples must be entered as arrays containing: + +- `isEnabled` +- `capacity` +- `rate` + +All numeric values must be expressed in the token’s smallest unit. + +## Tooling options + +Common tooling options for executing multisig transactions include: + +- Safe transaction builder +- custom scripts that submit transactions to the multisig +- internal operator tooling built on top of web3 libraries + +The specific interface used does not affect the on-chain outcome. + +## Verification before submission + +Before submitting a multisig transaction: + +- confirm the token pool contract address +- verify the remote chain selector +- recheck inbound and outbound directions +- validate capacity and rate values in base units + +Because rate limit changes take effect immediately, careful review is essential. + +## After execution + +Once the multisig transaction is executed and confirmed on-chain: + +- the updated rate limits apply immediately +- transfers follow the new configuration + +Monitor behavior after execution to confirm the expected outcome. + +## setChainRateLimiterConfig ABI + +The following ABI is provided to support multisig and transaction builder workflows where the function interface must be supplied manually. This is a direct representation of the function used to update CCIP rate limits. + +```json +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "remoteChainSelector", + "type": "uint64" + }, + { + "components": [ + { + "internalType": "bool", + "name": "isEnabled", + "type": "bool" + }, + { + "internalType": "uint128", + "name": "capacity", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "rate", + "type": "uint128" + } + ], + "internalType": "struct RateLimiter.Config", + "name": "outboundConfig", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "isEnabled", + "type": "bool" + }, + { + "internalType": "uint128", + "name": "capacity", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "rate", + "type": "uint128" + } + ], + "internalType": "struct RateLimiter.Config", + "name": "inboundConfig", + "type": "tuple" + } + ], + "name": "setChainRateLimiterConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] +``` + +## Related references + +- [Inspect Current Rate Limits](/ccip/concepts/rate-limit-management/inspect-current-rate-limits) +- [Update Rate Limits](/ccip/concepts/rate-limit-management/update-rate-limits) +- [Common Scenarios](/ccip/concepts/rate-limit-management/common-scenarios) + +For tool-specific walkthroughs, refer to the Token Manager and multisig documentation linked from the Tools section. diff --git a/src/content/ccip/concepts/rate-limit-management/how-rate-limits-work.mdx b/src/content/ccip/concepts/rate-limit-management/how-rate-limits-work.mdx new file mode 100644 index 00000000000..ecf3e7e86d3 --- /dev/null +++ b/src/content/ccip/concepts/rate-limit-management/how-rate-limits-work.mdx @@ -0,0 +1,76 @@ +--- +section: ccip +date: Last Modified +title: "How Rate Limits Work" +--- + +This page explains how CCIP rate limits function at a conceptual level. It focuses on _what the system does_ and _how the parameters interact_, without covering how to make changes on-chain. + +## Rate limits as capacity buckets + +CCIP rate limits are implemented as **capacity buckets** that refill over time. Each bucket starts with a defined maximum capacity and refills continuously at a fixed rate. + +Transfers draw down capacity from the relevant bucket. If insufficient capacity is available, the transfer is rejected until enough capacity has refilled. + +This model limits how much value can move through a CCIP lane within a given time window, even if many transfers are attempted. + +## Inbound and outbound rate limits + +Each token pool maintains **two independent rate limits per connected chain**: + +- **Outbound rate limit**: limits transfers _from_ the local chain _to_ a remote chain +- **Inbound rate limit**: limits transfers _from_ a remote chain _into_ the local chain + +Inbound and outbound limits are configured separately and can differ in capacity and refill rate. This allows operators to tune risk asymmetrically depending on the direction of flow. + +In practice, outbound limits are often configured to be slightly lower than inbound limits to provide buffer room and reduce the risk of in-flight congestion. + +## Core rate limit parameters + +Each inbound or outbound rate limit is defined by three parameters: + +- **isEnabled**: whether the rate limit is active +- **capacity**: the maximum amount of tokens that can be transferred before the bucket is depleted +- **rate**: the speed at which capacity refills, measured in tokens per second + +All values are expressed in the token’s **smallest unit**, not in whole tokens. + +## Token bucket state + +At any moment, a rate limiter tracks the current state of its bucket, including: + +- the remaining number of tokens available +- the timestamp of the last refill +- whether the limiter is enabled +- the configured capacity and refill rate + +This state determines whether a transfer can proceed and how quickly capacity becomes available again after use. + +## Enabled vs disabled behavior + +When a rate limit is **enabled**, transfers are constrained by the configured capacity and refill rate. + +When a rate limit is **disabled**, transfers are not subject to any volume limits for that lane. + +Disabling rate limits removes an important safety mechanism and should only be done intentionally and with a clear understanding of the associated risk. + +## Scope and granularity + +Rate limits are applied: + +- per token pool +- per remote chain +- independently for inbound and outbound directions + +This means changes to a rate limit affect only a specific token and lane, not all CCIP traffic. + +## What this page does not cover + +This page does not cover: + +- required permissions to manage rate limits +- how to inspect current configurations +- how to update or disable rate limits +- emergency or incident response actions + +Those topics are covered in the subsequent pages of this section. diff --git a/src/content/ccip/concepts/rate-limit-management/inspect-current-rate-limits.mdx b/src/content/ccip/concepts/rate-limit-management/inspect-current-rate-limits.mdx new file mode 100644 index 00000000000..65e8b1c1423 --- /dev/null +++ b/src/content/ccip/concepts/rate-limit-management/inspect-current-rate-limits.mdx @@ -0,0 +1,95 @@ +--- +section: ccip +date: Last Modified +title: "Inspect Current Rate Limits" +--- + +Before updating any rate limit configuration, you should inspect the **current inbound and outbound settings** for the token pool and lane you are managing. This ensures you understand the existing capacity, refill rate, and enabled state before making changes. + +## What you can inspect + +Each token pool exposes read-only functions that return the current rate limiter state for a given remote chain. These values describe: + +- whether the inbound or outbound rate limit is enabled +- the configured capacity +- the configured refill rate +- the current number of tokens available in the bucket +- the timestamp of the last refill + +Together, these values determine whether transfers are currently allowed and how quickly capacity becomes available. + +## Identify the token pool contract + +To inspect rate limits, you first need the **token pool contract address** for the token you are managing. + +You can find token pool addresses using the Token Manager or by searching for the token contract address in the token manager search interface. + +## Select the remote chain + +Rate limits are configured per remote chain. When querying a rate limiter, you must provide the **remote chain selector** that identifies the cross-chain lane you want to inspect. + +Chain selectors are represented as `uint64` values. You can find the correct selector for each supported network in the CCIP directory. + +## Query inbound and outbound limiter state + +Most token pool contracts expose public getter functions similar to: + +```solidity +function getCurrentInboundRateLimiterState( + uint64 remoteChainSelector +) external view returns (TokenBucket memory); + +function getCurrentOutboundRateLimiterState( + uint64 remoteChainSelector +) external view returns (TokenBucket memory); + +``` + +These functions take a remote chain selector as input and return the current **TokenBucket** state for that lane. + +You can call these functions using: + +- a block explorer’s “Read Contract” interface +- a web3-enabled script or client + +## Interpreting the TokenBucket state + +A typical rate limiter state includes the following fields: + +```solidity +struct TokenBucket { + uint128 tokens; + uint32 lastUpdated; + bool isEnabled; + uint128 capacity; + uint128 rate; +} +``` + +Where: + +- tokens (uint128): the current number of tokens available in the bucket +- lastUpdated (uint32): the timestamp of the last refill +- isEnabled (bool): whether the rate limit is active +- capacity (uint128): the maximum bucket size +- rate (uint128): the refill rate in tokens per second +- All numeric values are expressed in the token’s **smallest unit**, not in whole tokens. + +## Inbound vs outbound inspection + +Inbound and outbound configurations should be inspected **independently**: + +- outbound limits control transfers leaving the current chain +- inbound limits control transfers entering the current chain + +Although these values are often similar, they may intentionally differ based on risk tolerance and traffic patterns. + +## Before proceeding + +After inspecting the current configuration: + +- record the existing values +- confirm token decimals and unit conversions +- identify which direction and lane you intend to modify + +Only proceed to updating rate limits once you fully understand the current state. diff --git a/src/content/ccip/concepts/rate-limit-management/overview.mdx b/src/content/ccip/concepts/rate-limit-management/overview.mdx new file mode 100644 index 00000000000..eda11857ea2 --- /dev/null +++ b/src/content/ccip/concepts/rate-limit-management/overview.mdx @@ -0,0 +1,71 @@ +--- +section: ccip +date: Last Modified +title: "Rate Limit Management Overview" +--- + +CCIP rate limits are an **operator-level control** that apply to token pools used for cross-chain transfers. They are designed to limit the volume of tokens that can move across a specific CCIP lane over time, reducing the blast radius of unexpected behavior and helping manage operational risk. + +This documentation is intended for **CCIP operators, token issuers, and administrators** who have been granted permission to manage rate limits on their token pool contracts. Most CCIP users do **not** need to interact with rate limits as part of a standard integration. + +Rate limit changes are applied on-chain, take effect immediately, and directly affect user-facing transfer availability. + +## What rate limits are + +Rate limits in CCIP act as **capacity buckets** that refill over time. Each token pool maintains two independent limits for every connected chain: + +- **Outbound rate limits**: how much of a token can be sent _from_ the current chain to a remote chain +- **Inbound rate limits**: how much of a token can be received _from_ a remote chain into the current chain + +Each limit is defined by: + +- whether it is enabled +- a maximum capacity +- a refill rate (tokens per second) + +Together, these parameters control how much value can flow through a CCIP lane within a given time window. + +## Why rate limits exist + +Rate limits are a defensive mechanism. They help: + +- prevent large, single transfers from draining liquidity unexpectedly +- limit exposure during misconfiguration, incidents, or active investigations +- give operators time to react if abnormal activity is detected + +Inbound and outbound limits are intentionally separate so that operators can tune risk asymmetrically depending on the direction of flow. + +## Who this applies to + +You should only interact with CCIP rate limits if **all** of the following are true: + +- You operate or administer a CCIP token pool +- Your wallet (typically a multisig) has been granted the `rateLimitAdmin` role +- You understand the decimal precision and units used by the token +- You are prepared to take responsibility for the operational impact of changes + +If these conditions are not met, you should not attempt to modify rate limits. + +## Responsibility and risk + +Managing rate limits directly affects the availability of cross-chain transfers for a token. Incorrect configuration can: + +- unintentionally halt bridging +- allow more volume than intended +- create congestion or stuck transfers + +Changes are applied on-chain and take effect immediately. Always review parameters carefully, verify units, and use a multisig workflow where possible. + +## What this section covers + +The pages in this section walk through: + +- how CCIP rate limits work +- required permissions and prerequisites +- inspecting current inbound and outbound configurations +- accounting for token decimals and units +- updating rate limits safely +- emergency actions such as locking down a lane +- common configuration scenarios + +This content focuses on **operational control**, not on basic CCIP integration or application development. diff --git a/src/content/ccip/concepts/rate-limit-management/prerequisites-and-permissions.mdx b/src/content/ccip/concepts/rate-limit-management/prerequisites-and-permissions.mdx new file mode 100644 index 00000000000..419f222dc21 --- /dev/null +++ b/src/content/ccip/concepts/rate-limit-management/prerequisites-and-permissions.mdx @@ -0,0 +1,66 @@ +--- +section: ccip +date: Last Modified +title: "Prerequisites and Permissions" +--- + +Managing CCIP rate limits is a privileged, operator-level action. Before attempting to inspect or modify any rate limit configuration, you must meet the prerequisites described on this page. + +## Required permissions + +To manage rate limits, your wallet must be granted the **`rateLimitAdmin`** role on the relevant token pool contracts. + +This role allows the wallet to update inbound and outbound rate limit configurations for specific cross-chain lanes. Without it, you can read on-chain data but cannot make changes. + +In most cases, the `rateLimitAdmin` role is assigned to a **multisig wallet** rather than to an individual externally owned account. + +## How admin access is granted + +Admin access is not self-assigned. + +To receive the `rateLimitAdmin` role: + +- You provide the address of your designated wallet (typically a multisig) +- Chainlink Labs assigns that address as the rate limit administrator on the relevant token pool contracts + +Once the on-chain transaction granting this role is confirmed, the wallet can update rate limit configurations. + +## Scope of admin authority + +The `rateLimitAdmin` role applies: + +- per token pool +- across inbound and outbound directions +- per connected chain + +This means: + +- you can manage rate limits only for token pools where your wallet has been granted access +- changes affect only the specified token and lane +- core CCIP configuration outside of rate limits is not affected + +## Operational expectations + +Before making any changes, you should ensure that: + +- you understand the token’s decimal precision and smallest unit +- you have reviewed the current inbound and outbound configurations +- you are prepared to validate values carefully before submitting transactions + +Rate limit changes are applied on-chain and take effect immediately. + +## Responsibility boundary + +By managing rate limits, you take responsibility for the availability of cross-chain transfers for the affected token and lane. + +Incorrect configuration can: + +- unintentionally block transfers +- allow more volume than intended +- create operational or user-facing disruption + +For this reason, rate limit management should follow a deliberate review process and use a multisig workflow where possible. + +## What’s next + +If you meet these prerequisites, the next step is to [inspect the current inbound and outbound rate limit](/ccip/concepts/rate-limit-management/inspect-current-rate-limits) configuration before making any changes. diff --git a/src/content/ccip/concepts/rate-limit-management/token-units-and-decimals.mdx b/src/content/ccip/concepts/rate-limit-management/token-units-and-decimals.mdx new file mode 100644 index 00000000000..9f1c6273902 --- /dev/null +++ b/src/content/ccip/concepts/rate-limit-management/token-units-and-decimals.mdx @@ -0,0 +1,89 @@ +--- +section: ccip +date: Last Modified +title: "Token Units and Decimals" +--- + +When configuring CCIP rate limits, **all values are specified in the token’s smallest unit**, not in whole tokens. Understanding token decimals is critical to setting correct capacity and refill rates. + +Incorrect unit handling can result in rate limits that are orders of magnitude larger or smaller than intended. + +## Smallest unit vs human-readable amounts + +Every ERC-20 token defines a number of decimal places that determine its smallest unit: + +- An 18-decimal token (for example, LINK or ETH) uses `10^18` base units per token +- A 6-decimal token (for example, USDC or USDT) uses `10^6` base units per token + +Rate limit parameters such as **capacity** and **rate** must always be provided in these base units. + +## Converting values for on-chain configuration + +To convert a human-readable token amount into the value used on-chain, apply the following formula: + +``` +On-chain value = human-readable amount × (10 ^ token decimals) +``` + +This conversion applies to: + +- capacity values +- refill rate values + +## Example: 18-decimal token + +Token: + +- Decimals: 18 +- Desired capacity: 100 tokens + +Calculation: + +``` +100 × 10^18 = 100000000000000000000 +``` + +The capacity value passed to the token pool contract must be `100000000000000000000`. + +## Example: 6-decimal token + +Token: + +- Decimals: 6 +- Desired capacity: 500 tokens + +Calculation: + +``` +500 × 10^6 = 500000000 +``` + +The capacity value passed to the token pool contract must be `500000000`. + +## Common failure modes + +The most common causes of misconfiguration include: + +- assuming values are specified in whole tokens +- applying the wrong decimal precision +- copying example values without recalculating for the target token + +Any of these mistakes can: + +- unintentionally block transfers +- allow far more volume than expected +- create operational risk that is difficult to detect immediately + +## Before updating rate limits + +Before submitting any transaction that updates rate limits: + +- verify the token’s decimal precision +- recompute capacity and rate values from first principles +- double-check values in base units + +Once values are submitted on-chain, they take effect immediately. + +## What’s next + +After validating units and conversions, you can proceed to [updating inbound and outbound rate limits](/ccip/concepts/rate-limit-management/update-rate-limits) for the selected token pool and lane. diff --git a/src/content/ccip/concepts/rate-limit-management/update-rate-limits.mdx b/src/content/ccip/concepts/rate-limit-management/update-rate-limits.mdx new file mode 100644 index 00000000000..92223c39377 --- /dev/null +++ b/src/content/ccip/concepts/rate-limit-management/update-rate-limits.mdx @@ -0,0 +1,93 @@ +--- +section: ccip +date: Last Modified +title: "Update Rate Limits" +--- + +Once you understand the current configuration and have validated token units and decimals, you can update inbound and outbound rate limits for a specific token pool and lane. + +Rate limit updates are applied on-chain and take effect immediately. Changes should be made deliberately and reviewed carefully before submission. + +## Function used to update rate limits + +Rate limits are updated by calling the `setChainRateLimiterConfig` function on the token pool contract. + +This function updates both the inbound and outbound rate limit configuration for a given remote chain. + +## Required parameters + +The `setChainRateLimiterConfig` function takes three parameters: + +```solidity +function setChainRateLimiterConfig( + uint64 remoteChainSelector, + RateLimiter.Config outboundConfig, + RateLimiter.Config inboundConfig +) external; +``` + +Each configuration tuple contains: + +```solidity +struct Config { + bool isEnabled; + uint128 capacity; + uint128 rate; +} +``` + +- **isEnabled**: whether the rate limit is active +- **capacity**: maximum bucket size (in base units) +- **rate**: refill rate in tokens per second (in base units) + +## Inbound and outbound configuration guidance + +Inbound and outbound limits are configured independently, but they are related. + +A common operational pattern is: + +- configure **outbound capacity** to be lower than inbound capacity +- set outbound capacity to approximately **90% of the inbound value** + +This provides buffer room and reduces the likelihood of in-flight congestion. + +## Example interaction (conceptual) + +Rate limit updates are typically executed using a web3-enabled client or a multisig wallet. + +At a high level, updating a rate limit involves: + +- selecting the token pool contract address +- providing the remote chain selector +- supplying outbound and inbound configuration tuples +- submitting the transaction from a wallet with the `rateLimitAdmin` role + +The exact tooling used does not change the on-chain behavior. + +## Verifying before submission + +Before submitting a rate limit update: + +- re-check all values are expressed in the token’s smallest unit +- confirm inbound and outbound directions are not swapped +- verify the correct remote chain selector is used +- review existing values to ensure changes are intentional + +## After the update + +Once the transaction is confirmed: + +- the new rate limits apply immediately +- transfers are accepted or rejected based on the updated configuration + +You should monitor behavior after changes to confirm the limits behave as expected. + +## What this page does not cover + +This page does not cover: + +- emergency actions such as locking down a lane +- worked examples for specific token decimals +- tool-specific execution steps + +Those topics are covered in the following pages. diff --git a/src/content/ccip/getting-started/evm.mdx b/src/content/ccip/getting-started/evm.mdx index 96d0822ddee..58c1497d06e 100644 --- a/src/content/ccip/getting-started/evm.mdx +++ b/src/content/ccip/getting-started/evm.mdx @@ -1,12 +1,12 @@ --- section: ccip date: Last Modified -title: "Getting Started (EVM)" +title: "Get Started with CCIP (EVM)" metadata: description: "Get started with Chainlink CCIP on EVM chains. Deploy sender/receiver contracts, send data cross-chain, and pay fees in LINK." excerpt: "Chainlink CCIP, EVM chains, Ethereum, Avalanche, Cross-chain messaging, Solidity contracts, LINK token, Remix IDE, MetaMask, Testnet" datePublished: "2025-05-19" - lastModified: "2025-05-19" + lastModified: "2025-12-25" estimatedTime: "20 minutes" whatsnext: { @@ -18,48 +18,663 @@ whatsnext: } --- -import { CodeSample, ClickToZoom, CopyText, Aside } from "@components" +import { Callout } from "@components/Callout/Callout.tsx" +import { Accordion, CodeSample, ClickToZoom, CopyText, Aside } from "@components" import CcipCommon from "@features/ccip/CcipCommon.astro" -<CcipCommon callout="talkToExpert" /> +**Build and run a secure cross-chain messaging workflow between two EVM chains using Chainlink CCIP.** -A simple use case for Chainlink CCIP is sending data between smart contracts on different blockchains. This guide shows you how to deploy a CCIP sender contract and a CCIP receiver contract to two different blockchains and send data from the sender contract to the receiver contract. You pay the CCIP fees using LINK. +In this guide, you will: -Fees can also be paid in alternative assets, which currently include the native gas tokens of the source blockchain and their ERC20 wrapped version. For example, you can pay ETH or WETH when you send transactions to the CCIP router on Ethereum and AVAX or WAVAX when you send transactions to the CCIP router on Avalanche. +1. Deploy a sender on a source chain +2. Deploy a receiver on a destination chain +3. Send and verify a cross-chain message ## Before you begin -- If you are new to smart contract development, learn how to [Deploy Your First Smart Contract](/quickstarts/deploy-your-first-contract) so you are familiar with the tools that are necessary for this guide: - - The [Solidity](https://soliditylang.org/) programming language - - The [MetaMask](https://metamask.io) wallet - - The [Remix](https://remix.ethereum.org/) development environment -- Acquire testnet funds. This guide requires testnet AVAX and LINK on _Avalanche Fuji_. It also requires testnet ETH on _Ethereum Sepolia_. If you need to use different networks, you can find more faucets on the [LINK Token Contracts](/resources/link-token-contracts) page. - - Go to [faucets.chain.link](https://faucets.chain.link/) to get your testnet tokens. -- Learn how to [Fund your contract with LINK](/resources/fund-your-contract). +<Aside type="note" title="Please note"> + We use the same two smart contracts throughout the tutorial. You can check them out in the [Examine the example + code](#examine-the-example-code) section. +</Aside> -## Deploy the sender contract +You will need: -Deploy the `Sender.sol` contract on _Avalanche Fuji_. To see a detailed explanation of this contract, read the [Code Explanation](#sender-code) section. +- Basic [Solidity](https://soliditylang.org/) and [smart contract deployment](/quickstarts/deploy-your-first-contract) experience +- One [wallet](https://metamask.io/) funded on two CCIP-supported EVM testnets: [Avalanche Fuji and Ethereum Sepolia](/ccip/directory/testnet). You will need some native tokens and `LINK` on both networks. + +- Choose one of the following development environments: + - **[Hardhat 3](https://hardhat.org/docs/getting-started)** + - **[Foundry](https://book.getfoundry.sh/)** + - **[Remix](https://remix-ide.readthedocs.io/en/latest/)** + +## Examine the example code + +This section goes through the code for the `sender` and `receiver` contracts +needed to complete the tutorial. +We will use the same contracts for all three development environments. + +<br /> + +<Accordion title="Sender code" number={1}> + +The smart contract in this tutorial is designed to interact with CCIP to send data. The contract code includes comments to clarify the various functions, events, and underlying logic. However, this section explains the key elements. You can see the full contract code below. + +<CodeSample src="samples/CCIP/Sender.sol" filename="Sender.sol" /> + +#### Initializing the contract + +When deploying the contract, you define the router address and the LINK contract address of the blockchain where you choose to deploy the contract. + +The router address provides functions that are required for this example: + +- The `getFee` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#getfee) to estimate the CCIP fees. +- The `ccipSend` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#ccipsend) to send CCIP messages. + +#### Sending data + +The `sendMessage` function completes several operations: + +1. Construct a CCIP-compatible message using the `EVM2AnyMessage` [struct](/ccip/api-reference/evm/v1.6.1/client#evm2anymessage): + - The `receiver` address is encoded in bytes format to accommodate non-EVM destination blockchains with distinct address formats. The encoding is achieved through [abi.encode](https://docs.soliditylang.org/en/develop/abi-spec.html). + - The `data` is encoded from a string text to bytes using [abi.encode](https://docs.soliditylang.org/en/develop/abi-spec.html). + - The `tokenAmounts` is an array. Each element comprises a [struct](/ccip/api-reference/evm/v1.6.1/client#evmtokenamount) that contains the token address and amount. In this example, the array is empty because no tokens are sent. + - The `extraArgs` specify the `gasLimit` for relaying the CCIP message to the recipient contract on the destination blockchain. In this example, the `gasLimit` is set to `200000`. + - The `feeToken` designates the token address used for CCIP fees. Here, `address(linkToken)` signifies payment in LINK. + +1. Compute the fees by invoking the router's `getFee` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#getfee). +1. Ensure that your contract balance in LINK is enough to cover the fees. +1. Grant the router contract permission to deduct the fees from the contract's LINK balance. +1. Dispatch the CCIP message to the destination chain by executing the router's `ccipSend` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#ccipsend). + +<CcipCommon callout="senderContractCallout" /> + +</Accordion> + +<Accordion title="Receiver code" number={2}> + +The smart contract in this tutorial is designed to interact with CCIP to receive data. The contract code includes comments to clarify the various functions, events, and underlying logic. However, this section explains the key elements. You can see the full contract code below. + +<CodeSample src="samples/CCIP/Receiver.sol" filename="Receiver.sol" /> + +#### Initializing the contract + +When you deploy the contract, you define the router address. The receiver contract inherits from the [CCIPReceiver.sol](/ccip/api-reference/evm/v1.6.1/ccip-receiver) contract, which uses the router address. + +#### Receiving data + +On the destination blockchain: + +1. The CCIP Router invokes the `ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#ccipreceive). **Note**: This function is protected by the `onlyRouter` [modifier](/ccip/api-reference/evm/v1.6.1/ccip-receiver#onlyrouter), which ensures that only the router can call the receiver contract. + +2. The `ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#ccipreceive) calls an internal function `_ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#_ccipreceive). The receiver contract implements this function. + +<Aside type="caution" title="_ccipReceive"> +- It is critical for the receiver contract to implement this function. + +- The CCIP router will look for this function to deliver the message to the receiver contract. + +- The message won't be delivered to the receiver contract if this + function is not implemented correctly. + +</Aside> + +3. This `_ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#_ccipreceive) expects an `Any2EVMMessage` [struct](/ccip/api-reference/evm/v1.6.1/client#any2evmmessage) that contains the following values: + - The CCIP `messageId`. + - The `sourceChainSelector`. + - The `sender` address in bytes format. The sender is a contract deployed on an EVM-compatible blockchain, so the address is decoded from bytes to an Ethereum address using the [ABI specification](https://docs.soliditylang.org/en/v0.8.20/abi-spec.html). + - The `data` is also in bytes format. A `string` is expected, so the data is decoded from bytes to a string using the [ABI specification](https://docs.soliditylang.org/en/v0.8.20/abi-spec.html). + +<Aside type="caution" title="Recommendations Receiver contract"> +The example was simplified for learning purposes. For production code, use the following best practices: + + - Validate the source chain. + - Depending on your use case, analyze whether you should validate the sender address. + +Note that the receiver contract in this example inherits from the base contract [CCIPReceiver.sol](/ccip/api-reference/evm/v1.6.1/ccip-receiver), which uses the `onlyRouter` [modifier](/ccip/api-reference/evm/v1.6.1/ccip-receiver#onlyrouter) to ensure that only the router can call the `ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#ccipreceive). + +</Aside> + +</Accordion> + +## Send a cross-chain message using CCIP + +Send and verify a cross-chain message using CCIP in under 10 minutes, with your favorite development framework. + +### Hardhat 3 + +Best for a `Typescript` based scripting workflow where you deploy contracts, send a CCIP message, and verify delivery from the command line. +{/* Ideal for getting a full end-to-end CCIP flow running quickly. */} + +<br /> + +<Accordion title="Bootstrap a new Hardhat project" number={1}> + +1. Open a new terminal in a directory of your choice and run this command: + +```bash filename="Terminal" +npx hardhat --init +``` + +Create a project with the following options: + +- Hardhat Version: hardhat-3 +- Initialize project: At root of the project +- Type of project: A minimal Hardhat project +- Install the necessary dependencies: Yes + +2. Install the additional dependencies required by this tutorial: + +```bash filename="Terminal" +npm install @chainlink/contracts-ccip @chainlink/contracts viem +npm install --save-dev @nomicfoundation/hardhat-viem @nomicfoundation/hardhat-keystore +``` + +<Aside type="caution" title="WE HIGHLY RECOMMEND NOT USING PLAINTEXT PRIVATE KEYS"> + +1. It is not recommended to store your sensitive keys in plaintext in `.env` files. +2. In this tutorial we use in-built keystores for both Hardhat and Foundry for their respective projects. + +</Aside> + +3. Update `hardhat.config.ts` to use the `hardhat-viem` and `hardhat-keystore` plugins: + +```typescript filename="hardhat.config.ts" +import { configVariable, defineConfig } from "hardhat/config" +import hardhatKeystore from "@nomicfoundation/hardhat-keystore" +import hardhatViem from "@nomicfoundation/hardhat-viem" + +export default defineConfig({ + plugins: [hardhatViem, hardhatKeystore], + solidity: { + version: "0.8.24", + }, + networks: { + sepolia: { + type: "http", + url: configVariable("SEPOLIA_RPC_URL"), + accounts: [configVariable("PRIVATE_KEY")], + }, + avalancheFuji: { + type: "http", + url: configVariable("FUJI_RPC_URL"), + accounts: [configVariable("PRIVATE_KEY")], + }, + }, +}) +``` + +4. Finally, set the environment variables being referenced in the `hardhat.config.ts` file using `hardhat-keystore`. \ + If you have followed the tutorial you have already installed the required package. + You will need to run the following three commands **in succession** to configure the environment variables, Hardhat will ask you to enter the password for the keystore + for each of the variables: + +```bash filename="Terminal" +npx hardhat keystore set SEPOLIA_RPC_URL +npx hardhat keystore set FUJI_RPC_URL +npx hardhat keystore set PRIVATE_KEY +``` + +The output of `npx hardhat keystore list ` should look like this: + + <ClickToZoom + src="/images/ccip/tutorials/ccip-getting-started-evm-1.png" + alt="Hardhat keystore list command output" + /> + +</Accordion> + +<Accordion title="Set up the contracts" number={2}> + +1. Create a new directory named `contracts` for your smart contracts if it doesn't already exist. +2. Create a new file named `Sender.sol` in this directory and paste the [sender contract code](#examine-the-example-code) inside it. +3. Create a new file named `Receiver.sol` in the same directory and paste the [receiver contract code](#examine-the-example-code) inside it. +4. Run the following command to compile the contracts: + +```bash filename="Terminal" +npx hardhat build +``` + +</Accordion> + +<Accordion title="Send a cross-chain message using CCIP" number={3}> + +1. Create a new directory named `scripts` at the root of the project if it doesn't already exist. +2. Create a new file named `send-cross-chain-message.ts` in this directory and paste the following code inside it: + +```typescript filename="scripts/send-cross-chain-message.ts" +import { network } from "hardhat" +import { getContract, parseAbi, parseUnits } from "viem" + +// Avalanche Fuji configuration +const FUJI_ROUTER = "0xF694E193200268f9a4868e4Aa017A0118C9a8177" +const FUJI_LINK = "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846" + +// Ethereum Sepolia configuration +// Note that the contract on Sepolia doesn't need to have LINK to pay for CCIP fees. +const SEPOLIA_ROUTER = "0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59" +const SEPOLIA_CHAIN_SELECTOR = 16015286601757825753n + +// Connect to Avalanche Fuji +console.log("Connecting to Avalanche Fuji...") +const fujiNetwork = await network.connect("avalancheFuji") + +// Connect to Ethereum Sepolia +console.log("Connecting to Ethereum Sepolia...") +const sepoliaNetwork = await network.connect("sepolia") + +// Step 1: Deploy Sender on Fuji +console.log("\n[Step 1] Deploying Sender contract on Avalanche Fuji...") + +const sender = await fujiNetwork.viem.deployContract("Sender", [FUJI_ROUTER, FUJI_LINK]) +const fujiPublicClient = await fujiNetwork.viem.getPublicClient() + +console.log(`Sender contract has been deployed to this address on the Fuji testnet: ${sender.address}`) +console.log(`View on Avascan: https://testnet.avascan.info/blockchain/all/address/${sender.address}`) + +// Step 2: Fund Sender with LINK +console.log("\n[Step 2] Funding Sender with 1 LINK...") + +const [fujiWalletClient] = await fujiNetwork.viem.getWalletClients() +if (!fujiWalletClient) { + throw new Error("No wallet client available. Check PRIVATE_KEY + network config in hardhat.config.ts.") +} + +// We create a minimal interface for the LINK token to be able to call the transfer function. + +const linkTokenInterfaceAbi = parseAbi(["function transfer(address to, uint256 value) returns (bool)"]) + +const link = getContract({ + address: FUJI_LINK, + abi: linkTokenInterfaceAbi, + client: { public: fujiPublicClient, wallet: fujiWalletClient }, +}) + +const transferLinkToFujiContract = await link.write.transfer([sender.address, parseUnits("1", 18)]) + +console.log("LINK token transfer in progress, awaiting confirmation...") +await fujiPublicClient.waitForTransactionReceipt({ hash: transferLinkToFujiContract, confirmations: 1 }) +console.log(`Funded Sender with 1 LINK`) + +// Step 3: Deploy Receiver on Sepolia +console.log("\n[Step 3] Deploying Receiver on Ethereum Sepolia...") + +const receiver = await sepoliaNetwork.viem.deployContract("Receiver", [SEPOLIA_ROUTER]) +const sepoliaPublicClient = await sepoliaNetwork.viem.getPublicClient() + +console.log(`Receiver contract has been deployed to this address on the Sepolia testnet: ${receiver.address}`) +console.log(`View on Etherscan: https://sepolia.etherscan.io/address/${receiver.address}`) +console.log(`\n📋 Copy the receiver address since it will be needed to run the verification script 📋 \n`) + +// Step 4: Send cross-chain message +console.log("\n[Step 4] Sending cross-chain message...") + +const sendMessageTx = await sender.write.sendMessage([ + SEPOLIA_CHAIN_SELECTOR, + receiver.address, + "Hello World from Hardhat script!", +]) + +console.log("Cross-chain message sent, awaiting confirmation...") +console.log(`Message sent from source contract! ✅ \n Tx hash: ${sendMessageTx}`) +console.log(`View transaction status on CCIP Explorer: https://ccip.chain.link`) +console.log( + "Run the receiver script after 10 minutes to check if the message has been received on the destination contract." +) +``` + +This script does the following: + +- Connects to the Avalanche Fuji and Ethereum Sepolia networks. +- Deploys the sender contract on Avalanche Fuji. +- Funds the sender contract with 1 LINK. +- Deploys the receiver contract on Ethereum Sepolia. +- Sends a cross-chain message from the sender contract to the receiver contract. + +<Aside type="note" title="LINK token Interface"> + You will notice that we create a minimal interface for the `LINK` token as part of our script. Another option could + have been to generate a compiled artifact out of an empty contract that extends the `LinkTokenInterface` from the + `@chainlink/contracts` package. + <br /> + Which approach do you prefer? +</Aside> + +3. Run the following command to send the cross-chain message: -1. [Open the Sender.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/CCIP/Sender.sol) in Remix. +```bash filename="Terminal" +npx hardhat run scripts/send-cross-chain-message.ts +``` - <CodeSample src="samples/CCIP/Sender.sol" showButtonOnly={true} /> +</Accordion> -1. Compile the contract. +<Accordion title="Verify message delivery" number={4}> -1. Deploy the sender contract on _Avalanche Fuji_: +1. Wait for a few minutes for the message to be delivered to the receiver contract. + +2. Create a new file named `verify-cross-chain-message.ts` in the `scripts` directory and paste the following code inside it: + +<Callout type="note" title="Paste the Receiver contract address here"> + The second script will call the `getLastReceivedMessageDetails` function on the receiver contract to verify if the + message has been received. It will need the correct address to call the function. +</Callout> + +```typescript filename="scripts/verify-cross-chain-message.ts" +import { network } from "hardhat" + +// Paste the Receiver contract address +const RECEIVER_ADDRESS = "" + +console.log("Connecting to Ethereum Sepolia...") +const sepoliaNetwork = await network.connect("sepolia") + +console.log("Checking for received message...\n") +const receiver = await sepoliaNetwork.viem.getContractAt("Receiver", RECEIVER_ADDRESS) + +const [messageId, text] = await receiver.read.getLastReceivedMessageDetails() + +// A null hexadecimal value means no message has been received yet +const ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000" + +if (messageId === ZERO_BYTES32) { + console.log("No message received yet.") + console.log("Please wait a bit longer and try again.") + process.exit(1) +} else { + console.log(`✅ Message ID: ${messageId}`) + console.log(`Text: "${text}"`) +} +``` + +This script does the following: + +- Connects to the Ethereum Sepolia network. +- Reads the last received message details from the receiver contract. +- Checks if any message has been received. +- Prints the message ID and text of the last received message. + +3. Run the following command to verify the cross-chain message: + +```bash filename="Terminal" +npx hardhat run scripts/verify-cross-chain-message.ts +``` + +4. You should see the message ID and text of the last received message printed in the terminal. + +</Accordion> + +### Foundry + +Best for **Solidity-native** workflows that prefer a modular, powerful scripting framework. + +<br /> + +<Accordion title="Bootstrap a new Foundry project" number={1}> + +1. Open a new terminal in a directory of your choice and run this command to initialize a new Foundry project at the root: + +```bash filename="Terminal" +forge init +``` + +2. Install the required dependencies: + +```bash filename="Terminal" +forge install smartcontractkit/chainlink-ccip smartcontractkit/chainlink-evm +``` + +<Aside type="note" title="Note"> + `cast wallet import` will throw an error if an `env` variable with the same name already exists. Use `cast wallet + list` to check previously set variables. +</Aside> + +3. Use Foundry's `cast` command to create a new keystore for your `PRIVATE_KEY`: + +```bash filename="Terminal" +cast wallet import --interactive PRIVATE_KEY +``` + +And use the `cast wallet list` command to verify: + + <ClickToZoom + src="/images/ccip/tutorials/ccip-getting-started-evm-2.png" + alt="Foundry keystore list command output" + /> + +<Aside type="caution" title="Note"> + You will notice that while we pulled in our RPC URLs via encrypted keystore variables in the Hardhat project, we only + encrypt the `PRIVATE_KEY` in Foundry. This is because as of of writing, Foundry supports keystore encryption only for + Private keys, and not generic strings. +</Aside> + +4. Configure the remappings so that your `foundry.toml` file looks like this: + +```toml filename="foundry.toml" +[profile.default] +solc = "0.8.24" +src = "src" +out = "out" +libs = ["lib"] + +remappings = [ + "forge-std/=lib/forge-std/src/", + "@chainlink/contracts-ccip/contracts/=lib/chainlink-ccip/chains/evm/contracts/", + "@chainlink/contracts/=lib/chainlink-evm/contracts/", + "@openzeppelin/contracts@5.0.2/utils/introspection/=lib/forge-std/src/interfaces/" +] + +# RPC URLs will be fed to our script via Foundry's config file +[rpc_endpoints] +sepolia = "ENTER_YOUR_SEPOLIA_RPC_URL_HERE" +fuji = "ENTER_YOUR_FUJI_RPC_URL_HERE" +``` + +</Accordion> + +<Accordion title="Set up the contracts" number={2}> + +1. Create a new directory named `src` at the root of the project if it doesn't already exist. +2. Create a new file named `Sender.sol` in this directory and paste the [sender contract code](#examine-the-example-code) inside it. +3. Create a new file named `Receiver.sol` in the same directory and paste the [receiver contract code](#examine-the-example-code) inside it. +4. Run the following command to compile the contracts: + +```bash filename="Terminal" +forge build +``` + +</Accordion> + +<Accordion title="Send a cross-chain message using CCIP" number={3}> + +1. Create a new directory named `script` at the root of the project if it doesn't already exist. +2. Create a new file named `SendCrossChainMessage.s.sol` in this directory and paste the following code inside it: + +```solidity filename="script/SendCrossChainMessage.s.sol" +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.24; + +import {Script, console} from "forge-std/Script.sol"; + +import {Sender} from "../src/Sender.sol"; +import {Receiver} from "../src/Receiver.sol"; +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; + +contract SendCrossChainMessage is Script { + // Avalanche Fuji configuration + address constant FUJI_ROUTER = 0xF694E193200268f9a4868e4Aa017A0118C9a8177; + address constant FUJI_LINK = 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846; + + // Ethereum Sepolia configuration + address constant SEPOLIA_ROUTER =0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59; + uint64 constant SEPOLIA_CHAIN_SELECTOR = 16015286601757825753; + + // Configuring decimal value for LINK token + uint256 ONE_LINK = 1e18; + + function run() public { + + // Load form configs from foundry.toml + uint256 fujiFork = vm.createFork(vm.rpcUrl("fuji")); + uint256 sepoliaFork = vm.createFork(vm.rpcUrl("sepolia")); + + // Step 1: Deploy Sender on Fuji + + // Connect to Fuji Network + console.log("Connecting to Avalanche Fuji..."); + vm.selectFork(fujiFork); + vm.startBroadcast(); + + // Deploy Sender contract + console.log("\n[Step 1] Deploying Sender contract on Avalanche Fuji..."); + Sender sender = new Sender(FUJI_ROUTER, FUJI_LINK); + console.log("Sender contract has been deployed to this address on the Fuji testnet:", address(sender)); + console.log( + string.concat( + "View on Avascan: https://testnet.avascan.info/blockchain/all/address/", + vm.toString(address(sender)) + ) + ); + + // Step 2: Fund Sender with 1 LINK + console.log("\n[Step 2] Funding Sender with 1 LINK on Avalanche Fuji..."); + LinkTokenInterface(FUJI_LINK).transfer(address(sender), ONE_LINK); + vm.stopBroadcast(); + console.log("Funded Sender with 1 LINK on Fuji"); + + // Step 3: Deploy Receiver on Sepolia + + // Connect to Sepolia Network + console.log("Connecting to Ethereum Sepolia..."); + vm.selectFork(sepoliaFork); + vm.startBroadcast(); + + // Deploy Receiver contract + + console.log("\n[Step 3] Deploying Receiver contract on Ethereum Sepolia..."); + Receiver receiver = new Receiver(SEPOLIA_ROUTER); + vm.stopBroadcast(); + console.log("Receiver deployed on Sepolia at this address:", address(receiver)); + console.log( + string.concat( + "View on Etherscan: https://sepolia.etherscan.io/address/", + vm.toString(address(receiver)) + ) + ); + console.log("\n .....Copy the receiver address since it will be needed to run the verification script.....\n"); + console.log(address(receiver)); + + // Step 4: Send cross-chain message (Fuji -> Sepolia) + vm.selectFork(fujiFork); + vm.startBroadcast(); + + // Send cross-chain message + console.log("Sending cross-chain message from Fuji to Sepolia..."); + bytes32 messageId = sender.sendMessage( + SEPOLIA_CHAIN_SELECTOR, + address(receiver), + "Hello World from Foundry script!" + ); + vm.stopBroadcast(); + + console.log("The message has been sent to the CCIP router on Fuji, check for successful delivery after 5 minutes..."); + console.log("CCIP messageId:"); + console.logBytes32(messageId); + console.log("View transaction status on CCIP Explorer: https://ccip.chain.link"); + } +} +``` + +3. Run the following command to send the cross-chain message: + +```bash filename="Terminal" +forge script script/SendCrossChainMessage.s.sol:SendCrossChainMessage --broadcast --multi --account PRIVATE_KEY +``` + +<Aside type="note"> + +- The `--broadcast` flag is used to broadcast transactions to an actual network. +- You can get detailed runtime logs by using the `-vvvv` verbosity flag. - The `--multi` flag is used to send transactions to multiple chains. + +</Aside> + +</Accordion> + +<Accordion title="Verify message delivery" number={4}> + +1. Create a new file named `VerifyCrossChainMessage.s.sol` in the `script` directory and paste the following code inside it: + +```solidity filename="script/VerifyCrossChainMessage.s.sol" +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.24; + +import {Script, console} from "forge-std/Script.sol"; +import {Receiver} from "../src/Receiver.sol"; + +contract VerifyCrossChainMessage is Script { + + bytes32 constant ZERO_BYTES32 = bytes32(0); + + function run() public { + + address receiverAddress = PASTE_RECEIVER_ADDRESS_HERE; + require(receiverAddress != address(0), "Set RECEIVER_ADDRESS"); + + console.log("Connecting to Ethereum Sepolia..."); + uint256 sepoliaFork = vm.createFork(vm.rpcUrl("sepolia")); + vm.selectFork(sepoliaFork); + + console.log("Checking for received message...\n"); + Receiver receiver = Receiver(receiverAddress); + + (bytes32 messageId, string memory text) = receiver + .getLastReceivedMessageDetails(); + + if (messageId == ZERO_BYTES32) { + console.log("No message received yet."); + console.log("Please wait a bit longer and try again."); + revert("No message received yet"); + } + + console.log("Received Message ID:"); + console.logBytes32(messageId); + console.log(string.concat('Received Text: "', text, '"')); + } +} +``` + +2. Run the following command to verify the cross-chain message: + +```bash filename="Terminal" +forge script script/VerifyCrossChainMessage.s.sol:VerifyCrossChainMessage +``` + +</Accordion> + +### Remix + +Best for **Web3-native** workflows that prefer a browser-based IDE. + +<br /> + +<Accordion title="Deploy the sender contract" number={1}> + +Deploy the `Sender.sol` contract on _Avalanche Fuji_. To see a detailed explanation of this contract, read the [Code Explanation](#sender-code) section. + +1. Open the Sender.sol contract in Remix. + +2. Compile the contract. + +3. Deploy the sender contract on _Avalanche Fuji_: 1. Open MetaMask and select the _Avalanche Fuji_ network. - 1. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Avalanche Fuji_. - 1. Under the **Deploy** section, fill in the router address and the LINK token contract addresses for your specific blockchain. You can find both of these addresses on the [CCIP Directory](/ccip/directory). The LINK token contract address is also listed on the [LINK Token Contracts](/resources/link-token-contracts) page. For _Avalanche Fuji_, the router address is <CopyText text="0xF694E193200268f9a4868e4Aa017A0118C9a8177" code/> and the LINK address is <CopyText text="0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846" code/>. + 2. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Avalanche Fuji_. + 3. Under the **Deploy** section, fill in the router address and the LINK token contract addresses for your specific blockchain. You can find both of these addresses on the [CCIP Directory](/ccip/directory). The LINK token contract address is also listed on the [LINK Token Contracts](/resources/link-token-contracts) page. For _Avalanche Fuji_, the router address is <CopyText text="0xF694E193200268f9a4868e4Aa017A0118C9a8177" code/> and the LINK address is <CopyText text="0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846" code/>. <ClickToZoom src="/images/ccip/tutorials/deploy-sender-avalanche-fuji.webp" alt="Chainlink CCIP deploy sender Avalanche Fuji" /> - 1. Click the **transact** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Avalanche Fuji_. + 4. Click the **transact** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Avalanche Fuji_. - 1. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy your contract address. + 5. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy your contract address. <ClickToZoom src="/images/ccip/tutorials/deployed-sender-avalanche-fuji.webp" @@ -67,12 +682,14 @@ Deploy the `Sender.sol` contract on _Avalanche Fuji_. To see a detailed explanat style="max-width: 70%;" /> - 1. Open MetaMask and send <CopyText text="70" code/> LINK to the contract address that you copied. Your contract will pay CCIP fees in LINK. + 6. Open MetaMask and send <CopyText text="70" code/> LINK to the contract address that you copied. Your contract will pay CCIP fees in LINK. **Note:** This transaction fee is significantly higher than normal due to gas spikes on Sepolia. To run this example, you can get additional testnet LINK from [faucets.chain.link](https://faucets.chain.link) or use a supported testnet other than Sepolia. -## Deploy the receiver contract +</Accordion> + +<Accordion title="Deploy the receiver contract" number={2}> Deploy the receiver contract on _Ethereum Sepolia_. You will use this contract to receive data from the sender that you deployed on _Avalanche Fuji_. To see a detailed explanation of this contract, read the [Code Explanation](#receiver-code) section. @@ -80,22 +697,22 @@ Deploy the receiver contract on _Ethereum Sepolia_. You will use this contract t <CodeSample src="samples/CCIP/Receiver.sol" showButtonOnly={true} /> -1. Compile the contract. +2. Compile the contract. -1. Deploy the receiver contract on _Ethereum Sepolia_: +3. Deploy the receiver contract on _Ethereum Sepolia_: 1. Open MetaMask and select the _Ethereum Sepolia_ network. - 1. In Remix under the **Deploy & Run Transactions** tab, make sure the **Environment** is still set to _Injected Provider - MetaMask_. - 1. Under the **Deploy** section, fill in the router address field. For _Ethereum Sepolia_, the Router address is <CopyText text="0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59" code/>. You can find the addresses for each network on the [CCIP Directory](/ccip/directory). + 2. In Remix under the **Deploy & Run Transactions** tab, make sure the **Environment** is still set to _Injected Provider - MetaMask_. + 3. Under the **Deploy** section, fill in the router address field. For _Ethereum Sepolia_, the Router address is <CopyText text="0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59" code/>. You can find the addresses for each network on the [CCIP Directory](/ccip/directory). <ClickToZoom src="/images/ccip/tutorials/deploy-receiver-sepolia.webp" alt="Chainlink CCIP Deploy receiver Sepolia" /> - 1. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Ethereum Sepolia_. + 4. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Ethereum Sepolia_. - 1. After you confirm the transaction, the contract address appears as the second item in the **Deployed Contracts** list. Copy this contract address. + 5. After you confirm the transaction, the contract address appears as the second item in the **Deployed Contracts** list. Copy this contract address. <ClickToZoom src="/images/ccip/tutorials/deployed-receiver-sepolia.webp" @@ -105,13 +722,14 @@ Deploy the receiver contract on _Ethereum Sepolia_. You will use this contract t You now have one _sender_ contract on _Avalanche Fuji_ and one _receiver_ contract on _Ethereum Sepolia_. You sent `70` LINK to the _sender_ contract to pay the CCIP fees. Next, send data from the sender contract to the receiver contract. -## Send data +</Accordion> +<Accordion title="Send data" number={3}> Send a `Hello World!` string from your contract on _Avalanche Fuji_ to the contract you deployed on _Ethereum Sepolia_: 1. Open MetaMask and select the _Avalanche Fuji_ network. -1. In Remix under the **Deploy & Run Transactions** tab, expand the first contract in the **Deployed Contracts** section. -1. Expand the **sendMessage** function and fill in the following arguments: +2. In Remix under the **Deploy & Run Transactions** tab, expand the first contract in the **Deployed Contracts** section. +3. Expand the **sendMessage** function and fill in the following arguments: | Argument | Description | Value (_Ethereum Sepolia_) | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | @@ -125,35 +743,37 @@ Send a `Hello World!` string from your contract on _Avalanche Fuji_ to the contr style="max-width: 70%;" /> -1. Click the **transact** button to run the function. MetaMask prompts you to confirm the transaction. +4. Click the **transact** button to run the function. MetaMask prompts you to confirm the transaction. <CcipCommon callout="gasSpike" /> -1. After the transaction is successful, note the transaction hash. Here is an [example](https://testnet.snowtrace.io/tx/0x113933ec9f1b2e795a1e2f564c9d452db92d3e9a150545712687eb546916e633) of a successful transaction on _Avalanche Fuji_. +5. After the transaction is successful, note the transaction hash. Here is an [example](https://testnet.snowtrace.io/tx/0x113933ec9f1b2e795a1e2f564c9d452db92d3e9a150545712687eb546916e633) of a successful transaction on _Avalanche Fuji_. After the transaction is finalized on the source chain, it will take a few minutes for CCIP to deliver the data to _Ethereum Sepolia_ and call the `ccipReceive` function on your receiver contract. You can use the [CCIP explorer](https://ccip.chain.link/) to see the status of your CCIP transaction and then read data stored by your receiver contract. -1. Open the [CCIP explorer](https://ccip.chain.link/) and use the transaction hash that you copied to search for your cross-chain transaction. The explorer provides several details about your request. +6. Open the [CCIP explorer](https://ccip.chain.link/) and use the transaction hash that you copied to search for your cross-chain transaction. The explorer provides several details about your request. <ClickToZoom src="/images/ccip/tutorials/ccip-explorer-tx-details.webp" alt="Chainlink CCIP Explorer transaction details" /> -1. When the status of the transaction is marked with a "Success" status, the CCIP transaction and the destination transaction are complete. +7. When the status of the transaction is marked with a "Success" status, the CCIP transaction and the destination transaction are complete. <ClickToZoom src="/images/ccip/tutorials/ccip-explorer-tx-details-success.webp" alt="Chainlink CCIP Explorer transaction details success" /> -## Read data +</Accordion> + +<Accordion title="Read data" number={4}> Read data stored by the receiver contract on _Ethereum Sepolia_: 1. Open MetaMask and select the _Ethereum Sepolia_ network. -1. In Remix under the **Deploy & Run Transactions** tab, expand the receiver contract deployed on _Ethereum Sepolia_. -1. Click the **getLastReceivedMessageDetails** function button to read the stored data. In this example, it is "Hello World!". +2. In Remix under the **Deploy & Run Transactions** tab, expand the receiver contract deployed on _Ethereum Sepolia_. +3. Click the **getLastReceivedMessageDetails** function button to read the stored data. In this example, it should be "Hello World!". <ClickToZoom src="/images/ccip/tutorials/sepolia-getmessagedetails.webp" @@ -163,69 +783,4 @@ Read data stored by the receiver contract on _Ethereum Sepolia_: Congratulations! You just sent your first cross-chain data using CCIP. Next, examine the example code to learn how this contract works. -## Examine the example code - -### Sender code - -The smart contract in this tutorial is designed to interact with CCIP to send data. The contract code includes comments to clarify the various functions, events, and underlying logic. However, this section explains the key elements. You can see the full contract code below. - -<CodeSample src="samples/CCIP/Sender.sol" /> - -#### Initializing the contract - -When deploying the contract, you define the router address and the LINK contract address of the blockchain where you choose to deploy the contract. - -The router address provides functions that are required for this example: - -- The `getFee` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#getfee) to estimate the CCIP fees. -- The `ccipSend` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#ccipsend) to send CCIP messages. - -#### Sending data - -The `sendMessage` function completes several operations: - -1. Construct a CCIP-compatible message using the `EVM2AnyMessage` [struct](/ccip/api-reference/evm/v1.6.1/client#evm2anymessage): - - The `receiver` address is encoded in bytes format to accommodate non-EVM destination blockchains with distinct address formats. The encoding is achieved through [abi.encode](https://docs.soliditylang.org/en/develop/abi-spec.html). - - The `data` is encoded from a string text to bytes using [abi.encode](https://docs.soliditylang.org/en/develop/abi-spec.html). - - The `tokenAmounts` is an array. Each element comprises a [struct](/ccip/api-reference/evm/v1.6.1/client#evmtokenamount) that contains the token address and amount. In this example, the array is empty because no tokens are sent. - - The `extraArgs` specify the `gasLimit` for relaying the CCIP message to the recipient contract on the destination blockchain. In this example, the `gasLimit` is set to `200000`. - - The `feeToken` designates the token address used for CCIP fees. Here, `address(linkToken)` signifies payment in LINK. - -1. Compute the fees by invoking the router's `getFee` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#getfee). -1. Ensure that your contract balance in LINK is enough to cover the fees. -1. Grant the router contract permission to deduct the fees from the contract's LINK balance. -1. Dispatch the CCIP message to the destination chain by executing the router's `ccipSend` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#ccipsend). - -<CcipCommon callout="senderContractCallout" /> - -### Receiver code - -The smart contract in this tutorial is designed to interact with CCIP to receive data. The contract code includes comments to clarify the various functions, events, and underlying logic. However, this section explains the key elements. You can see the full contract code below. - -<CodeSample src="samples/CCIP/Receiver.sol" /> - -#### Initializing the contract - -When you deploy the contract, you define the router address. The receiver contract inherits from the [CCIPReceiver.sol](/ccip/api-reference/evm/v1.6.1/ccip-receiver) contract, which uses the router address. - -#### Receiving data - -On the destination blockchain: - -1. The CCIP Router invokes the `ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#ccipreceive). **Note**: This function is protected by the `onlyRouter` [modifier](/ccip/api-reference/evm/v1.6.1/ccip-receiver#onlyrouter), which ensures that only the router can call the receiver contract. -1. The `ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#ccipreceive) calls an internal function `_ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#_ccipreceive). The receiver contract implements this function. -1. This `_ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#_ccipreceive) expects an `Any2EVMMessage` [struct](/ccip/api-reference/evm/v1.6.1/client#any2evmmessage) that contains the following values: - - The CCIP `messageId`. - - The `sourceChainSelector`. - - The `sender` address in bytes format. The sender is a contract deployed on an EVM-compatible blockchain, so the address is decoded from bytes to an Ethereum address using the [ABI specification](https://docs.soliditylang.org/en/v0.8.20/abi-spec.html). - - The `data` is also in bytes format. A `string` is expected, so the data is decoded from bytes to a string using the [ABI specification](https://docs.soliditylang.org/en/v0.8.20/abi-spec.html). - -<Aside type="caution" title="Recommendations Receiver contract"> -The example was simplified for learning purposes. For production code, use the following best practices: - - - Validate the source chain. - - Depending on your use case, analyze whether you should validate the sender address. - -Note that the receiver contract in this example inherits from the base contract [CCIPReceiver.sol](/ccip/api-reference/evm/v1.6.1/ccip-receiver), which uses the `onlyRouter` [modifier](/ccip/api-reference/evm/v1.6.1/ccip-receiver#onlyrouter) to ensure that only the router can call the `ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#ccipreceive). - -</Aside> +</Accordion> diff --git a/src/content/ccip/index.mdx b/src/content/ccip/index.mdx index a2bc305caff..a5e616fed06 100644 --- a/src/content/ccip/index.mdx +++ b/src/content/ccip/index.mdx @@ -8,31 +8,302 @@ metadata: datePublished: "2023-08-03" lastModified: "2025-05-19" isIndex: true -whatsnext: - "Complete the Getting Started guide to learn the basics": "/ccip/getting-started" - "CCIP Directory": "/ccip/directory" - "Learn how to transfer tokens": "/ccip/tutorials/evm/transfer-tokens-from-contract" - "Learn more about CCIP architecture": "/ccip/concepts/architecture" +disableDefaultStyles: true +hideTitle: true --- -import { ClickToZoom, Aside } from "@components" -import CcipCommon from "@features/ccip/CcipCommon.astro" - -<CcipCommon callout="talkToExpert" /> - -Blockchain interoperability protocols are important for the Web3 ecosystem and traditional systems that need to interact with different blockchains. These protocols are the foundation for building blockchain abstraction layers, allowing traditional backends and dApps to interact with any blockchain network through a single middleware solution. Without a blockchain interoperability protocol, Web2 systems and dApps would need to build separate in-house implementations for each cross-chain interaction that they want to use, which is a time-consuming, resource-intensive, and complex process. - -Blockchain interoperability protocols provide the following capabilities: - -- You can transfer assets and information across multiple blockchains. -- Application developers can leverage the strengths and benefits of different chains. -- Collaboration between developers from diverse blockchain ecosystems enables the building of cross-chain applications to serve more users and provide additional features or products for them. - -The _Chainlink Cross-Chain Interoperability Protocol (CCIP)_ provides these capabilities and enables a variety of [use cases](#common-use-cases). - -## What is Chainlink CCIP? +import LayoutHero from "@components/LayoutHero/LayoutHero.astro" +import { ChainAwareTabGrid } from "@components/TabGrid/ChainAwareTabGrid.tsx" +import ResourceSection from "@components/Resource/ResourceSection.astro" +import QuickLinkCard from "@components/QuickLinkCard/QuickLinkCard.astro" +import ToolsUtilitiesGrid from "@components/ToolsUtilitiesGrid/ToolsUtilitiesGrid.astro" +import MediaSection from "@components/MediaSection/MediaSection.astro" +import CardsWrapper from "@components/Cards/CardsWrapper.astro" +import OverviewWrapper from "@components/OverviewWrapper.astro" +import ChangelogSnippet from "@components/ChangelogSnippet/ChangelogSnippet.astro" +import { + SvgEyeOptic, + SvgTransactionRepeatRecurring, + SvgWaveSignal, + SvgStartup, + SvgCrossChain, + SvgBulletList, +} from "@chainlink/blocks" +import { ClickToZoom } from "@components" + +export const toolsAndUtilities = [ + { + image: "/images/ccip-logo.svg", + imageAlt: "CCIP API icon", + label: "CCIP API", + link: "/ccip/api-reference", + description: "An API for message retrieval and lane latency information.", + }, + { + image: "/images/js-logo.svg", + imageAlt: "JavaScript SDK icon", + label: "Javascript SDK", + link: "https://github.com/smartcontractkit/ccip-javascript-sdk", + description: "Integrate CCIP functionality directly into your web applications for EVM-compatible chains.", + }, + { + image: "/images/ts-logo.svg", + imageAlt: "CLI icon", + label: "CLI", + link: "https://github.com/smartcontractkit/ccip-tools-ts", + description: "TypeScript command-line interface and library designed for interacting with deployed CCIP contracts.", + }, + { + image: "/images/hardhat-logo.svg", + imageAlt: "Hardhat icon", + label: "Hardhat Starter Kit", + link: "https://github.com/smartcontractkit/hardhat-starter-kit", + description: + "Ready-to-go boilerplate for basic CCIP use cases that help you get started building quickly with Hardhat.", + }, + { + image: "/images/foundry-logo.svg", + imageAlt: "Foundry icon", + label: "Foundry Starter Kit", + link: "https://github.com/smartcontractkit/foundry-starter-kit", + description: + "Ready-to-go boilerplate for basic CCIP use cases that help you get started building quickly with Foundry.", + }, + { + image: "/images/npm-logo.png", + imageAlt: "NPM icon", + label: "CCIP Contracts NPM", + link: "https://www.npmjs.com/package/@chainlink/contracts-ccip", + description: + "An npm package providing Solidity smart contract implementations to integrate CCIP into your EVM-based project.", + }, + { + image: "/images/direct-stacking-logo.svg", + imageAlt: "Direct Staking icon", + label: "Direct Staking", + link: "https://github.com/Aphyla/chainlink-csr", + description: + "Stake native tokens on supported L2 networks and receive liquid staked tokens directly on the same chain.", + }, +] + +export const exampleResources = [ + { + label: "Token Pool Types", + description: + "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs. Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs...", + link: "/", + type: "article", + }, + { + label: "Token Pool Types", + description: + "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs. Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs...", + link: "/", + type: "article", + }, + { + label: "Token Pool Types", + description: + "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs. Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs...", + link: "/", + type: "article", + }, +] + +export const exampleTutorials = [ + { + name: "EVM", + links: [ + { + title: "Acquire Test Tokens", + description: "Get test tokens in minutes; build and test cross-chain apps with zero friction.", + link: "/ccip/test-tokens", + }, + { + title: "Transfer Tokens", + description: "Unlock seamless token transfers from contracts; learn, code, and deploy.", + link: "/ccip/tutorials/evm/transfer-tokens-from-contract", + }, + { + title: "Transfer Tokens with Data", + description: "Go beyond basic transfers with logic-infused token movements in your EVM contracts.", + link: "/ccip/tutorials/evm/programmable-token-transfers", + }, + { + title: "Using the Token Manager", + description: "Effortlessly manage CCTs by tracking, importing and organizing tokens from your dashboard.", + link: "/ccip/tutorials/evm/token-manager", + }, + { + title: "Using the JS SDK", + description: "Integrate CCIP in your frontend or backend effortlessly with JavaScript SDK.", + link: "/ccip/ccip-javascript-sdk", + }, + { + title: "Check Message Status", + description: "Retrieve real-time status of your offchain transaction from EVM.", + link: "/ccip/tutorials/evm/offchain/get-status-offchain", + }, + { + title: "Transfer Tokens Between EOAs", + description: "Send tokens offchain from an Externally Owned Account with clear steps.", + link: "/ccip/tutorials/evm/offchain/transfer-tokens-from-eoa", + }, + { + title: "Using the CLI", + description: "Use offchain tools from CCIP to simplify your Ethereum workflows.", + link: "/ccip/tutorials/evm/offchain/ccip-tools", + }, + { + title: "Deploy and Register a CCT", + description: "Use RemixIDE to launch and configure tokens for cross-chain transfers on CCIP.", + link: "/ccip/tutorials/evm/cross-chain-tokens/register-from-eoa-remix", + }, + { + title: "Register CCT Burn & Mint EOA", + description: "Implement burn-mint cross-chain token logic with CCIP using Hardhat or Foundry.", + link: "/ccip/tutorials/evm/cross-chain-tokens/register-from-eoa-burn-mint-hardhat", + }, + { + title: "Register CCT Lock & Mint EOA", + description: "Implement a lock-mint token registration workflow with CCIP and Hardhat or Foundry.", + link: "/ccip/tutorials/evm/cross-chain-tokens/register-from-eoa-lock-mint-hardhat", + }, + { + title: "Set Token Pool Rate Limits", + description: "Update rate limiter settings for your cross-chain tokens using Hardhat or Foundry.", + link: "/ccip/tutorials/evm/cross-chain-tokens/update-rate-limiters-hardhat", + }, + ], + }, + { + name: "Solana", + links: [ + { + title: "Getting Started with Solana", + description: "Learn the basics of building on Solana blockchain.", + link: "/ccip/tutorials/svm", + }, + { + title: "Solana Token Transfers", + description: "Transfer tokens on the Solana blockchain.", + link: "/ccip/tutorials/svm/source/token-transfers", + }, + ], + }, + { + name: "Aptos", + links: [ + { + title: "Getting Started with Aptos", + description: "Start building on the Aptos blockchain.", + link: "/ccip/tutorials/aptos", + }, + ], + }, +] + +export const quickLinks = [ + { + icon: SvgEyeOptic, + label: "View Network Configs", + link: "https://docs.chain.link/ccip/directory/mainnet", + }, + { + icon: SvgTransactionRepeatRecurring, + label: "Check Transaction Status", + link: "https://ccip.chain.link/", + }, + { + icon: SvgWaveSignal, + label: "View Lane Status", + link: "https://ccip.chain.link/status", + }, + { + icon: SvgStartup, + label: "Get Testnet Tokens", + link: "https://tokenmanager.chain.link/", + }, + { + icon: SvgCrossChain, + label: "Convert Chainlink tokens", + link: "https://www.transporter.io/", + }, + { + icon: SvgBulletList, + label: "View the Changelog", + link: "https://dev.chain.link/changelog?product=CCIP", + }, +] + +export const cardLinks = [ + { + title: "Deploy/enable a token across multiple chains", + description: + "Create a new Cross-Chain-Token or enable an established one that can be launched on 50+ chains, providing unparalleled interoperability and reach.", + links: [ + { + icon: "token", + href: "https://example.com", + label: "View Token Manager", + }, + { + icon: "remix", + href: "https://example.com", + label: "Open in Remix", + }, + ], + }, + { + title: "Bridge a token", + description: + "Securely transfer tokens - including ETH, USDC, LINK - and messages between different blockchain networks.", + links: [ + { + icon: "token", + href: "https://example.com", + label: "View Token Manager", + }, + { + icon: "remix", + href: "https://example.com", + label: "Open in Remix", + }, + ], + }, + { + title: "Send a token with data", + description: + "Build token transfers that do more than move value, letting you embed business logic directly into your cross-chain workflows.", + links: [ + { + icon: "remix", + href: "https://example.com", + label: "Open in Remix", + }, + ], + }, +] + +<LayoutHero + title="Build with CCIP" + description="CCIP makes it simple to move data, messages, and tokens across blockchains. Connect smart contracts on different networks as if they were one system, whether transferring stablecoins, powering cross-chain apps, or running multi-chain DeFi." + buttons={[ + { label: "Get the SDK", link: "#" }, + { label: "API Doc", link: "#" }, + ]} + image="/images/ccip/ccip-hero.png" +/> -Chainlink CCIP is a blockchain interoperability protocol that enables developers to build secure applications that can transfer tokens, messages (data), or both tokens and messages across chains. +<OverviewWrapper> + <CardsWrapper links={cardLinks} /> + <ChainAwareTabGrid header="Tutorials" client:visible tabs={exampleTutorials} /> + <QuickLinkCard links={quickLinks} /> + <ToolsUtilitiesGrid links={toolsAndUtilities} /> + <ResourceSection title="Resources" resources={exampleResources} /> + <ChangelogSnippet query="ccip" /> +</OverviewWrapper> Given the [inherent risks of cross-chain interoperability](/resources/bridge-risks), CCIP features [defense-in-depth security](https://blog.chain.link/five-levels-cross-chain-security/#level_5__defense-in-depth) and is powered by Chainlink's industry-standard oracle networks which have a proven track record of securing tens of billions of dollars and enabling over $14 trillion in onchain transaction value. @@ -44,58 +315,9 @@ CCIP's robust security framework is built upon several core components: - **High-Quality, Sybil-Resistant Node Operators**: The system is secured by the same globally distributed, security-reviewed, public node operators that secure other Chainlink services, validate leading blockchain networks, and operate traditional Web2 infrastructure. Each independent CCIP node is run by a distinct organization with extensive DevOps expertise and rigorous private key management security practices. <ClickToZoom - src="/images/ccip/ccip-hl-v1.7.png" + src="/images/ccip/ccip-hl-v1.7.jpg" alt="Chainlink CCIP Architecture" style="display: block; margin: 2rem auto; max-height: 60vh; width: auto;" /> -To understand how Chainlink CCIP works, refer to the [architecture](/ccip/concepts/architecture) section. If you are new to using Chainlink CCIP, read these guides before you deploy any contracts that use CCIP. - -## Chainlink CCIP core capabilities - -Chainlink CCIP supports three main capabilities: - -### Arbitrary Messaging - -The ability to send arbitrary data (encoded as bytes) to a receiving smart contract on a different blockchain. The developer is free to encode any data they wish to send. - -Typically, developers use arbitrary messaging to trigger an informed action on the receiving smart contract, such as rebalancing an index, minting a specific NFT, or calling an arbitrary function with the sent data as custom parameters. Developers can encode multiple instructions in a single message, enabling them to orchestrate complex, multi-step, multi-chain tasks. - -### Token Transfer - -The ability to transfer tokens to an account on a different blockchain. This capability enables the seamless movement of assets across chains. - -### Programmable Token Transfer - -The ability to simultaneously transfer tokens and arbitrary data (encoded as bytes) within a single transaction. This mechanism allows users to transfer tokens and send instructions on what to do with those tokens. - -For example, a user could transfer tokens to a lending protocol with instructions to leverage those tokens as collateral for a loan, borrowing another asset to be sent back to the user. - -### Receiving account types - -With CCIP, you send transactions with data (arbitrary messaging), tokens, or both data and tokens (programmable token transfer). The receiver of a CCIP transaction varies by blockchain family: - -| CCIP capability | What is sent | Receiving account types | -| --------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -| Arbitrary Messaging | Data | EVM: Smart contracts only<br />SVM: Programs only<br />Aptos: Modules only | -| Token Transfer | Tokens | EVM: Smart contracts and EOAs<br />SVM: User wallets or program-controlled PDAs<br />Aptos: User accounts or modules deployed to resource accounts | -| Programmable Token Transfer | Data and tokens | EVM: Smart contracts only<br />SVM: Data to programs, tokens to program-controlled PDAs<br />Aptos: Modules deployed to resource accounts | - -**Note**: On EVM chains, EOAs cannot receive messages. On Solana (SVM), programs work with Program Derived Addresses (PDAs) to manage token reception. - -## Common use cases - -Chainlink CCIP enables a variety of use cases: - -- **Cross-chain lending:** Chainlink CCIP enables users to lend and borrow a wide range of crypto assets across multiple DeFi platforms running on independent chains. -- **Low-cost transaction computation:** Chainlink CCIP can help offload the computation of transaction data on cost-optimized chains. -- **Optimizing cross-chain yield:** Users can leverage Chainlink CCIP to move collateral to new DeFi protocols to maximize yield across chains. -- **Creating new kinds of dApps:** Chainlink CCIP enables users to take advantage of network effects on certain chains while harnessing compute and storage capabilities of other chains. - -Read [What Are Cross-Chain Smart Contracts](https://chain.link/education-hub/cross-chain-smart-contracts) to learn about cross-chain smart contracts and examples of use cases they enable. - -## CCIP Directory - -See the [CCIP Directory](/ccip/directory) page for a list of supported networks, tokens, and contract addresses. - -To learn about tokens, token pools, and the token onboarding process, see the [CCIP Architecture](/ccip/concepts/cross-chain-token/evm/token-pools) page. +To understand how Chainlink CCIP works, refer to the [architecture](/ccip/concepts/architecture/overview) section. If you are new to using Chainlink CCIP, read these guides before you deploy any contracts that use CCIP. diff --git a/src/content/ccip/llms-full.txt b/src/content/ccip/llms-full.txt index 5340e42d537..dad081bb007 100644 --- a/src/content/ccip/llms-full.txt +++ b/src/content/ccip/llms-full.txt @@ -22,16 +22,16 @@ The *Chainlink Cross-Chain Interoperability Protocol (CCIP)* provides these capa Chainlink CCIP is a blockchain interoperability protocol that enables developers to build secure applications that can transfer tokens, messages (data), or both tokens and messages across chains. -Given the [inherent risks of cross-chain interoperability](/resources/bridge-risks), CCIP features [defense-in-depth security](https://blog.chain.link/five-levels-cross-chain-security/#level_5__defense-in-depth) and is powered by Chainlink's industry-standard oracle networks which have a proven track record of securing tens of billions of dollars and enabling over $14 trillion in onchain transaction value. +Given the [inherent risks of cross-chain interoperability](/resources/bridge-risks), CCIP features defense-in-depth security and is powered by Chainlink's industry-standard oracle networks which have a proven track record of securing tens of billions of dollars and enabling over $14 trillion in onchain transaction value. CCIP's robust security framework is built upon several core components: -- **Proven Decentralized Architecture**: CCIP leverages the same highly reliable infrastructure as Chainlink Data Feeds, which has enabled trillions in transaction value across hundreds of DeFi applications. Cross-chain transactions are validated by multiple decentralized oracle networks (DONs). +- **Proven Decentralized Architecture**: CCIP leverages the same highly reliable infrastructure as Chainlink Data Feeds, which has enabled trillions in transaction value across hundreds of DeFi applications. Cross-chain transactions leverage multiple decentralized oracle networks (DONs). - **Rate Limiting**: To mitigate risk, CCIP includes a rate limiting feature. This allows owners to establish and configure policies for Cross-Chain Tokens, which are then enforced on both the source and destination chains. - **Timelocked Upgrades**: All on-chain, security-critical configuration changes and core infrastructure upgrades must pass through a Role-based Access Control Timelock contract. This process provides a review period during which CCIP node operators can veto the upgrade, or, in time-sensitive situations, explicitly approve it. - **High-Quality, Sybil-Resistant Node Operators**: The system is secured by the same globally distributed, security-reviewed, public node operators that secure other Chainlink services, validate leading blockchain networks, and operate traditional Web2 infrastructure. Each independent CCIP node is run by a distinct organization with extensive DevOps expertise and rigorous private key management security practices. -To understand how Chainlink CCIP works, refer to the [architecture](/ccip/concepts/architecture) section. If you are new to using Chainlink CCIP, read these guides before you deploy any contracts that use CCIP. +To understand how Chainlink CCIP works, refer to the [architecture](/ccip/concepts/architecture/overview) section. If you are new to using Chainlink CCIP, read these guides before you deploy any contracts that use CCIP. ## Chainlink CCIP core capabilities @@ -84,192 +84,519 @@ To learn about tokens, token pools, and the token onboarding process, see the [C --- -# Getting Started (EVM) +# Get Started with CCIP (EVM) Source: https://docs.chain.link/ccip/getting-started/evm -Last Updated: 2025-05-19 +Last Updated: 2025-12-25 -<Aside type="note" title="Talk to a CCIP expert"> - If you require technical advice or wish to consult on your project's implementation, please contact a CCIP expert. Our - dedicated team is ready to support your projects and ensure their success. For expert guidance, visit the [Chainlink - CCIP Contact form](https://chain.link/ccip-contact). -</Aside> +**Build and run a secure cross-chain messaging workflow between two EVM chains using Chainlink CCIP.** -A simple use case for Chainlink CCIP is sending data between smart contracts on different blockchains. This guide shows you how to deploy a CCIP sender contract and a CCIP receiver contract to two different blockchains and send data from the sender contract to the receiver contract. You pay the CCIP fees using LINK. +In this guide, you will: -Fees can also be paid in alternative assets, which currently include the native gas tokens of the source blockchain and their ERC20 wrapped version. For example, you can pay ETH or WETH when you send transactions to the CCIP router on Ethereum and AVAX or WAVAX when you send transactions to the CCIP router on Avalanche. +1. Deploy a sender on a source chain +2. Deploy a receiver on a destination chain +3. Send and verify a cross-chain message ## Before you begin -- If you are new to smart contract development, learn how to [Deploy Your First Smart Contract](/quickstarts/deploy-your-first-contract) so you are familiar with the tools that are necessary for this guide: - - The [Solidity](https://soliditylang.org/) programming language - - The [MetaMask](https://metamask.io) wallet - - The [Remix](https://remix.ethereum.org/) development environment -- Acquire testnet funds. This guide requires testnet AVAX and LINK on *Avalanche Fuji*. It also requires testnet ETH on *Ethereum Sepolia*. If you need to use different networks, you can find more faucets on the [LINK Token Contracts](/resources/link-token-contracts) page. - - Go to [faucets.chain.link](https://faucets.chain.link/) to get your testnet tokens. -- Learn how to [Fund your contract with LINK](/resources/fund-your-contract). +<Aside type="note" title="Please note"> + We use the same two smart contracts throughout the tutorial. You can check them out in the [Examine the example + code](#examine-the-example-code) section. +</Aside> -## Deploy the sender contract +You will need: -Deploy the `Sender.sol` contract on *Avalanche Fuji*. To see a detailed explanation of this contract, read the [Code Explanation](#sender-code) section. +- Basic [Solidity](https://soliditylang.org/) and [smart contract deployment](/quickstarts/deploy-your-first-contract) experience -1. [Open the Sender.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/CCIP/Sender.sol) in Remix. +- One [wallet](https://metamask.io/) funded on two CCIP-supported EVM testnets: [Avalanche Fuji and Ethereum Sepolia](/ccip/directory/testnet). You will need some native tokens and `LINK` on both networks. -2. Compile the contract. +- Choose one of the following development environments: + - **[Hardhat 3](https://hardhat.org/docs/getting-started)** + - **[Foundry](https://book.getfoundry.sh/)** + - **[Remix](https://remix-ide.readthedocs.io/en/latest/)** -3. Deploy the sender contract on *Avalanche Fuji*: - 1. Open MetaMask and select the *Avalanche Fuji* network. +## Examine the example code - 2. In Remix under the **Deploy & Run Transactions** tab, select *Injected Provider - MetaMask* in the **Environment** list. Remix will use the MetaMask wallet to communicate with *Avalanche Fuji*. +This section goes through the code for the `sender` and `receiver` contracts +needed to complete the tutorial. +We will use the same contracts for all three development environments. - 3. Under the **Deploy** section, fill in the router address and the LINK token contract addresses for your specific blockchain. You can find both of these addresses on the [CCIP Directory](/ccip/directory). The LINK token contract address is also listed on the [LINK Token Contracts](/resources/link-token-contracts) page. For *Avalanche Fuji*, the router address is 0xF694E193200268f9a4868e4Aa017A0118C9a8177 and the LINK address is 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846. +<Accordion title="Sender code" number={1}> + The smart contract in this tutorial is designed to interact with CCIP to send data. The contract code includes comments to clarify the various functions, events, and underlying logic. However, this section explains the key elements. You can see the full contract code below. - 4. Click the **transact** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to *Avalanche Fuji*. + <CodeSample src="samples/CCIP/Sender.sol" filename="Sender.sol" /> - 5. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy your contract address. + #### Initializing the contract - 6. Open MetaMask and send 70 LINK to the contract address that you copied. Your contract will pay CCIP fees in LINK. + When deploying the contract, you define the router address and the LINK contract address of the blockchain where you choose to deploy the contract. - **Note:** This transaction fee is significantly higher than normal due to gas spikes on Sepolia. To run this example, you can get additional testnet LINK - from [faucets.chain.link](https://faucets.chain.link) or use a supported testnet other than Sepolia. + The router address provides functions that are required for this example: -## Deploy the receiver contract + - The `getFee` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#getfee) to estimate the CCIP fees. + - The `ccipSend` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#ccipsend) to send CCIP messages. -Deploy the receiver contract on *Ethereum Sepolia*. You will use this contract to receive data from the sender that you deployed on *Avalanche Fuji*. To see a detailed explanation of this contract, read the [Code Explanation](#receiver-code) section. + #### Sending data -1. [Open the Receiver.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/CCIP/Receiver.sol) contract in Remix. + The `sendMessage` function completes several operations: -2. Compile the contract. + 1. Construct a CCIP-compatible message using the `EVM2AnyMessage` [struct](/ccip/api-reference/evm/v1.6.1/client#evm2anymessage): + - The `receiver` address is encoded in bytes format to accommodate non-EVM destination blockchains with distinct address formats. The encoding is achieved through [abi.encode](https://docs.soliditylang.org/en/develop/abi-spec.html). + - The `data` is encoded from a string text to bytes using [abi.encode](https://docs.soliditylang.org/en/develop/abi-spec.html). + - The `tokenAmounts` is an array. Each element comprises a [struct](/ccip/api-reference/evm/v1.6.1/client#evmtokenamount) that contains the token address and amount. In this example, the array is empty because no tokens are sent. + - The `extraArgs` specify the `gasLimit` for relaying the CCIP message to the recipient contract on the destination blockchain. In this example, the `gasLimit` is set to `200000`. + - The `feeToken` designates the token address used for CCIP fees. Here, `address(linkToken)` signifies payment in LINK. -3. Deploy the receiver contract on *Ethereum Sepolia*: - 1. Open MetaMask and select the *Ethereum Sepolia* network. + 2. Compute the fees by invoking the router's `getFee` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#getfee). - 2. In Remix under the **Deploy & Run Transactions** tab, make sure the **Environment** is still set to *Injected Provider - MetaMask*. + 3. Ensure that your contract balance in LINK is enough to cover the fees. - 3. Under the **Deploy** section, fill in the router address field. For *Ethereum Sepolia*, the Router address is 0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59. You can find the addresses for each network on the [CCIP Directory](/ccip/directory). + 4. Grant the router contract permission to deduct the fees from the contract's LINK balance. - 4. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to *Ethereum Sepolia*. + 5. Dispatch the CCIP message to the destination chain by executing the router's `ccipSend` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#ccipsend). - 5. After you confirm the transaction, the contract address appears as the second item in the **Deployed Contracts** list. Copy this contract address. + <Aside type="caution" title="Best Practices"> + This example is simplified for educational purposes. For production code, please adhere to the following best practices: -You now have one *sender* contract on *Avalanche Fuji* and one *receiver* contract on *Ethereum Sepolia*. You sent `70` LINK to the *sender* contract to pay the CCIP fees. Next, send data from the sender contract to the receiver contract. + - **Do Not Hardcode `extraArgs`**: In this example, `extraArgs` are hardcoded within the contract for simplicity. It is recommended to make `extraArgs` mutable. For instance, you can construct `extraArgs` off-chain and pass them into your function calls, or store them in a storage variable that can be updated as needed. This approach ensures that `extraArgs` remain backward compatible with future CCIP upgrades. Refer to the [Best Practices](/ccip/concepts/best-practices/evm) guide for more information. -## Send data + - **Validate the Destination Chain**: Always ensure that the destination chain is valid and supported before sending messages. -Send a `Hello World!` string from your contract on *Avalanche Fuji* to the contract you deployed on *Ethereum Sepolia*: + - **Understand `allowOutOfOrderExecution` Usage**: This example sets `allowOutOfOrderExecution` to `true` (see [GenericExtraArgsV2](/ccip/api-reference/evm/v1.6.1/client#genericextraargsv2)). Read the [Best Practices: Setting `allowOutOfOrderExecution`](/ccip/concepts/best-practices/evm#setting-allowoutoforderexecution) to learn more about this parameter. -1. Open MetaMask and select the *Avalanche Fuji* network. + - **Understand CCIP Service Limits**: Review the [CCIP Service Limits](/ccip/service-limits) for constraints on message data size, execution gas, and the number of tokens per transaction. If your requirements exceed these limits, you may need to [contact the Chainlink Labs Team](https://chain.link/ccip-contact). -2. In Remix under the **Deploy & Run Transactions** tab, expand the first contract in the **Deployed Contracts** section. + Following these best practices ensures that your contract is robust, future-proof, and compliant with CCIP standards. + </Aside> +</Accordion> -3. Expand the **sendMessage** function and fill in the following arguments: +## Send a cross-chain message using CCIP - | Argument | Description | Value (*Ethereum Sepolia*) | - | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | - | destinationChainSelector | CCIP Chain identifier of the target blockchain. You can find each network's chain selector on the [CCIP Directory](/ccip/directory) | 16015286601757825753 | - | receiver | The destination smart contract address | Your deployed contract address | - | text | Any `string` | Hello World! | +Send and verify a cross-chain message using CCIP in under 10 minutes, with your favorite development framework. -4. Click the **transact** button to run the function. MetaMask prompts you to confirm the transaction. +### Hardhat 3 -<Aside type="note" title="Gas price spikes"> - Under normal circumstances, transactions on the Ethereum Sepolia network require significantly fewer tokens to pay for gas. However, during exceptional periods of high gas price spikes, your transactions may fail if not sufficiently funded. In such cases, you may need to fund your contract with additional tokens. We recommend paying for your CCIP transactions in **LINK** tokens (rather than native tokens) as you can obtain extra LINK testnet tokens from [faucets.chain.link](https://faucets.chain.link/). If you encounter a transaction failure due to these gas price spikes, please add additional LINK tokens to your contract and try again. - Alternatively, you can use a supported testnet other than Sepolia. -</Aside> +Best for a `Typescript` based scripting workflow where you deploy contracts, send a CCIP message, and verify delivery from the command line. -1. After the transaction is successful, note the transaction hash. Here is an [example](https://testnet.snowtrace.io/tx/0x113933ec9f1b2e795a1e2f564c9d452db92d3e9a150545712687eb546916e633) of a successful transaction on *Avalanche Fuji*. +{/* Ideal for getting a full end-to-end CCIP flow running quickly. */} -After the transaction is finalized on the source chain, it will take a few minutes for CCIP to deliver the data to *Ethereum Sepolia* and call the `ccipReceive` function on your receiver contract. You can use the [CCIP explorer](https://ccip.chain.link/) to see the status of your CCIP transaction and then read data stored by your receiver contract. +<Accordion title="Bootstrap a new Hardhat project" number={1}> + 1. Open a new terminal in a directory of your choice and run this command: -1. Open the [CCIP explorer](https://ccip.chain.link/) and use the transaction hash that you copied to search for your cross-chain transaction. The explorer provides several details about your request. + ```bash filename="Terminal" + npx hardhat --init + ``` -2. When the status of the transaction is marked with a "Success" status, the CCIP transaction and the destination transaction are complete. + Create a project with the following options: -## Read data + - Hardhat Version: hardhat-3 + - Initialize project: At root of the project + - Type of project: A minimal Hardhat project + - Install the necessary dependencies: Yes -Read data stored by the receiver contract on *Ethereum Sepolia*: + 2. Install the additional dependencies required by this tutorial: -1. Open MetaMask and select the *Ethereum Sepolia* network. -2. In Remix under the **Deploy & Run Transactions** tab, expand the receiver contract deployed on *Ethereum Sepolia*. -3. Click the **getLastReceivedMessageDetails** function button to read the stored data. In this example, it is "Hello World!". + ```bash filename="Terminal" + npm install @chainlink/contracts-ccip @chainlink/contracts viem + npm install --save-dev @nomicfoundation/hardhat-viem @nomicfoundation/hardhat-keystore + ``` -Congratulations! You just sent your first cross-chain data using CCIP. Next, examine the example code to learn how this contract works. + <Aside type="caution" title="WE HIGHLY RECOMMEND NOT USING PLAINTEXT PRIVATE KEYS"> + 1. It is not recommended to store your sensitive keys in plaintext in `.env` files. + 2. In this tutorial we use in-built keystores for both Hardhat and Foundry for their respective projects. + </Aside> -## Examine the example code + 3. Update `hardhat.config.ts` to use the `hardhat-viem` and `hardhat-keystore` plugins: -### Sender code + ```typescript filename="hardhat.config.ts" + import { configVariable, defineConfig } from "hardhat/config" + import hardhatKeystore from "@nomicfoundation/hardhat-keystore" + import hardhatViem from "@nomicfoundation/hardhat-viem" -The smart contract in this tutorial is designed to interact with CCIP to send data. The contract code includes comments to clarify the various functions, events, and underlying logic. However, this section explains the key elements. You can see the full contract code below. + export default defineConfig({ + plugins: [hardhatViem, hardhatKeystore], + solidity: { + version: "0.8.24", + }, + networks: { + sepolia: { + type: "http", + url: configVariable("SEPOLIA_RPC_URL"), + accounts: [configVariable("PRIVATE_KEY")], + }, + avalancheFuji: { + type: "http", + url: configVariable("FUJI_RPC_URL"), + accounts: [configVariable("PRIVATE_KEY")], + }, + }, + }) + ``` -#### Initializing the contract + 4. Finally, set the environment variables being referenced in the `hardhat.config.ts` file using `hardhat-keystore`. \ + If you have followed the tutorial you have already installed the required package. + You will need to run the following three commands **in succession** to configure the environment variables, Hardhat will ask you to enter the password for the keystore + for each of the variables: -When deploying the contract, you define the router address and the LINK contract address of the blockchain where you choose to deploy the contract. + ```bash filename="Terminal" + npx hardhat keystore set SEPOLIA_RPC_URL + npx hardhat keystore set FUJI_RPC_URL + npx hardhat keystore set PRIVATE_KEY + ``` -The router address provides functions that are required for this example: + The output of `npx hardhat keystore list ` should look like this: -- The `getFee` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#getfee) to estimate the CCIP fees. -- The `ccipSend` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#ccipsend) to send CCIP messages. + <ClickToZoom src="/images/ccip/tutorials/ccip-getting-started-evm-1.png" alt="Hardhat keystore list command output" /> +</Accordion> -#### Sending data +<Accordion title="Send a cross-chain message using CCIP" number={3}> + 1. Create a new directory named `scripts` at the root of the project if it doesn't already exist. + 2. Create a new file named `send-cross-chain-message.ts` in this directory and paste the following code inside it: -The `sendMessage` function completes several operations: + ```typescript filename="scripts/send-cross-chain-message.ts" + import { network } from "hardhat" + import { getContract, parseAbi, parseUnits } from "viem" -1. Construct a CCIP-compatible message using the `EVM2AnyMessage` [struct](/ccip/api-reference/evm/v1.6.1/client#evm2anymessage): - - The `receiver` address is encoded in bytes format to accommodate non-EVM destination blockchains with distinct address formats. The encoding is achieved through [abi.encode](https://docs.soliditylang.org/en/develop/abi-spec.html). - - The `data` is encoded from a string text to bytes using [abi.encode](https://docs.soliditylang.org/en/develop/abi-spec.html). - - The `tokenAmounts` is an array. Each element comprises a [struct](/ccip/api-reference/evm/v1.6.1/client#evmtokenamount) that contains the token address and amount. In this example, the array is empty because no tokens are sent. - - The `extraArgs` specify the `gasLimit` for relaying the CCIP message to the recipient contract on the destination blockchain. In this example, the `gasLimit` is set to `200000`. - - The `feeToken` designates the token address used for CCIP fees. Here, `address(linkToken)` signifies payment in LINK. + // Avalanche Fuji configuration + const FUJI_ROUTER = "0xF694E193200268f9a4868e4Aa017A0118C9a8177" + const FUJI_LINK = "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846" -2. Compute the fees by invoking the router's `getFee` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#getfee). + // Ethereum Sepolia configuration + // Note that the contract on Sepolia doesn't need to have LINK to pay for CCIP fees. + const SEPOLIA_ROUTER = "0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59" + const SEPOLIA_CHAIN_SELECTOR = 16015286601757825753n -3. Ensure that your contract balance in LINK is enough to cover the fees. + // Connect to Avalanche Fuji + console.log("Connecting to Avalanche Fuji...") + const fujiNetwork = await network.connect("avalancheFuji") -4. Grant the router contract permission to deduct the fees from the contract's LINK balance. + // Connect to Ethereum Sepolia + console.log("Connecting to Ethereum Sepolia...") + const sepoliaNetwork = await network.connect("sepolia") -5. Dispatch the CCIP message to the destination chain by executing the router's `ccipSend` [function](/ccip/api-reference/evm/v1.6.1/i-router-client#ccipsend). + // Step 1: Deploy Sender on Fuji + console.log("\n[Step 1] Deploying Sender contract on Avalanche Fuji...") -<Aside type="caution" title="Best Practices"> - This example is simplified for educational purposes. For production code, please adhere to the following best practices: + const sender = await fujiNetwork.viem.deployContract("Sender", [FUJI_ROUTER, FUJI_LINK]) + const fujiPublicClient = await fujiNetwork.viem.getPublicClient() - - **Do Not Hardcode `extraArgs`**: In this example, `extraArgs` are hardcoded within the contract for simplicity. It is recommended to make `extraArgs` mutable. For instance, you can construct `extraArgs` off-chain and pass them into your function calls, or store them in a storage variable that can be updated as needed. This approach ensures that `extraArgs` remain backward compatible with future CCIP upgrades. Refer to the [Best Practices](/ccip/concepts/best-practices/evm) guide for more information. + console.log(`Sender contract has been deployed to this address on the Fuji testnet: ${sender.address}`) + console.log(`View on Avascan: https://testnet.avascan.info/blockchain/all/address/${sender.address}`) - - **Validate the Destination Chain**: Always ensure that the destination chain is valid and supported before sending messages. + // Step 2: Fund Sender with LINK + console.log("\n[Step 2] Funding Sender with 1 LINK...") - - **Understand `allowOutOfOrderExecution` Usage**: This example sets `allowOutOfOrderExecution` to `true` (see [GenericExtraArgsV2](/ccip/api-reference/evm/v1.6.1/client#genericextraargsv2)). Read the [Best Practices: Setting `allowOutOfOrderExecution`](/ccip/concepts/best-practices/evm#setting-allowoutoforderexecution) to learn more about this parameter. + const [fujiWalletClient] = await fujiNetwork.viem.getWalletClients() + if (!fujiWalletClient) { + throw new Error("No wallet client available. Check PRIVATE_KEY + network config in hardhat.config.ts.") + } - - **Understand CCIP Service Limits**: Review the [CCIP Service Limits](/ccip/service-limits) for constraints on message data size, execution gas, and the number of tokens per transaction. If your requirements exceed these limits, you may need to [contact the Chainlink Labs Team](https://chain.link/ccip-contact). + // We create a minimal interface for the LINK token to be able to call the transfer function. - Following these best practices ensures that your contract is robust, future-proof, and compliant with CCIP standards. -</Aside> + const linkTokenInterfaceAbi = parseAbi(["function transfer(address to, uint256 value) returns (bool)"]) -### Receiver code + const link = getContract({ + address: FUJI_LINK, + abi: linkTokenInterfaceAbi, + client: { public: fujiPublicClient, wallet: fujiWalletClient }, + }) -The smart contract in this tutorial is designed to interact with CCIP to receive data. The contract code includes comments to clarify the various functions, events, and underlying logic. However, this section explains the key elements. You can see the full contract code below. + const transferLinkToFujiContract = await link.write.transfer([sender.address, parseUnits("1", 18)]) -#### Initializing the contract + console.log("LINK token transfer in progress, awaiting confirmation...") + await fujiPublicClient.waitForTransactionReceipt({ hash: transferLinkToFujiContract, confirmations: 1 }) + console.log(`Funded Sender with 1 LINK`) -When you deploy the contract, you define the router address. The receiver contract inherits from the [CCIPReceiver.sol](/ccip/api-reference/evm/v1.6.1/ccip-receiver) contract, which uses the router address. + // Step 3: Deploy Receiver on Sepolia + console.log("\n[Step 3] Deploying Receiver on Ethereum Sepolia...") -#### Receiving data + const receiver = await sepoliaNetwork.viem.deployContract("Receiver", [SEPOLIA_ROUTER]) + const sepoliaPublicClient = await sepoliaNetwork.viem.getPublicClient() -On the destination blockchain: + console.log(`Receiver contract has been deployed to this address on the Sepolia testnet: ${receiver.address}`) + console.log(`View on Etherscan: https://sepolia.etherscan.io/address/${receiver.address}`) + console.log(`\n📋 Copy the receiver address since it will be needed to run the verification script 📋 \n`) -1. The CCIP Router invokes the `ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#ccipreceive). **Note**: This function is protected by the `onlyRouter` [modifier](/ccip/api-reference/evm/v1.6.1/ccip-receiver#onlyrouter), which ensures that only the router can call the receiver contract. -2. The `ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#ccipreceive) calls an internal function `_ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#_ccipreceive). The receiver contract implements this function. -3. This `_ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#_ccipreceive) expects an `Any2EVMMessage` [struct](/ccip/api-reference/evm/v1.6.1/client#any2evmmessage) that contains the following values: - - The CCIP `messageId`. - - The `sourceChainSelector`. - - The `sender` address in bytes format. The sender is a contract deployed on an EVM-compatible blockchain, so the address is decoded from bytes to an Ethereum address using the [ABI specification](https://docs.soliditylang.org/en/v0.8.20/abi-spec.html). - - The `data` is also in bytes format. A `string` is expected, so the data is decoded from bytes to a string using the [ABI specification](https://docs.soliditylang.org/en/v0.8.20/abi-spec.html). + // Step 4: Send cross-chain message + console.log("\n[Step 4] Sending cross-chain message...") -<Aside type="caution" title="Recommendations Receiver contract"> - The example was simplified for learning purposes. For production code, use the following best practices: + const sendMessageTx = await sender.write.sendMessage([ + SEPOLIA_CHAIN_SELECTOR, + receiver.address, + "Hello World from Hardhat script!", + ]) - - Validate the source chain. - - Depending on your use case, analyze whether you should validate the sender address. + console.log("Cross-chain message sent, awaiting confirmation...") + console.log(`Message sent from source contract! ✅ \n Tx hash: ${sendMessageTx}`) + console.log(`View transaction status on CCIP Explorer: https://ccip.chain.link`) + console.log( + "Run the receiver script after 10 minutes to check if the message has been received on the destination contract." + ) + ``` - Note that the receiver contract in this example inherits from the base contract [CCIPReceiver.sol](/ccip/api-reference/evm/v1.6.1/ccip-receiver), which uses the `onlyRouter` [modifier](/ccip/api-reference/evm/v1.6.1/ccip-receiver#onlyrouter) to ensure that only the router can call the `ccipReceive` [function](/ccip/api-reference/evm/v1.6.1/ccip-receiver#ccipreceive). -</Aside> + This script does the following: + + - Connects to the Avalanche Fuji and Ethereum Sepolia networks. + - Deploys the sender contract on Avalanche Fuji. + - Funds the sender contract with 1 LINK. + - Deploys the receiver contract on Ethereum Sepolia. + - Sends a cross-chain message from the sender contract to the receiver contract. + + <Aside type="note" title="LINK token Interface"> + You will notice that we create a minimal interface for the `LINK` token as part of our script. Another option could + have been to generate a compiled artifact out of an empty contract that extends the `LinkTokenInterface` from the + `@chainlink/contracts` package. + + <br /> + + Which approach do you prefer? + </Aside> + + 3. Run the following command to send the cross-chain message: + + ```bash filename="Terminal" + npx hardhat run scripts/send-cross-chain-message.ts + ``` +</Accordion> + +### Foundry + +Best for **Solidity-native** workflows that prefer a modular, powerful scripting framework. + +<Accordion title="Bootstrap a new Foundry project" number={1}> + 1. Open a new terminal in a directory of your choice and run this command to initialize a new Foundry project at the root: + + ```bash filename="Terminal" + forge init + ``` + + 2. Install the required dependencies: + + ```bash filename="Terminal" + forge install smartcontractkit/chainlink-ccip smartcontractkit/chainlink-evm + ``` + + <Aside type="note" title="Note"> + `cast wallet import` will throw an error if an `env` variable with the same name already exists. Use `cast wallet + list` to check previously set variables. + </Aside> + + 3. Use Foundry's `cast` command to create a new keystore for your `PRIVATE_KEY`: + + ```bash filename="Terminal" + cast wallet import --interactive PRIVATE_KEY + ``` + + And use the `cast wallet list` command to verify: + + <ClickToZoom src="/images/ccip/tutorials/ccip-getting-started-evm-2.png" alt="Foundry keystore list command output" /> + + <Aside type="caution" title="Note"> + You will notice that while we pulled in our RPC URLs via encrypted keystore variables in the Hardhat project, we only + encrypt the `PRIVATE_KEY` in Foundry. This is because as of of writing, Foundry supports keystore encryption only for + Private keys, and not generic strings. + </Aside> + + 4. Configure the remappings so that your `foundry.toml` file looks like this: + + ```toml filename="foundry.toml" + [profile.default] + solc = "0.8.24" + src = "src" + out = "out" + libs = ["lib"] + + remappings = [ + "forge-std/=lib/forge-std/src/", + "@chainlink/contracts-ccip/contracts/=lib/chainlink-ccip/chains/evm/contracts/", + "@chainlink/contracts/=lib/chainlink-evm/contracts/", + "@openzeppelin/contracts@5.0.2/utils/introspection/=lib/forge-std/src/interfaces/" + ] + + # RPC URLs will be fed to our script via Foundry's config file + [rpc_endpoints] + sepolia = "ENTER_YOUR_SEPOLIA_RPC_URL_HERE" + fuji = "ENTER_YOUR_FUJI_RPC_URL_HERE" + ``` +</Accordion> + +<Accordion title="Send a cross-chain message using CCIP" number={3}> + 1. Create a new directory named `script` at the root of the project if it doesn't already exist. + 2. Create a new file named `SendCrossChainMessage.s.sol` in this directory and paste the following code inside it: + + ```solidity filename="script/SendCrossChainMessage.s.sol" + // SPDX-License-Identifier: UNLICENSED + pragma solidity 0.8.24; + + import {Script, console} from "forge-std/Script.sol"; + + import {Sender} from "../src/Sender.sol"; + import {Receiver} from "../src/Receiver.sol"; + import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; + + contract SendCrossChainMessage is Script { + // Avalanche Fuji configuration + address constant FUJI_ROUTER = 0xF694E193200268f9a4868e4Aa017A0118C9a8177; + address constant FUJI_LINK = 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846; + + // Ethereum Sepolia configuration + address constant SEPOLIA_ROUTER =0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59; + uint64 constant SEPOLIA_CHAIN_SELECTOR = 16015286601757825753; + + // Configuring decimal value for LINK token + uint256 ONE_LINK = 1e18; + + function run() public { + + // Load form configs from foundry.toml + uint256 fujiFork = vm.createFork(vm.rpcUrl("fuji")); + uint256 sepoliaFork = vm.createFork(vm.rpcUrl("sepolia")); + + // Step 1: Deploy Sender on Fuji + + // Connect to Fuji Network + console.log("Connecting to Avalanche Fuji..."); + vm.selectFork(fujiFork); + vm.startBroadcast(); + + // Deploy Sender contract + console.log("\n[Step 1] Deploying Sender contract on Avalanche Fuji..."); + Sender sender = new Sender(FUJI_ROUTER, FUJI_LINK); + console.log("Sender contract has been deployed to this address on the Fuji testnet:", address(sender)); + console.log( + string.concat( + "View on Avascan: https://testnet.avascan.info/blockchain/all/address/", + vm.toString(address(sender)) + ) + ); + + // Step 2: Fund Sender with 1 LINK + console.log("\n[Step 2] Funding Sender with 1 LINK on Avalanche Fuji..."); + LinkTokenInterface(FUJI_LINK).transfer(address(sender), ONE_LINK); + vm.stopBroadcast(); + console.log("Funded Sender with 1 LINK on Fuji"); + + // Step 3: Deploy Receiver on Sepolia + + // Connect to Sepolia Network + console.log("Connecting to Ethereum Sepolia..."); + vm.selectFork(sepoliaFork); + vm.startBroadcast(); + + // Deploy Receiver contract + + console.log("\n[Step 3] Deploying Receiver contract on Ethereum Sepolia..."); + Receiver receiver = new Receiver(SEPOLIA_ROUTER); + vm.stopBroadcast(); + console.log("Receiver deployed on Sepolia at this address:", address(receiver)); + console.log( + string.concat( + "View on Etherscan: https://sepolia.etherscan.io/address/", + vm.toString(address(receiver)) + ) + ); + console.log("\n .....Copy the receiver address since it will be needed to run the verification script.....\n"); + console.log(address(receiver)); + + // Step 4: Send cross-chain message (Fuji -> Sepolia) + vm.selectFork(fujiFork); + vm.startBroadcast(); + + // Send cross-chain message + console.log("Sending cross-chain message from Fuji to Sepolia..."); + bytes32 messageId = sender.sendMessage( + SEPOLIA_CHAIN_SELECTOR, + address(receiver), + "Hello World from Foundry script!" + ); + vm.stopBroadcast(); + + console.log("The message has been sent to the CCIP router on Fuji, check for successful delivery after 5 minutes..."); + console.log("CCIP messageId:"); + console.logBytes32(messageId); + console.log("View transaction status on CCIP Explorer: https://ccip.chain.link"); + } + } + ``` + + 3. Run the following command to send the cross-chain message: + + ```bash filename="Terminal" + forge script script/SendCrossChainMessage.s.sol:SendCrossChainMessage --broadcast --multi --account PRIVATE_KEY + ``` + + <Aside type="note"> + - The `--broadcast` flag is used to broadcast transactions to an actual network. + - You can get detailed runtime logs by using the `-vvvv` verbosity flag. - The `--multi` flag is used to send transactions to multiple chains. + </Aside> +</Accordion> + +### Remix + +Best for **Web3-native** workflows that prefer a browser-based IDE. + +<Accordion title="Deploy the sender contract" number={1}> + Deploy the `Sender.sol` contract on *Avalanche Fuji*. To see a detailed explanation of this contract, read the [Code Explanation](#sender-code) section. + + 1. Open the Sender.sol contract in Remix. + + 2. Compile the contract. + + 3. Deploy the sender contract on *Avalanche Fuji*: + 1. Open MetaMask and select the *Avalanche Fuji* network. + + 2. In Remix under the **Deploy & Run Transactions** tab, select *Injected Provider - MetaMask* in the **Environment** list. Remix will use the MetaMask wallet to communicate with *Avalanche Fuji*. + + 3. Under the **Deploy** section, fill in the router address and the LINK token contract addresses for your specific blockchain. You can find both of these addresses on the [CCIP Directory](/ccip/directory). The LINK token contract address is also listed on the [LINK Token Contracts](/resources/link-token-contracts) page. For *Avalanche Fuji*, the router address is <CopyText text="0xF694E193200268f9a4868e4Aa017A0118C9a8177" code /> and the LINK address is <CopyText text="0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846" code />. + + <ClickToZoom src="/images/ccip/tutorials/deploy-sender-avalanche-fuji.webp" alt="Chainlink CCIP deploy sender Avalanche Fuji" /> + + 4. Click the **transact** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to *Avalanche Fuji*. + + 5. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy your contract address. + + <ClickToZoom src="/images/ccip/tutorials/deployed-sender-avalanche-fuji.webp" alt="Chainlink CCIP Deployed sender Avalanche Fuji" style="max-width: 70%;" /> + + 6. Open MetaMask and send <CopyText text="70" code /> LINK to the contract address that you copied. Your contract will pay CCIP fees in LINK. + + **Note:** This transaction fee is significantly higher than normal due to gas spikes on Sepolia. To run this example, you can get additional testnet LINK + from [faucets.chain.link](https://faucets.chain.link) or use a supported testnet other than Sepolia. +</Accordion> + +<Accordion title="Send data" number={3}> + Send a `Hello World!` string from your contract on *Avalanche Fuji* to the contract you deployed on *Ethereum Sepolia*: + + 1. Open MetaMask and select the *Avalanche Fuji* network. + + 2. In Remix under the **Deploy & Run Transactions** tab, expand the first contract in the **Deployed Contracts** section. + + 3. Expand the **sendMessage** function and fill in the following arguments: + + | Argument | Description | Value (*Ethereum Sepolia*) | + | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | + | destinationChainSelector | CCIP Chain identifier of the target blockchain. You can find each network's chain selector on the [CCIP Directory](/ccip/directory) | <CopyText text="16015286601757825753" code /> | + | receiver | The destination smart contract address | Your deployed contract address | + | text | Any `string` | <CopyText text="Hello World!" code /> | + + <ClickToZoom src="/images/ccip/tutorials/fuji-sendmessage.webp" alt="Chainlink CCIP Sepolia send message" style="max-width: 70%;" /> + + 4. Click the **transact** button to run the function. MetaMask prompts you to confirm the transaction. + + <Aside type="note" title="Gas price spikes"> + Under normal circumstances, transactions on the Ethereum Sepolia network require significantly fewer tokens to pay for gas. However, during exceptional periods of high gas price spikes, your transactions may fail if not sufficiently funded. In such cases, you may need to fund your contract with additional tokens. We recommend paying for your CCIP transactions in **LINK** tokens (rather than native tokens) as you can obtain extra LINK testnet tokens from [faucets.chain.link](https://faucets.chain.link/). If you encounter a transaction failure due to these gas price spikes, please add additional LINK tokens to your contract and try again. + Alternatively, you can use a supported testnet other than Sepolia. + </Aside> + + 5. After the transaction is successful, note the transaction hash. Here is an [example](https://testnet.snowtrace.io/tx/0x113933ec9f1b2e795a1e2f564c9d452db92d3e9a150545712687eb546916e633) of a successful transaction on *Avalanche Fuji*. + + After the transaction is finalized on the source chain, it will take a few minutes for CCIP to deliver the data to *Ethereum Sepolia* and call the `ccipReceive` function on your receiver contract. You can use the [CCIP explorer](https://ccip.chain.link/) to see the status of your CCIP transaction and then read data stored by your receiver contract. + + 6. Open the [CCIP explorer](https://ccip.chain.link/) and use the transaction hash that you copied to search for your cross-chain transaction. The explorer provides several details about your request. + + <ClickToZoom src="/images/ccip/tutorials/ccip-explorer-tx-details.webp" alt="Chainlink CCIP Explorer transaction details" /> + + 7. When the status of the transaction is marked with a "Success" status, the CCIP transaction and the destination transaction are complete. + + <ClickToZoom src="/images/ccip/tutorials/ccip-explorer-tx-details-success.webp" alt="Chainlink CCIP Explorer transaction details success" /> +</Accordion> --- @@ -423,7 +750,7 @@ These limits apply to messages sent from an EVM-compatible chain to the Aptos bl | Message execution gas limit | The user-specified `gasLimit` in `extraArgs` for the execution of the `ccip_receive` function on Aptos. | 100,000 gas | | Maximum number of tokens | The maximum number of distinct tokens that can be transferred in a single transaction. | 1 | | Smart Execution time window | The maximum duration that CCIP will attempt to automatically execute a message on Aptos before manual execution is required. | 8 hours | -| Token pool execution gas limit | The default gas overhead allocated for a standard token transfer operation on Aptos when a message is received from an EVM chain. | 36 gas | +| Token pool execution gas limit | The default gas overhead allocated for a standard token transfer operation on Aptos when a message is received from an EVM chain. | 10,000 gas | | Out of Order execution | The `allowOutOfOrderExecution` parameter in the `extraArgs` of a CCIP message from an EVM chain. | Must be `true` | ## Aptos to EVM @@ -433,10 +760,10 @@ These limits apply to messages sent from the Aptos blockchain to an EVM-compatib | Item | Description | Limit | | :----------------------------- | :------------------------------------------------------------------------------------------------------------------------- | :------------- | | Maximum message data length | The `data` payload sent within the [CCIP message](/ccip/api-reference/aptos/v1.6.0/messages#aptos2anymessage). | 30,000 bytes | -| Message execution gas limit | The user-specified `gasLimit` in `extraArgs` for the execution of the `ccipReceive` function on the destination EVM chain. | 100,000 gas | +| Message execution gas limit | The user-specified `gasLimit` in `extraArgs` for the execution of the `ccipReceive` function on the destination EVM chain. | 3,000,000 gas | | Maximum number of tokens | The maximum number of distinct tokens that can be transferred in a single transaction. | 1 | | Smart Execution time window | The maximum duration for the execution of a CCIP message on the destination EVM chain. | 8 hours | -| Token pool execution gas limit | The default gas overhead for executing token pool logic on the destination EVM chain for a standard token transfer. | 36 gas | +| Token pool execution gas limit | The default gas overhead for executing token pool logic on the destination EVM chain for a standard token transfer. | 90,000 gas | | Out of Order execution | The `allow_out_of_order_execution` parameter in the `extraArgs` of a CCIP message from Aptos. | Must be `true` | --- @@ -502,7 +829,7 @@ Token Developers may enable token transfers on CCIP for the tokens that they adm - **Token transfer rate limits**: Token DeveloperToken Owners must select and configure appropriate token transfer rate limits for tokens on each lane where they choose to enable their token. -- **Token transfer types**: Token Developers must select appropriate token transfer type for their tokens; either [Burn and Mint](/ccip/concepts/cross-chain-token/overview#burn-and-mint), [Lock and Mint](/ccip/concepts/cross-chain-token/overview#lock-and-mint), or [Lock and Unlock](/ccip/concepts/cross-chain-token/overview#lock-and-unlock). Token Developers are responsible for implementing the burn and mint functions, lock and mint functions or lock and unlock functions in their token contracts correctly on all applicable chains. +- **Token transfer types**: Token Developers must select appropriate token transfer type for their tokens; either [Burn and Mint](/ccip/concepts/cross-chain-token/overview#burn-and-mint), [Lock and Mint](/ccip/concepts/cross-chain-token/overview#lock-and-mint), or [Lock and Unlock](/ccip/concepts/cross-chain-token/overview#lock-and-unlock). Token Developers are responsible for implementing the burn / mint / transfer functions in their token contracts correctly on all applicable chains. - **Migration between CCIP versions**: Token Developers who wish to adopt future versions of CCIP are responsible for all migration tasks required to adopt new features and functionality. @@ -679,6 +1006,7 @@ This section provides an overview of the finality methods CCIP uses to determine | Metis | Finality tag | 2 hours | | Mind Network | Finality tag | 1 hour | | Mode | Finality tag | 37 minutes | +| Monad | [Block depth](#block-depth) (120 blocks) | 48 seconds | | OP | Finality tag | 20 minutes | | Polygon | [Block depth](#block-depth) (500 blocks) | 17 minutes | | Polygon zkEVM | Finality tag | 2 hours | @@ -771,7 +1099,7 @@ This cost is only relevant if the destination blockchain is a [L2 layer](https:/ ### Network fee -The fee paid to RMN node operators running the [Decentralized Oracle Network](/ccip/concepts/architecture/key-concepts#decentralized-oracle-network-don): +The fee paid to node operators running the [Decentralized Oracle Network](/ccip/concepts/architecture/key-concepts#decentralized-oracle-network-don): #### Token transfers or programmable token transfers @@ -1095,7 +1423,7 @@ When the Router forwards a `ccipSend()` request to the OnRamp, the contract perf - If the message involves token transfers, it retrieves the correct Token Pool from the Token Admin Registry. - Initiates calls to lock or burn the token, based on the token handling mechanism. 3. **Nonce Management** - - Uses the Nonce Manager to ensure messages requiring in-order execution are processed in the correct order. + - Uses the Nonce Manager to ensure messages requiring in-order execution are processed in the correct order. Note: In-Order enforcement using Nonce Manager will be deprecated in early 2026. 4. **Message ID Generation** - Returns a unique message ID to the Router. 5. **Event Emission** @@ -1165,17 +1493,6 @@ The FeeQuoter is an internal CCIP smart contract that calculates and returns CCI For additional details on how CCIP fees are calculated, refer to the [CCIP Billing page](/ccip/billing). -## NonceManager - -The NonceManager helps order messages in CCIP by tracking outbound nonces on the source blockchain and inbound nonces on the destination blockchain. It ensures strict ordering when the message's extraArgs parameter requires ordering, thus providing a flexible design. - -1. **Ordered Messages** - - **Non-zero Nonces:** When an OnRamp identifies a message that must preserve ordering, it increments and assigns a non-zero outbound nonce. - - **Inbound Validation:** On the destination blockchain, the OffRamp checks that the incoming message's nonce matches the expected inbound nonce. If there is a mismatch, the message is skipped or deferred for later retry. -2. **Out-of-Order Messages** - - **Zero Nonces:** For messages marked "out of order," the OnRamp sets the nonce to **0**. - - **No Sequence Checks:** Because `nonce == 0` indicates no ordering, the OffRamp does not validate or increment inbound nonces. These messages can execute immediately without waiting for earlier messages. - ## Token Admin Registry The Token Admin Registry is a user-facing CCIP smart contract that maintains a one-to-one mapping between token addresses and their corresponding token pool addresses on a given chain. The OnRamp and OffRamp contracts use the Token Admin Registry to retrieve a token's configured token pool address to call the appropriate functions: @@ -1451,7 +1768,7 @@ This section provides more detail on the Onchain components. **Additional Resources**: -- CCIP provides program examples for a Sender/Receiver in the [Programs folder](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs). +- CCIP provides program examples for a Sender/Receiver in the [Programs folder](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs). ## Router @@ -1581,7 +1898,7 @@ The FeeQuoter is a central component in Chainlink CCIP that maintains token and - Token Pools are deployed by token developers and exist independently of the core CCIP programs. - Token Pools are programs that interact with SPL token programs. -- Token pools follow standard models (Lock/Release and Burn/Mint), with audited code available in the [CCIP repository](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs). +- Token pools follow standard models (Lock/Release and Burn/Mint), with audited code available in the [CCIP repository](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs). - For tokens requiring bespoke logic before burn/mint/lock/release, custom pools can be built on top of the base pools. More details are available in the CCT documentation. ## Risk Management Network @@ -1837,18 +2154,9 @@ When the Router forwards a `ccip_send` request, the OnRamp performs the followin - If the message involves token transfers, it initiates a secure callback pattern by calling the `Token Admin Dispatcher`. - The dispatcher uses the `Token Admin Registry` to store the message context (sender, receiver, etc.) before invoking the correct `Token Pool` to `lock_or_burn` the assets. -- **Nonce Management** - - For ordered messages, it calls the `Nonce Manager` to retrieve and increment the sender's nonce for that destination. - - **Event Emission** - Generates a unique `messageId` and emits a `CCIPMessageSent` event containing the complete, sequenced message details. -## Nonce Manager - -The `ccip::nonce_manager` module enables optional strict message ordering. It tracks outbound nonces on a per-sender and per-destination-chain basis. - -When out-of-order execution is disabled for a message, the `OnRamp` module uses the `Nonce Manager` to assign an incrementing nonce, which is then verified by the `OffRamp` on the destination chain. - ## OffRamp The `ccip_offramp::offramp` module is an internal CCIP module that operates on the destination chain. It is the primary module that the offchain DONs interact with to deliver messages to Aptos. @@ -1996,6 +2304,14 @@ CCIP's offchain architecture includes the following: - **Decentralized Oracle Networks (DONs)**: Running offchain consensus using the Offchain Reporting Protocol (OCR). - **Interaction Components**: Managing communication between the CCIP DONs. +<Aside type="note"> + Based on user demand, CCIP's architecture is evolving to provide enhanced support for modular security and + configurable compliance capabilities. As part of this transition, the Risk Management Network is being adapted to + align with this broader, more flexible architecture. Please see the [onchain + architecture](/ccip/concepts/architecture/onchain/evm/components#rmn-contract) for more information on the current + functionality of the Risk Management Network. +</Aside> + ## Components ### CCIP Decentralized Oracle Networks @@ -2004,7 +2320,6 @@ With the CCIP v1.6 architecture, there is a single DON called the Role DON that 1. **Commit OCR Plugin** - Coordinates observations from multiple source chains. - - Requests blessings from the RMN (when applicable) and posts a Commit Report on the destination chain. 2. **Executing OCR Plugin** - Monitors pending executions on the destination chain. @@ -3027,7 +3342,7 @@ Before diving into the technical details, it's important to understand your thre **Who should use this:** Projects that need control over upgrade timing or have specific governance requirements. -**How it works:** You compile and deploy the Chainlink-provided [BurnMint](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/burnmint-token-pool) or [LockRelease](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/lockrelease-token-pool) programs to your chosen address, retaining upgrade authority. +**How it works:** You compile and deploy the Chainlink-provided [BurnMint](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/burnmint-token-pool) or [LockRelease](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/lockrelease-token-pool) programs to your chosen address, retaining upgrade authority. ### Approach 3: Custom Token Pools @@ -3047,7 +3362,7 @@ Before diving into the technical details, it's important to understand your thre Before implementing token pools, you need to choose the appropriate [token handling mechanism](/ccip/concepts/cross-chain-token/overview#token-handling-mechanisms) for your cross-chain token transfers. This strategic decision determines which combination of token pools you'll deploy on source and destination blockchains. -The table below summarizes the different token handling mechanisms and the [recommended token pools](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs) to deploy for each scenario, ensuring a seamless token transfer process. +The table below summarizes the different token handling mechanisms and the [recommended token pools](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs) to deploy for each scenario, ensuring a seamless token transfer process. | Token Handling Mechanism | Source Blockchain Token Pool Type | Destination Blockchain Token Pool Type | How it Works | | ------------------------ | --------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -3466,7 +3781,7 @@ Understanding who can call which instructions is critical for secure pool operat - You have operational capacity to monitor and maintain pool liquidity levels - Your token participates in [Lock and Mint/Burn and Unlock](/ccip/concepts/cross-chain-token/overview#burn-and-unlock) or [Lock and Unlock](/ccip/concepts/cross-chain-token/overview#lock-and-unlock) token handling mechanisms -Both pool types are built on the shared [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/base-token-pool) foundation, which provides common functionality including [rate limiting](/ccip/concepts/cross-chain-token/overview#token-pool-rate-limits), allowlists, cross-chain configuration, and event handling. +Both pool types are built on the shared [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/base-token-pool) foundation, which provides common functionality including [rate limiting](/ccip/concepts/cross-chain-token/overview#token-pool-rate-limits), allowlists, cross-chain configuration, and event handling. ## Next Steps: Pool Configuration @@ -3548,7 +3863,7 @@ When CCIP interacts with your custom token pools, it expects the presence of the #### Integration with Base Token Pool -All custom token pools should integrate the [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/base-token-pool) library for core functionality: +All custom token pools should integrate the [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/base-token-pool) library for core functionality: - **Ownership management**: Pool ownership and proposed ownership transfers - **Rate limiting**: Inbound and outbound rate limit controls per destination chain @@ -3602,9 +3917,9 @@ All standard token pools (BurnMint, LockRelease) automatically call [`to_svm_tok **Implementation References:** -- [BurnMint Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/burnmint-token-pool) - Standard burn/mint implementation -- [LockRelease Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/lockrelease-token-pool) - Standard lock/release implementation -- [Base Token Pool Library](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/base-token-pool) - Shared functionality foundation +- [BurnMint Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/burnmint-token-pool) - Standard burn/mint implementation +- [LockRelease Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/lockrelease-token-pool) - Standard lock/release implementation +- [Base Token Pool Library](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/base-token-pool) - Shared functionality foundation **Testing and Validation:** @@ -4202,11 +4517,11 @@ Source: https://docs.chain.link/ccip/concepts/manual-execution Last Updated: 2025-07-21 <Aside type="note" title="Prerequisites"> - Read the CCIP [Concepts](/ccip/concepts) and [Architecture](/ccip/concepts/architecture) pages to understand all the - concepts discussed on this page. + Read the CCIP [Concepts](/ccip/concepts) and [Architecture](/ccip/concepts/architecture/overview) pages to understand + all the concepts discussed on this page. </Aside> -In general, messages are successfully delivered and processed via CCIP as described in the [Architecture](/ccip/concepts/architecture) page. However, some exceptional conditions might require users to manually execute the transaction on the destination blockchain: +In general, messages are successfully delivered and processed via CCIP as described in the [Architecture](/ccip/concepts/architecture/overview) page. However, some exceptional conditions might require users to manually execute the transaction on the destination blockchain: - The receiver contract on the destination blockchain reverted due to an unhandled exception such as a logical error. - For token pools, if the combined execution of the required functions (`balanceOf` checks and `releaseOrMint`) exceeds the default gas limit of **90,000 gas** on the destination blockchain, CCIP execution will fail. Read the Token pools [common requirements](/ccip/concepts/cross-chain-token/evm/token-pools#common-requirements) to learn more. @@ -4297,6 +4612,823 @@ If your token pool's combined execution—including the `balanceOf` function cal --- +# Rate Limit Management Overview +Source: https://docs.chain.link/ccip/concepts/rate-limit-management/overview + +CCIP rate limits are an **operator-level control** that apply to token pools used for cross-chain transfers. They are designed to limit the volume of tokens that can move across a specific CCIP lane over time, reducing the blast radius of unexpected behavior and helping manage operational risk. + +This documentation is intended for **CCIP operators, token issuers, and administrators** who have been granted permission to manage rate limits on their token pool contracts. Most CCIP users do **not** need to interact with rate limits as part of a standard integration. + +Rate limit changes are applied on-chain, take effect immediately, and directly affect user-facing transfer availability. + +## What rate limits are + +Rate limits in CCIP act as **capacity buckets** that refill over time. Each token pool maintains two independent limits for every connected chain: + +- **Outbound rate limits**: how much of a token can be sent *from* the current chain to a remote chain +- **Inbound rate limits**: how much of a token can be received *from* a remote chain into the current chain + +Each limit is defined by: + +- whether it is enabled +- a maximum capacity +- a refill rate (tokens per second) + +Together, these parameters control how much value can flow through a CCIP lane within a given time window. + +## Why rate limits exist + +Rate limits are a defensive mechanism. They help: + +- prevent large, single transfers from draining liquidity unexpectedly +- limit exposure during misconfiguration, incidents, or active investigations +- give operators time to react if abnormal activity is detected + +Inbound and outbound limits are intentionally separate so that operators can tune risk asymmetrically depending on the direction of flow. + +## Who this applies to + +You should only interact with CCIP rate limits if **all** of the following are true: + +- You operate or administer a CCIP token pool +- Your wallet (typically a multisig) has been granted the `rateLimitAdmin` role +- You understand the decimal precision and units used by the token +- You are prepared to take responsibility for the operational impact of changes + +If these conditions are not met, you should not attempt to modify rate limits. + +## Responsibility and risk + +Managing rate limits directly affects the availability of cross-chain transfers for a token. Incorrect configuration can: + +- unintentionally halt bridging +- allow more volume than intended +- create congestion or stuck transfers + +Changes are applied on-chain and take effect immediately. Always review parameters carefully, verify units, and use a multisig workflow where possible. + +## What this section covers + +The pages in this section walk through: + +- how CCIP rate limits work +- required permissions and prerequisites +- inspecting current inbound and outbound configurations +- accounting for token decimals and units +- updating rate limits safely +- emergency actions such as locking down a lane +- common configuration scenarios + +This content focuses on **operational control**, not on basic CCIP integration or application development. + +--- + +# How Rate Limits Work +Source: https://docs.chain.link/ccip/concepts/rate-limit-management/how-rate-limits-work + +This page explains how CCIP rate limits function at a conceptual level. It focuses on *what the system does* and *how the parameters interact*, without covering how to make changes on-chain. + +## Rate limits as capacity buckets + +CCIP rate limits are implemented as **capacity buckets** that refill over time. Each bucket starts with a defined maximum capacity and refills continuously at a fixed rate. + +Transfers draw down capacity from the relevant bucket. If insufficient capacity is available, the transfer is rejected until enough capacity has refilled. + +This model limits how much value can move through a CCIP lane within a given time window, even if many transfers are attempted. + +## Inbound and outbound rate limits + +Each token pool maintains **two independent rate limits per connected chain**: + +- **Outbound rate limit**: limits transfers *from* the local chain *to* a remote chain +- **Inbound rate limit**: limits transfers *from* a remote chain *into* the local chain + +Inbound and outbound limits are configured separately and can differ in capacity and refill rate. This allows operators to tune risk asymmetrically depending on the direction of flow. + +In practice, outbound limits are often configured to be slightly lower than inbound limits to provide buffer room and reduce the risk of in-flight congestion. + +## Core rate limit parameters + +Each inbound or outbound rate limit is defined by three parameters: + +- **isEnabled**: whether the rate limit is active +- **capacity**: the maximum amount of tokens that can be transferred before the bucket is depleted +- **rate**: the speed at which capacity refills, measured in tokens per second + +All values are expressed in the token’s **smallest unit**, not in whole tokens. + +## Token bucket state + +At any moment, a rate limiter tracks the current state of its bucket, including: + +- the remaining number of tokens available +- the timestamp of the last refill +- whether the limiter is enabled +- the configured capacity and refill rate + +This state determines whether a transfer can proceed and how quickly capacity becomes available again after use. + +## Enabled vs disabled behavior + +When a rate limit is **enabled**, transfers are constrained by the configured capacity and refill rate. + +When a rate limit is **disabled**, transfers are not subject to any volume limits for that lane. + +Disabling rate limits removes an important safety mechanism and should only be done intentionally and with a clear understanding of the associated risk. + +## Scope and granularity + +Rate limits are applied: + +- per token pool +- per remote chain +- independently for inbound and outbound directions + +This means changes to a rate limit affect only a specific token and lane, not all CCIP traffic. + +## What this page does not cover + +This page does not cover: + +- required permissions to manage rate limits +- how to inspect current configurations +- how to update or disable rate limits +- emergency or incident response actions + +Those topics are covered in the subsequent pages of this section. + +--- + +# Prerequisites and Permissions +Source: https://docs.chain.link/ccip/concepts/rate-limit-management/prerequisites-and-permissions + +Managing CCIP rate limits is a privileged, operator-level action. Before attempting to inspect or modify any rate limit configuration, you must meet the prerequisites described on this page. + +## Required permissions + +To manage rate limits, your wallet must be granted the **`rateLimitAdmin`** role on the relevant token pool contracts. + +This role allows the wallet to update inbound and outbound rate limit configurations for specific cross-chain lanes. Without it, you can read on-chain data but cannot make changes. + +In most cases, the `rateLimitAdmin` role is assigned to a **multisig wallet** rather than to an individual externally owned account. + +## How admin access is granted + +Admin access is not self-assigned. + +To receive the `rateLimitAdmin` role: + +- You provide the address of your designated wallet (typically a multisig) +- Chainlink Labs assigns that address as the rate limit administrator on the relevant token pool contracts + +Once the on-chain transaction granting this role is confirmed, the wallet can update rate limit configurations. + +## Scope of admin authority + +The `rateLimitAdmin` role applies: + +- per token pool +- across inbound and outbound directions +- per connected chain + +This means: + +- you can manage rate limits only for token pools where your wallet has been granted access +- changes affect only the specified token and lane +- core CCIP configuration outside of rate limits is not affected + +## Operational expectations + +Before making any changes, you should ensure that: + +- you understand the token’s decimal precision and smallest unit +- you have reviewed the current inbound and outbound configurations +- you are prepared to validate values carefully before submitting transactions + +Rate limit changes are applied on-chain and take effect immediately. + +## Responsibility boundary + +By managing rate limits, you take responsibility for the availability of cross-chain transfers for the affected token and lane. + +Incorrect configuration can: + +- unintentionally block transfers +- allow more volume than intended +- create operational or user-facing disruption + +For this reason, rate limit management should follow a deliberate review process and use a multisig workflow where possible. + +## What’s next + +If you meet these prerequisites, the next step is to [inspect the current inbound and outbound rate limit](/ccip/concepts/rate-limit-management/inspect-current-rate-limits) configuration before making any changes. + +--- + +# Inspect Current Rate Limits +Source: https://docs.chain.link/ccip/concepts/rate-limit-management/inspect-current-rate-limits + +Before updating any rate limit configuration, you should inspect the **current inbound and outbound settings** for the token pool and lane you are managing. This ensures you understand the existing capacity, refill rate, and enabled state before making changes. + +## What you can inspect + +Each token pool exposes read-only functions that return the current rate limiter state for a given remote chain. These values describe: + +- whether the inbound or outbound rate limit is enabled +- the configured capacity +- the configured refill rate +- the current number of tokens available in the bucket +- the timestamp of the last refill + +Together, these values determine whether transfers are currently allowed and how quickly capacity becomes available. + +## Identify the token pool contract + +To inspect rate limits, you first need the **token pool contract address** for the token you are managing. + +You can find token pool addresses using the Token Manager or by searching for the token contract address in the token manager search interface. + +## Select the remote chain + +Rate limits are configured per remote chain. When querying a rate limiter, you must provide the **remote chain selector** that identifies the cross-chain lane you want to inspect. + +Chain selectors are represented as `uint64` values. You can find the correct selector for each supported network in the CCIP directory. + +## Query inbound and outbound limiter state + +Most token pool contracts expose public getter functions similar to: + +```solidity +function getCurrentInboundRateLimiterState( + uint64 remoteChainSelector +) external view returns (TokenBucket memory); + +function getCurrentOutboundRateLimiterState( + uint64 remoteChainSelector +) external view returns (TokenBucket memory); + +``` + +These functions take a remote chain selector as input and return the current **TokenBucket** state for that lane. + +You can call these functions using: + +- a block explorer’s “Read Contract” interface +- a web3-enabled script or client + +## Interpreting the TokenBucket state + +A typical rate limiter state includes the following fields: + +```solidity +struct TokenBucket { + uint128 tokens; + uint32 lastUpdated; + bool isEnabled; + uint128 capacity; + uint128 rate; +} +``` + +Where: + +- tokens (uint128): the current number of tokens available in the bucket +- lastUpdated (uint32): the timestamp of the last refill +- isEnabled (bool): whether the rate limit is active +- capacity (uint128): the maximum bucket size +- rate (uint128): the refill rate in tokens per second +- All numeric values are expressed in the token’s **smallest unit**, not in whole tokens. + +## Inbound vs outbound inspection + +Inbound and outbound configurations should be inspected **independently**: + +- outbound limits control transfers leaving the current chain +- inbound limits control transfers entering the current chain + +Although these values are often similar, they may intentionally differ based on risk tolerance and traffic patterns. + +## Before proceeding + +After inspecting the current configuration: + +- record the existing values +- confirm token decimals and unit conversions +- identify which direction and lane you intend to modify + +Only proceed to updating rate limits once you fully understand the current state. + +--- + +# Token Units and Decimals +Source: https://docs.chain.link/ccip/concepts/rate-limit-management/token-units-and-decimals + +When configuring CCIP rate limits, **all values are specified in the token’s smallest unit**, not in whole tokens. Understanding token decimals is critical to setting correct capacity and refill rates. + +Incorrect unit handling can result in rate limits that are orders of magnitude larger or smaller than intended. + +## Smallest unit vs human-readable amounts + +Every ERC-20 token defines a number of decimal places that determine its smallest unit: + +- An 18-decimal token (for example, LINK or ETH) uses `10^18` base units per token +- A 6-decimal token (for example, USDC or USDT) uses `10^6` base units per token + +Rate limit parameters such as **capacity** and **rate** must always be provided in these base units. + +## Converting values for on-chain configuration + +To convert a human-readable token amount into the value used on-chain, apply the following formula: + +``` +On-chain value = human-readable amount × (10 ^ token decimals) +``` + +This conversion applies to: + +- capacity values +- refill rate values + +## Example: 18-decimal token + +Token: + +- Decimals: 18 +- Desired capacity: 100 tokens + +Calculation: + +``` +100 × 10^18 = 100000000000000000000 +``` + +The capacity value passed to the token pool contract must be `100000000000000000000`. + +## Example: 6-decimal token + +Token: + +- Decimals: 6 +- Desired capacity: 500 tokens + +Calculation: + +``` +500 × 10^6 = 500000000 +``` + +The capacity value passed to the token pool contract must be `500000000`. + +## Common failure modes + +The most common causes of misconfiguration include: + +- assuming values are specified in whole tokens +- applying the wrong decimal precision +- copying example values without recalculating for the target token + +Any of these mistakes can: + +- unintentionally block transfers +- allow far more volume than expected +- create operational risk that is difficult to detect immediately + +## Before updating rate limits + +Before submitting any transaction that updates rate limits: + +- verify the token’s decimal precision +- recompute capacity and rate values from first principles +- double-check values in base units + +Once values are submitted on-chain, they take effect immediately. + +## What’s next + +After validating units and conversions, you can proceed to [updating inbound and outbound rate limits](/ccip/concepts/rate-limit-management/update-rate-limits) for the selected token pool and lane. + +--- + +# Update Rate Limits +Source: https://docs.chain.link/ccip/concepts/rate-limit-management/update-rate-limits + +Once you understand the current configuration and have validated token units and decimals, you can update inbound and outbound rate limits for a specific token pool and lane. + +Rate limit updates are applied on-chain and take effect immediately. Changes should be made deliberately and reviewed carefully before submission. + +## Function used to update rate limits + +Rate limits are updated by calling the `setChainRateLimiterConfig` function on the token pool contract. + +This function updates both the inbound and outbound rate limit configuration for a given remote chain. + +## Required parameters + +The `setChainRateLimiterConfig` function takes three parameters: + +```solidity +function setChainRateLimiterConfig( + uint64 remoteChainSelector, + RateLimiter.Config outboundConfig, + RateLimiter.Config inboundConfig +) external; +``` + +Each configuration tuple contains: + +```solidity +struct Config { + bool isEnabled; + uint128 capacity; + uint128 rate; +} +``` + +- **isEnabled**: whether the rate limit is active +- **capacity**: maximum bucket size (in base units) +- **rate**: refill rate in tokens per second (in base units) + +## Inbound and outbound configuration guidance + +Inbound and outbound limits are configured independently, but they are related. + +A common operational pattern is: + +- configure **outbound capacity** to be lower than inbound capacity +- set outbound capacity to approximately **90% of the inbound value** + +This provides buffer room and reduces the likelihood of in-flight congestion. + +## Example interaction (conceptual) + +Rate limit updates are typically executed using a web3-enabled client or a multisig wallet. + +At a high level, updating a rate limit involves: + +- selecting the token pool contract address +- providing the remote chain selector +- supplying outbound and inbound configuration tuples +- submitting the transaction from a wallet with the `rateLimitAdmin` role + +The exact tooling used does not change the on-chain behavior. + +## Verifying before submission + +Before submitting a rate limit update: + +- re-check all values are expressed in the token’s smallest unit +- confirm inbound and outbound directions are not swapped +- verify the correct remote chain selector is used +- review existing values to ensure changes are intentional + +## After the update + +Once the transaction is confirmed: + +- the new rate limits apply immediately +- transfers are accepted or rejected based on the updated configuration + +You should monitor behavior after changes to confirm the limits behave as expected. + +## What this page does not cover + +This page does not cover: + +- emergency actions such as locking down a lane +- worked examples for specific token decimals +- tool-specific execution steps + +Those topics are covered in the following pages. + +--- + +# Emergency Actions (Incident Response Only) +Source: https://docs.chain.link/ccip/concepts/rate-limit-management/emergency-actions + +This page describes emergency actions that can be taken to **contain or halt cross-chain transfers on a specific CCIP lane** using rate limit configuration. + +These actions are intended for **incident response, maintenance, or risk containment** scenarios. They should not be used for routine configuration. + +## When to use emergency actions + +You may need to take emergency action if: + +- abnormal or unexpected transfer activity is detected +- a misconfiguration or incident is under investigation +- maintenance requires temporarily stopping transfers on a lane + +Emergency actions are scoped to a **specific token pool and lane**. They do not pause CCIP globally. + +## Locking down a lane with minimal values + +To effectively stop bridging activity on a lane, you can configure rate limits with **very small capacity and refill values**. + +Because rate limits cannot be set to zero while enabled, the practical approach is to set: + +- **capacity** to the smallest transferable unit (for example, `1`) +- **rate** to `1` + +This configuration allows only a negligible transfer before the bucket is depleted, causing subsequent transfers to fail. + +## Example configuration + +Conceptually, a lane can be locked down by calling `setChainRateLimiterConfig` with the following values: + +```solidity +outboundConfig = [true, 1, 1]; +inboundConfig = [true, 1, 1]; +``` + +Both inbound and outbound limits should be set to ensure transfers are blocked in both directions. + +## Important considerations + +When locking down a lane: + +- transfers may still succeed for a minimal amount before capacity is exhausted +- behavior depends on the token’s smallest unit +- the change takes effect immediately after the transaction is confirmed + +This approach is intended to **contain activity**, not to permanently disable rate limits. + +## Restoring normal operation + +To resume normal transfers, update the inbound and outbound rate limit configuration with appropriate capacity and refill values. + +Always revalidate token units and existing configuration before restoring service. + +## What this page does not cover + +This page does not cover: + +- routine rate limit tuning +- worked examples for different token decimals +- fully removing rate limits + +Those topics are covered in the [common scenarios](/ccip/concepts/rate-limit-management/common-scenarios) section. + +--- + +# Common Scenarios +Source: https://docs.chain.link/ccip/concepts/rate-limit-management/common-scenarios + +This page provides worked configuration scenarios for common rate limit use cases. These examples illustrate how capacity and refill values are calculated and applied for different token types and operational goals. + +All scenarios assume: + +- you have the `rateLimitAdmin` role +- you have inspected the current configuration +- you have validated token units and decimals + +These scenarios are examples, not defaults. Values must always be recalculated for the specific token, lane, and risk tolerance. + +## Scenario: 18-decimal tokens + +This scenario applies to tokens with **18 decimals**, such as LINK or ETH. + +### When to use this + +Use this pattern when managing rate limits for an 18-decimal token and you want to allow a bounded amount of value to flow steadily between two chains. + +### Example configuration + +Assumptions: + +- desired inbound capacity: 20 tokens +- desired outbound capacity: 10 tokens +- refill rate: 0.1 tokens per second + +Converted to base units: + +- inbound capacity: `20 × 10^18 = 20000000000000000000` +- outbound capacity (90% of inbound): `10 × 10^18 = 10000000000000000000` +- refill rate: `0.1 × 10^18 = 100000000000000000` + +Inbound and outbound limits are configured separately for each token pool, with values swapped appropriately on each side of the lane. + +## Scenario: 6-decimal tokens + +This scenario applies to tokens with **6 decimals**, such as USDC or USDT. + +### When to use this + +Use this pattern when configuring rate limits for stablecoins or other low-decimal tokens. + +### Example configuration + +Assumptions: + +- desired inbound capacity: 2000 tokens +- desired outbound capacity: 1000 tokens +- inbound refill rate: 5 tokens per second +- outbound refill rate: 10 tokens per second + +Converted to base units: + +- inbound capacity: `2000 × 10^6 = 2000000000` +- outbound capacity (90% of inbound): `1000 × 10^6 = 1000000000` +- inbound refill rate: `5 × 10^6 = 5000000` +- outbound refill rate: `10 × 10^6 = 10000000` + +As with 18-decimal tokens, inbound and outbound configurations must be applied on both sides of the lane. + +## Scenario: pausing a lane + +This scenario demonstrates how to effectively pause transfers on a specific lane using rate limits. + +### When to use this + +Use this pattern during incidents, investigations, or maintenance when transfers must be temporarily halted. + +### Configuration pattern + +To lock down a lane: + +- enable the rate limit +- set capacity to `1` +- set refill rate to `1` + +Apply this configuration to **both inbound and outbound** limits for the lane. + +This allows only a negligible transfer before capacity is exhausted, causing subsequent transfers to fail. + +## Scenario: removing rate limits + +This scenario demonstrates how to remove rate limits entirely for a lane. + +### When to use this + +Use this pattern only when you intentionally want transfers to be unconstrained by rate limits. + +### Configuration pattern + +To remove rate limits: + +- set `isEnabled` to `false` +- set `capacity` to `0` +- set `rate` to `0` + +Apply this configuration to both inbound and outbound limits. + +## Important notes + +- Scenario values must always be recalculated for the specific token and lane +- Do not copy example values without adjusting for decimals and desired behavior +- Changes take effect immediately once the transaction is confirmed + +--- + +# Executing with a Multisig +Source: https://docs.chain.link/ccip/concepts/rate-limit-management/executing-with-a-multisig + +Rate limit changes are commonly executed from a **multisig wallet** to reduce operational risk and ensure changes are reviewed before being applied on-chain. + +This page describes the high-level execution model for multisig-based updates and points to tooling that can be used to submit transactions safely. + +## Why use a multisig + +Managing CCIP rate limits directly affects cross-chain transfer availability. Using a multisig helps: + +- require multiple reviewers before changes are executed +- reduce the risk of accidental misconfiguration +- provide an auditable record of approvals + +For this reason, the `rateLimitAdmin` role is typically assigned to a multisig wallet rather than to an individual account. + +## What the multisig submits + +Regardless of the interface used, a multisig ultimately submits a transaction that calls: + +- the token pool contract address +- the `setChainRateLimiterConfig` function +- the selected remote chain selector +- inbound and outbound configuration tuples + +The multisig does not change how rate limits work on-chain; it only controls how the transaction is approved and submitted. + +## Building the transaction + +To build a rate limit update transaction using a multisig: + +- identify the correct token pool contract address +- prepare the `setChainRateLimiterConfig` function call +- supply the remote chain selector +- enter the inbound and outbound configuration values as tuples + +Configuration tuples must be entered as arrays containing: + +- `isEnabled` +- `capacity` +- `rate` + +All numeric values must be expressed in the token’s smallest unit. + +## Tooling options + +Common tooling options for executing multisig transactions include: + +- Safe transaction builder +- custom scripts that submit transactions to the multisig +- internal operator tooling built on top of web3 libraries + +The specific interface used does not affect the on-chain outcome. + +## Verification before submission + +Before submitting a multisig transaction: + +- confirm the token pool contract address +- verify the remote chain selector +- recheck inbound and outbound directions +- validate capacity and rate values in base units + +Because rate limit changes take effect immediately, careful review is essential. + +## After execution + +Once the multisig transaction is executed and confirmed on-chain: + +- the updated rate limits apply immediately +- transfers follow the new configuration + +Monitor behavior after execution to confirm the expected outcome. + +## setChainRateLimiterConfig ABI + +The following ABI is provided to support multisig and transaction builder workflows where the function interface must be supplied manually. This is a direct representation of the function used to update CCIP rate limits. + +```json +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "remoteChainSelector", + "type": "uint64" + }, + { + "components": [ + { + "internalType": "bool", + "name": "isEnabled", + "type": "bool" + }, + { + "internalType": "uint128", + "name": "capacity", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "rate", + "type": "uint128" + } + ], + "internalType": "struct RateLimiter.Config", + "name": "outboundConfig", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "isEnabled", + "type": "bool" + }, + { + "internalType": "uint128", + "name": "capacity", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "rate", + "type": "uint128" + } + ], + "internalType": "struct RateLimiter.Config", + "name": "inboundConfig", + "type": "tuple" + } + ], + "name": "setChainRateLimiterConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] +``` + +## Related references + +- [Inspect Current Rate Limits](/ccip/concepts/rate-limit-management/inspect-current-rate-limits) +- [Update Rate Limits](/ccip/concepts/rate-limit-management/update-rate-limits) +- [Common Scenarios](/ccip/concepts/rate-limit-management/common-scenarios) + +For tool-specific walkthroughs, refer to the Token Manager and multisig documentation linked from the Tools section. + +--- + # CCIP Best Practices (EVM) Source: https://docs.chain.link/ccip/concepts/best-practices/evm Last Updated: 2025-05-19 @@ -4372,7 +5504,7 @@ The `allowOutOfOrderExecution` parameter enables you to control the execution or - **When `allowOutOfOrderExecution` is Optional:** - You can set `allowOutOfOrderExecution` to either `true` or `false`, depending on your application's requirements. - **`true`:** Messages can be executed in any order relative to other messages from the same sender. If a previous message has not yet been executed on the destination chain, it does not block the execution of subsequent messages. - - **`false`:** Messages are executed in order. CCIP ensures that preceding messages are processed before executing the current message. + - **`false`:** Messages are executed in order. CCIP ensures that preceding messages are processed before executing the current message. Note: Functionality for `allowOutofOrderExecution` = `false` (ie., enforcing In-Order cross-chain messages) is being deprecated in early 2026. - **When `allowOutOfOrderExecution` is Required:** - You **must** set `allowOutOfOrderExecution` to `true`. This setting acknowledges that messages may be executed out of order. If set to `false`, the message will revert and will not be processed. @@ -5126,6 +6258,299 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens from a smart co In this tutorial, you will transfer [CCIP-BnM](/ccip/test-tokens#about-ccip-test-tokens) tokens from a contract on Avalanche Fuji to an account on Ethereum Sepolia. First, you will pay [CCIP fees in LINK](#transfer-tokens-and-pay-in-link), then you will pay [CCIP fees in native gas](#transfer-tokens-and-pay-in-native). The destination account can be an [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) or a smart contract. Moreover, the example shows how to transfer CCIP-BnM tokens, but you can re-use the same example to transfer other tokens as long as they are supported for your [lane](/ccip/concepts/architecture/key-concepts#lane). +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; + +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/// @title - A simple contract for transferring tokens across chains. +contract TokenTransferor is OwnerIsCreator { + using SafeERC20 for IERC20; + + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 requiredBalance); // Used to make sure contract has enough + // token balance + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error FailedToWithdrawEth(address owner, address target, uint256 value); // Used when the withdrawal of Ether fails. + error DestinationChainNotAllowlisted(uint64 destinationChainSelector); // Used when the destination chain has not been + // allowlisted by the contract owner. + error InvalidReceiverAddress(); // Used when the receiver address is 0. + // Event emitted when the tokens are transferred to an account on another chain. + + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The token address that was transferred. + // The token amount that was transferred. + // the token address used to pay CCIP fees. + // The fees paid for sending the message. + event TokensTransferred( // The unique ID of the message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address receiver, + address token, + uint256 tokenAmount, + address feeToken, + uint256 fees + ); + + // Mapping to keep track of allowlisted destination chains. + mapping(uint64 => bool) public allowlistedChains; + + IRouterClient private s_router; + + IERC20 private s_linkToken; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) { + s_router = IRouterClient(_router); + s_linkToken = IERC20(_link); + } + + /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. + /// @param _destinationChainSelector The selector of the destination chain. + modifier onlyAllowlistedChain( + uint64 _destinationChainSelector + ) { + if (!allowlistedChains[_destinationChainSelector]) { + revert DestinationChainNotAllowlisted(_destinationChainSelector); + } + _; + } + + /// @dev Modifier that checks the receiver address is not 0. + /// @param _receiver The receiver address. + modifier validateReceiver( + address _receiver + ) { + if (_receiver == address(0)) revert InvalidReceiverAddress(); + _; + } + + /// @dev Updates the allowlist status of a destination chain for transactions. + /// @notice This function can only be called by the owner. + /// @param _destinationChainSelector The selector of the destination chain to be updated. + /// @param allowed The allowlist status to be set for the destination chain. + function allowlistDestinationChain( + uint64 _destinationChainSelector, + bool allowed + ) external onlyOwner { + allowlistedChains[_destinationChainSelector] = allowed; + } + + /// @notice Transfer tokens to receiver on the destination chain. + /// @notice pay in LINK. + /// @notice the token must be in the list of supported tokens. + /// @notice This function can only be called by the owner. + /// @dev Assumes your contract has sufficient LINK tokens to pay for the fees. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _token token address. + /// @param _amount token amount. + /// @return messageId The ID of the message that was sent. + function transferTokensPayLINK( + uint64 _destinationChainSelector, + address _receiver, + address _token, + uint256 _amount + ) + external + onlyOwner + onlyAllowlistedChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + // address(linkToken) means fees are paid in LINK + Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(_receiver, _token, _amount, address(s_linkToken)); + + // Get the fee required to send the message + uint256 fees = s_router.getFee(_destinationChainSelector, evm2AnyMessage); + + uint256 requiredLinkBalance; + if (_token == address(s_linkToken)) { + // Required LINK Balance is the sum of fees and amount to transfer, if the token to transfer is LINK + requiredLinkBalance = fees + _amount; + } else { + requiredLinkBalance = fees; + } + + uint256 linkBalance = s_linkToken.balanceOf(address(this)); + + if (requiredLinkBalance > linkBalance) { + revert NotEnoughBalance(linkBalance, requiredLinkBalance); + } + + // approve the Router to transfer LINK tokens on contract's behalf. It will spend the requiredLinkBalance + s_linkToken.approve(address(s_router), requiredLinkBalance); + + // If sending a token other than LINK, approve it separately + if (_token != address(s_linkToken)) { + uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); + if (_amount > tokenBalance) { + revert NotEnoughBalance(tokenBalance, _amount); + } + // approve the Router to spend tokens on contract's behalf. It will spend the amount of the given token + IERC20(_token).approve(address(s_router), _amount); + } + + // Send the message through the router and store the returned message ID + messageId = s_router.ccipSend(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit TokensTransferred(messageId, _destinationChainSelector, _receiver, _token, _amount, address(s_linkToken), fees); + + // Return the message ID + return messageId; + } + + /// @notice Transfer tokens to receiver on the destination chain. + /// @notice Pay in native gas such as ETH on Ethereum or POL on Polygon. + /// @notice the token must be in the list of supported tokens. + /// @notice This function can only be called by the owner. + /// @dev Assumes your contract has sufficient native gas like ETH on Ethereum or POL on Polygon. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _token token address. + /// @param _amount token amount. + /// @return messageId The ID of the message that was sent. + function transferTokensPayNative( + uint64 _destinationChainSelector, + address _receiver, + address _token, + uint256 _amount + ) + external + onlyOwner + onlyAllowlistedChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + // address(0) means fees are paid in native gas + Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(_receiver, _token, _amount, address(0)); + + // Get the fee required to send the message + uint256 fees = s_router.getFee(_destinationChainSelector, evm2AnyMessage); + + if (fees > address(this).balance) { + revert NotEnoughBalance(address(this).balance, fees); + } + + // approve the Router to spend tokens on contract's behalf. It will spend the amount of the given token + IERC20(_token).approve(address(s_router), _amount); + + // Send the message through the router and store the returned message ID + messageId = s_router.ccipSend{value: fees}(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit TokensTransferred(messageId, _destinationChainSelector, _receiver, _token, _amount, address(0), fees); + + // Return the message ID + return messageId; + } + + /// @notice Construct a CCIP message. + /// @dev This function will create an EVM2AnyMessage struct with all the necessary information for tokens transfer. + /// @param _receiver The address of the receiver. + /// @param _token The token to be transferred. + /// @param _amount The amount of the token to be transferred. + /// @param _feeTokenAddress The address of the token used for fees. Set address(0) for native gas. + /// @return Client.EVM2AnyMessage Returns an EVM2AnyMessage struct which contains information for sending a CCIP + /// message. + function _buildCCIPMessage( + address _receiver, + address _token, + uint256 _amount, + address _feeTokenAddress + ) private pure returns (Client.EVM2AnyMessage memory) { + // Set the token amounts + Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1); + tokenAmounts[0] = Client.EVMTokenAmount({token: _token, amount: _amount}); + + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + return Client.EVM2AnyMessage({ + receiver: abi.encode(_receiver), // ABI-encoded receiver address + data: "", // No data + tokenAmounts: tokenAmounts, // The amount and type of token being transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 0, // Gas limit for the callback on the destination chain + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender + }) + ), + // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees + feeToken: _feeTokenAddress + }); + } + + /// @notice Fallback function to allow the contract to receive Ether. + /// @dev This function has no function body, making it a default function for receiving Ether. + /// It is automatically called when Ether is transferred to the contract without any data. + receive() external payable {} + + /// @notice Allows the contract owner to withdraw the entire balance of Ether from the contract. + /// @dev This function reverts if there are no funds to withdraw or if the transfer fails. + /// It should only be callable by the owner of the contract. + /// @param _beneficiary The address to which the Ether should be transferred. + function withdraw( + address _beneficiary + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = address(this).balance; + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + // Attempt to send the funds, capturing the success status and discarding any return data + (bool sent,) = _beneficiary.call{value: amount}(""); + + // Revert if the send failed, with information about the attempted transfer + if (!sent) revert FailedToWithdrawEth(msg.sender, _beneficiary, amount); + } + + /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + /// @param _token The contract address of the ERC20 token to be withdrawn. + function withdrawToken( + address _beneficiary, + address _token + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = IERC20(_token).balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + IERC20(_token).safeTransfer(_beneficiary, amount); + } +} +``` + ### Deploy your contracts To use this contract: @@ -5382,6 +6807,418 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens and arbitrary d In this tutorial, you will send a *string* text and CCIP-BnM tokens between smart contracts on *Avalanche Fuji* and *Ethereum Sepolia* using CCIP. First, you will pay [CCIP fees in LINK](#transfer-and-receive-tokens-and-data-and-pay-in-link), then you will pay [CCIP fees in native gas](#transfer-and-receive-tokens-and-data-and-pay-in-native). +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; +import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/// @title - A simple messenger contract for transferring/receiving tokens and data across chains. +contract ProgrammableTokenTransfers is CCIPReceiver, OwnerIsCreator { + using SafeERC20 for IERC20; + + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 requiredBalance); // Used to make sure contract has enough + // token balance + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error FailedToWithdrawEth(address owner, address target, uint256 value); // Used when the withdrawal of Ether fails. + error DestinationChainNotAllowed(uint64 destinationChainSelector); // Used when the destination chain has not been + // allowlisted by the contract owner. + error SourceChainNotAllowed(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by the + // contract owner. + error SenderNotAllowed(address sender); // Used when the sender has not been allowlisted by the contract owner. + error InvalidReceiverAddress(); // Used when the receiver address is 0. + + // Event emitted when a message is sent to another chain. + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The text being sent. + // The token address that was transferred. + // The token amount that was transferred. + // the token address used to pay CCIP fees. + // The fees paid for sending the message. + event MessageSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address receiver, + string text, + address token, + uint256 tokenAmount, + address feeToken, + uint256 fees + ); + + // Event emitted when a message is received from another chain. + // The chain selector of the source chain. + // The address of the sender from the source chain. + // The text that was received. + // The token address that was transferred. + // The token amount that was transferred. + event MessageReceived( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed sourceChainSelector, + address sender, + string text, + address token, + uint256 tokenAmount + ); + + bytes32 private s_lastReceivedMessageId; // Store the last received messageId. + address private s_lastReceivedTokenAddress; // Store the last received token address. + uint256 private s_lastReceivedTokenAmount; // Store the last received amount. + string private s_lastReceivedText; // Store the last received text. + + // Mapping to keep track of allowlisted destination chains. + mapping(uint64 => bool) public allowlistedDestinationChains; + + // Mapping to keep track of allowlisted source chains. + mapping(uint64 => bool) public allowlistedSourceChains; + + // Mapping to keep track of allowlisted senders. + mapping(address => bool) public allowlistedSenders; + + IERC20 private s_linkToken; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) CCIPReceiver(_router) { + s_linkToken = IERC20(_link); + } + + /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. + /// @param _destinationChainSelector The selector of the destination chain. + modifier onlyAllowlistedDestinationChain( + uint64 _destinationChainSelector + ) { + if (!allowlistedDestinationChains[_destinationChainSelector]) { + revert DestinationChainNotAllowed(_destinationChainSelector); + } + _; + } + + /// @dev Modifier that checks the receiver address is not 0. + /// @param _receiver The receiver address. + modifier validateReceiver( + address _receiver + ) { + if (_receiver == address(0)) revert InvalidReceiverAddress(); + _; + } + + /// @dev Modifier that checks if the chain with the given sourceChainSelector is allowlisted and if the sender is + /// allowlisted. + /// @param _sourceChainSelector The selector of the destination chain. + /// @param _sender The address of the sender. + modifier onlyAllowlisted( + uint64 _sourceChainSelector, + address _sender + ) { + if (!allowlistedSourceChains[_sourceChainSelector]) { + revert SourceChainNotAllowed(_sourceChainSelector); + } + if (!allowlistedSenders[_sender]) revert SenderNotAllowed(_sender); + _; + } + + /// @dev Updates the allowlist status of a destination chain for transactions. + /// @notice This function can only be called by the owner. + /// @param _destinationChainSelector The selector of the destination chain to be updated. + /// @param allowed The allowlist status to be set for the destination chain. + function allowlistDestinationChain( + uint64 _destinationChainSelector, + bool allowed + ) external onlyOwner { + allowlistedDestinationChains[_destinationChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a source chain + /// @notice This function can only be called by the owner. + /// @param _sourceChainSelector The selector of the source chain to be updated. + /// @param allowed The allowlist status to be set for the source chain. + function allowlistSourceChain( + uint64 _sourceChainSelector, + bool allowed + ) external onlyOwner { + allowlistedSourceChains[_sourceChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a sender for transactions. + /// @notice This function can only be called by the owner. + /// @param _sender The address of the sender to be updated. + /// @param allowed The allowlist status to be set for the sender. + function allowlistSender( + address _sender, + bool allowed + ) external onlyOwner { + allowlistedSenders[_sender] = allowed; + } + + /// @notice Sends data and transfer tokens to receiver on the destination chain. + /// @notice Pay for fees in LINK. + /// @dev Assumes your contract has sufficient LINK to pay for CCIP fees. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _text The string data to be sent. + /// @param _token token address. + /// @param _amount token amount. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayLINK( + uint64 _destinationChainSelector, + address _receiver, + string calldata _text, + address _token, + uint256 _amount + ) + external + onlyOwner + onlyAllowlistedDestinationChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + // address(linkToken) means fees are paid in LINK + Client.EVM2AnyMessage memory evm2AnyMessage = + _buildCCIPMessage(_receiver, _text, _token, _amount, address(s_linkToken)); + + // Initialize a router client instance to interact with cross-chain router + IRouterClient router = IRouterClient(this.getRouter()); + + // Get the fee required to send the CCIP message + uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); + + uint256 requiredLinkBalance; + if (_token == address(s_linkToken)) { + // Required LINK Balance is the sum of fees and amount to transfer, if the token to transfer is LINK + requiredLinkBalance = fees + _amount; + } else { + requiredLinkBalance = fees; + } + + uint256 linkBalance = s_linkToken.balanceOf(address(this)); + + if (requiredLinkBalance > linkBalance) { + revert NotEnoughBalance(linkBalance, requiredLinkBalance); + } + + // approve the Router to transfer LINK tokens on contract's behalf. It will spend the requiredLinkBalance + s_linkToken.approve(address(router), requiredLinkBalance); + + // If sending a token other than LINK, approve it separately + if (_token != address(s_linkToken)) { + uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); + if (_amount > tokenBalance) { + revert NotEnoughBalance(tokenBalance, _amount); + } + // approve the Router to spend tokens on contract's behalf. It will spend the amount of the given token + IERC20(_token).approve(address(router), _amount); + } + + // Send the message through the router and store the returned message ID + messageId = router.ccipSend(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit MessageSent( + messageId, _destinationChainSelector, _receiver, _text, _token, _amount, address(s_linkToken), fees + ); + + // Return the message ID + return messageId; + } + + /// @notice Sends data and transfer tokens to receiver on the destination chain. + /// @notice Pay for fees in native gas. + /// @dev Assumes your contract has sufficient native gas like ETH on Ethereum or POL on Polygon. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _text The string data to be sent. + /// @param _token token address. + /// @param _amount token amount. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayNative( + uint64 _destinationChainSelector, + address _receiver, + string calldata _text, + address _token, + uint256 _amount + ) + external + onlyOwner + onlyAllowlistedDestinationChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + // address(0) means fees are paid in native gas + Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(_receiver, _text, _token, _amount, address(0)); + + // Initialize a router client instance to interact with cross-chain router + IRouterClient router = IRouterClient(this.getRouter()); + + // Get the fee required to send the CCIP message + uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); + + if (fees > address(this).balance) { + revert NotEnoughBalance(address(this).balance, fees); + } + + // approve the Router to spend tokens on contract's behalf. It will spend the amount of the given token + IERC20(_token).approve(address(router), _amount); + + // Send the message through the router and store the returned message ID + messageId = router.ccipSend{value: fees}(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit MessageSent(messageId, _destinationChainSelector, _receiver, _text, _token, _amount, address(0), fees); + + // Return the message ID + return messageId; + } + + /** + * @notice Returns the details of the last CCIP received message. + * @dev This function retrieves the ID, text, token address, and token amount of the last received CCIP message. + * @return messageId The ID of the last received CCIP message. + * @return text The text of the last received CCIP message. + * @return tokenAddress The address of the token in the last CCIP received message. + * @return tokenAmount The amount of the token in the last CCIP received message. + */ + function getLastReceivedMessageDetails() + public + view + returns (bytes32 messageId, string memory text, address tokenAddress, uint256 tokenAmount) + { + return (s_lastReceivedMessageId, s_lastReceivedText, s_lastReceivedTokenAddress, s_lastReceivedTokenAmount); + } + + /// handle a received message + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) + internal + override + onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Make sure + // source chain and sender are allowlisted + + { + s_lastReceivedMessageId = any2EvmMessage.messageId; // fetch the messageId + s_lastReceivedText = abi.decode(any2EvmMessage.data, (string)); // abi-decoding of the sent text + // Expect one token to be transferred at once, but you can transfer several tokens. + s_lastReceivedTokenAddress = any2EvmMessage.destTokenAmounts[0].token; + s_lastReceivedTokenAmount = any2EvmMessage.destTokenAmounts[0].amount; + + emit MessageReceived( + any2EvmMessage.messageId, + any2EvmMessage.sourceChainSelector, // fetch the source chain identifier (aka selector) + abi.decode(any2EvmMessage.sender, (address)), // abi-decoding of the sender address, + abi.decode(any2EvmMessage.data, (string)), + any2EvmMessage.destTokenAmounts[0].token, + any2EvmMessage.destTokenAmounts[0].amount + ); + } + + /// @notice Construct a CCIP message. + /// @dev This function will create an EVM2AnyMessage struct with all the necessary information for programmable tokens + /// transfer. + /// @param _receiver The address of the receiver. + /// @param _text The string data to be sent. + /// @param _token The token to be transferred. + /// @param _amount The amount of the token to be transferred. + /// @param _feeTokenAddress The address of the token used for fees. Set address(0) for native gas. + /// @return Client.EVM2AnyMessage Returns an EVM2AnyMessage struct which contains information for sending a CCIP + /// message. + function _buildCCIPMessage( + address _receiver, + string calldata _text, + address _token, + uint256 _amount, + address _feeTokenAddress + ) private pure returns (Client.EVM2AnyMessage memory) { + // Set the token amounts + Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1); + tokenAmounts[0] = Client.EVMTokenAmount({token: _token, amount: _amount}); + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + return Client.EVM2AnyMessage({ + receiver: abi.encode(_receiver), // ABI-encoded receiver address + data: abi.encode(_text), // ABI-encoded string + tokenAmounts: tokenAmounts, // The amount and type of token being transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 200_000, // Gas limit for the callback on the destination chain + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender + }) + ), + // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees + feeToken: _feeTokenAddress + }); + } + + /// @notice Fallback function to allow the contract to receive Ether. + /// @dev This function has no function body, making it a default function for receiving Ether. + /// It is automatically called when Ether is sent to the contract without any data. + receive() external payable {} + + /// @notice Allows the contract owner to withdraw the entire balance of Ether from the contract. + /// @dev This function reverts if there are no funds to withdraw or if the transfer fails. + /// It should only be callable by the owner of the contract. + /// @param _beneficiary The address to which the Ether should be sent. + function withdraw( + address _beneficiary + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = address(this).balance; + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + // Attempt to send the funds, capturing the success status and discarding any return data + (bool sent,) = _beneficiary.call{value: amount}(""); + + // Revert if the send failed, with information about the attempted transfer + if (!sent) revert FailedToWithdrawEth(msg.sender, _beneficiary, amount); + } + + /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + /// @param _token The contract address of the ERC20 token to be withdrawn. + function withdrawToken( + address _beneficiary, + address _token + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = IERC20(_token).balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + IERC20(_token).safeTransfer(_beneficiary, amount); + } +} +``` + ### Deploy your contracts To use this contract: @@ -5681,6 +7518,566 @@ In this guide, you'll initiate a transaction from a smart contract on *Avalanche that for successful scenarios. </Aside> +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; +import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/// @title - A simple messenger contract for transferring/receiving tokens and data across chains. +/// @dev - This example shows how to recover tokens in case of revert +contract ProgrammableDefensiveTokenTransfers is CCIPReceiver, OwnerIsCreator { + using EnumerableMap for EnumerableMap.Bytes32ToUintMap; + using SafeERC20 for IERC20; + + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 requiredBalance); // Used to make sure contract has enough + // token balance + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error FailedToWithdrawEth(address owner, address target, uint256 value); // Used when the withdrawal of Ether fails. + error DestinationChainNotAllowlisted(uint64 destinationChainSelector); // Used when the destination chain has not been + // allowlisted by the contract owner. + error SourceChainNotAllowed(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by the + // contract owner. + error SenderNotAllowed(address sender); // Used when the sender has not been allowlisted by the contract owner. + error InvalidReceiverAddress(); // Used when the receiver address is 0. + error OnlySelf(); // Used when a function is called outside of the contract itself. + error ErrorCase(); // Used when simulating a revert during message processing. + error MessageNotFailed(bytes32 messageId); + + // Example error code, could have many different error codes. + enum ErrorCode { + // RESOLVED is first so that the default value is resolved. + RESOLVED, + // Could have any number of error codes here. + FAILED + } + + struct FailedMessage { + bytes32 messageId; + ErrorCode errorCode; + } + + // Event emitted when a message is sent to another chain. + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The text being sent. + // The token address that was transferred. + // The token amount that was transferred. + // the token address used to pay CCIP fees. + // The fees paid for sending the message. + event MessageSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address receiver, + string text, + address token, + uint256 tokenAmount, + address feeToken, + uint256 fees + ); + + // Event emitted when a message is received from another chain. + // The chain selector of the source chain. + // The address of the sender from the source chain. + // The text that was received. + // The token address that was transferred. + // The token amount that was transferred. + event MessageReceived( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed sourceChainSelector, + address sender, + string text, + address token, + uint256 tokenAmount + ); + + event MessageFailed(bytes32 indexed messageId, bytes reason); + event MessageRecovered(bytes32 indexed messageId); + + bytes32 private s_lastReceivedMessageId; // Store the last received messageId. + address private s_lastReceivedTokenAddress; // Store the last received token address. + uint256 private s_lastReceivedTokenAmount; // Store the last received amount. + string private s_lastReceivedText; // Store the last received text. + + // Mapping to keep track of allowlisted destination chains. + mapping(uint64 => bool) public allowlistedDestinationChains; + + // Mapping to keep track of allowlisted source chains. + mapping(uint64 => bool) public allowlistedSourceChains; + + // Mapping to keep track of allowlisted senders. + mapping(address => bool) public allowlistedSenders; + + IERC20 private s_linkToken; + + // The message contents of failed messages are stored here. + mapping(bytes32 messageId => Client.Any2EVMMessage contents) public s_messageContents; + + // Contains failed messages and their state. + EnumerableMap.Bytes32ToUintMap internal s_failedMessages; + + // This is used to simulate a revert in the processMessage function. + bool internal s_simRevert = false; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) CCIPReceiver(_router) { + s_linkToken = IERC20(_link); + } + + /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. + /// @param _destinationChainSelector The selector of the destination chain. + modifier onlyAllowlistedDestinationChain( + uint64 _destinationChainSelector + ) { + if (!allowlistedDestinationChains[_destinationChainSelector]) { + revert DestinationChainNotAllowlisted(_destinationChainSelector); + } + _; + } + + /// @dev Modifier that checks if the chain with the given sourceChainSelector is allowlisted and if the sender is + /// allowlisted. + /// @param _sourceChainSelector The selector of the destination chain. + /// @param _sender The address of the sender. + modifier onlyAllowlisted( + uint64 _sourceChainSelector, + address _sender + ) { + if (!allowlistedSourceChains[_sourceChainSelector]) { + revert SourceChainNotAllowed(_sourceChainSelector); + } + if (!allowlistedSenders[_sender]) revert SenderNotAllowed(_sender); + _; + } + + /// @dev Modifier that checks the receiver address is not 0. + /// @param _receiver The receiver address. + modifier validateReceiver( + address _receiver + ) { + if (_receiver == address(0)) revert InvalidReceiverAddress(); + _; + } + + /// @dev Modifier to allow only the contract itself to execute a function. + /// Throws an exception if called by any account other than the contract itself. + modifier onlySelf() { + if (msg.sender != address(this)) revert OnlySelf(); + _; + } + + /// @dev Updates the allowlist status of a destination chain for transactions. + /// @notice This function can only be called by the owner. + /// @param _destinationChainSelector The selector of the destination chain to be updated. + /// @param allowed The allowlist status to be set for the destination chain. + function allowlistDestinationChain( + uint64 _destinationChainSelector, + bool allowed + ) external onlyOwner { + allowlistedDestinationChains[_destinationChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a source chain + /// @notice This function can only be called by the owner. + /// @param _sourceChainSelector The selector of the source chain to be updated. + /// @param allowed The allowlist status to be set for the source chain. + function allowlistSourceChain( + uint64 _sourceChainSelector, + bool allowed + ) external onlyOwner { + allowlistedSourceChains[_sourceChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a sender for transactions. + /// @notice This function can only be called by the owner. + /// @param _sender The address of the sender to be updated. + /// @param allowed The allowlist status to be set for the sender. + function allowlistSender( + address _sender, + bool allowed + ) external onlyOwner { + allowlistedSenders[_sender] = allowed; + } + + /// @notice Sends data and transfer tokens to receiver on the destination chain. + /// @notice Pay for fees in LINK. + /// @dev Assumes your contract has sufficient LINK to pay for CCIP fees. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _text The string data to be sent. + /// @param _token token address. + /// @param _amount token amount. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayLINK( + uint64 _destinationChainSelector, + address _receiver, + string calldata _text, + address _token, + uint256 _amount + ) + external + onlyOwner + onlyAllowlistedDestinationChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + // address(linkToken) means fees are paid in LINK + Client.EVM2AnyMessage memory evm2AnyMessage = + _buildCCIPMessage(_receiver, _text, _token, _amount, address(s_linkToken)); + + // Initialize a router client instance to interact with cross-chain router + IRouterClient router = IRouterClient(this.getRouter()); + + // Get the fee required to send the CCIP message + uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); + + uint256 requiredLinkBalance; + if (_token == address(s_linkToken)) { + // Required LINK Balance is the sum of fees and amount to transfer, if the token to transfer is LINK + requiredLinkBalance = fees + _amount; + } else { + requiredLinkBalance = fees; + } + + uint256 linkBalance = s_linkToken.balanceOf(address(this)); + + if (requiredLinkBalance > linkBalance) { + revert NotEnoughBalance(linkBalance, requiredLinkBalance); + } + + // approve the Router to transfer LINK tokens on contract's behalf. It will spend the requiredLinkBalance + s_linkToken.approve(address(router), requiredLinkBalance); + + // If sending a token other than LINK, approve it separately + if (_token != address(s_linkToken)) { + uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); + if (_amount > tokenBalance) { + revert NotEnoughBalance(tokenBalance, _amount); + } + // approve the Router to spend tokens on contract's behalf. It will spend the amount of the given token + IERC20(_token).approve(address(router), _amount); + } + + // Send the message through the router and store the returned message ID + messageId = router.ccipSend(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit MessageSent( + messageId, _destinationChainSelector, _receiver, _text, _token, _amount, address(s_linkToken), fees + ); + + // Return the message ID + return messageId; + } + + /// @notice Sends data and transfer tokens to receiver on the destination chain. + /// @notice Pay for fees in native gas. + /// @dev Assumes your contract has sufficient native gas like ETH on Ethereum or POL on Polygon. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _text The string data to be sent. + /// @param _token token address. + /// @param _amount token amount. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayNative( + uint64 _destinationChainSelector, + address _receiver, + string calldata _text, + address _token, + uint256 _amount + ) + external + onlyOwner + onlyAllowlistedDestinationChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + // address(0) means fees are paid in native gas + Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(_receiver, _text, _token, _amount, address(0)); + + // Initialize a router client instance to interact with cross-chain router + IRouterClient router = IRouterClient(this.getRouter()); + + // Get the fee required to send the CCIP message + uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); + + if (fees > address(this).balance) { + revert NotEnoughBalance(address(this).balance, fees); + } + + // approve the Router to spend tokens on contract's behalf. It will spend the amount of the given token + IERC20(_token).approve(address(router), _amount); + + // Send the message through the router and store the returned message ID + messageId = router.ccipSend{value: fees}(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit MessageSent(messageId, _destinationChainSelector, _receiver, _text, _token, _amount, address(0), fees); + + // Return the message ID + return messageId; + } + + /** + * @notice Returns the details of the last CCIP received message. + * @dev This function retrieves the ID, text, token address, and token amount of the last received CCIP message. + * @return messageId The ID of the last received CCIP message. + * @return text The text of the last received CCIP message. + * @return tokenAddress The address of the token in the last CCIP received message. + * @return tokenAmount The amount of the token in the last CCIP received message. + */ + function getLastReceivedMessageDetails() + public + view + returns (bytes32 messageId, string memory text, address tokenAddress, uint256 tokenAmount) + { + return (s_lastReceivedMessageId, s_lastReceivedText, s_lastReceivedTokenAddress, s_lastReceivedTokenAmount); + } + + /** + * @notice Retrieves a paginated list of failed messages. + * @dev This function returns a subset of failed messages defined by `offset` and `limit` parameters. It ensures that + * the pagination parameters are within the bounds of the available data set. + * @param offset The index of the first failed message to return, enabling pagination by skipping a specified number + * of messages from the start of the dataset. + * @param limit The maximum number of failed messages to return, restricting the size of the returned array. + * @return failedMessages An array of `FailedMessage` struct, each containing a `messageId` and an `errorCode` + * (RESOLVED or FAILED), representing the requested subset of failed messages. The length of the returned array is + * determined by the `limit` and the total number of failed messages. + */ + function getFailedMessages( + uint256 offset, + uint256 limit + ) external view returns (FailedMessage[] memory) { + uint256 length = s_failedMessages.length(); + + // Calculate the actual number of items to return (can't exceed total length or requested limit) + uint256 returnLength = (offset + limit > length) ? length - offset : limit; + FailedMessage[] memory failedMessages = new FailedMessage[](returnLength); + + // Adjust loop to respect pagination (start at offset, end at offset + limit or total length) + for (uint256 i = 0; i < returnLength; i++) { + (bytes32 messageId, uint256 errorCode) = s_failedMessages.at(offset + i); + failedMessages[i] = FailedMessage(messageId, ErrorCode(errorCode)); + } + return failedMessages; + } + + /// @notice The entrypoint for the CCIP router to call. This function should + /// never revert, all errors should be handled internally in this contract. + /// @param any2EvmMessage The message to process. + /// @dev Extremely important to ensure only router calls this. + function ccipReceive( + Client.Any2EVMMessage calldata any2EvmMessage + ) + external + override + onlyRouter + onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Make sure the + // source chain and sender are allowlisted + + { + /* solhint-disable no-empty-blocks */ + try this.processMessage(any2EvmMessage) { + // Intentionally empty in this example; no action needed if processMessage succeeds + } + catch (bytes memory err) { + // Could set different error codes based on the caught error. Each could be + // handled differently. + s_failedMessages.set(any2EvmMessage.messageId, uint256(ErrorCode.FAILED)); + s_messageContents[any2EvmMessage.messageId] = any2EvmMessage; + // Don't revert so CCIP doesn't revert. Emit event instead. + // The message can be retried later without having to do manual execution of CCIP. + emit MessageFailed(any2EvmMessage.messageId, err); + return; + } + } + + /// @notice Serves as the entry point for this contract to process incoming messages. + /// @param any2EvmMessage Received CCIP message. + /// @dev Transfers specified token amounts to the owner of this contract. This function + /// must be external because of the try/catch for error handling. + /// It uses the `onlySelf`: can only be called from the contract. + function processMessage( + Client.Any2EVMMessage calldata any2EvmMessage + ) + external + onlySelf + onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Make sure the + // source chain and sender are allowlisted + + { + // Simulate a revert for testing purposes + if (s_simRevert) revert ErrorCase(); + + _ccipReceive(any2EvmMessage); // process the message - may revert as well + } + + /// @notice Allows the owner to retry a failed message in order to unblock the associated tokens. + /// @param messageId The unique identifier of the failed message. + /// @param tokenReceiver The address to which the tokens will be sent. + /// @dev This function is only callable by the contract owner. It changes the status of the message + /// from 'failed' to 'resolved' to prevent reentry and multiple retries of the same message. + function retryFailedMessage( + bytes32 messageId, + address tokenReceiver + ) external onlyOwner { + // Check if the message has failed; if not, revert the transaction. + if (s_failedMessages.get(messageId) != uint256(ErrorCode.FAILED)) { + revert MessageNotFailed(messageId); + } + + // Set the error code to RESOLVED to disallow reentry and multiple retries of the same failed message. + s_failedMessages.set(messageId, uint256(ErrorCode.RESOLVED)); + + // Retrieve the content of the failed message. + Client.Any2EVMMessage memory message = s_messageContents[messageId]; + + // This example expects one token to have been sent, but you can handle multiple tokens. + // Transfer the associated tokens to the specified receiver as an escape hatch. + IERC20(message.destTokenAmounts[0].token).safeTransfer(tokenReceiver, message.destTokenAmounts[0].amount); + + // Emit an event indicating that the message has been recovered. + emit MessageRecovered(messageId); + } + + /// @notice Allows the owner to toggle simulation of reversion for testing purposes. + /// @param simRevert If `true`, simulates a revert condition; if `false`, disables the simulation. + /// @dev This function is only callable by the contract owner. + function setSimRevert( + bool simRevert + ) external onlyOwner { + s_simRevert = simRevert; + } + + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) internal override { + s_lastReceivedMessageId = any2EvmMessage.messageId; // fetch the messageId + s_lastReceivedText = abi.decode(any2EvmMessage.data, (string)); // abi-decoding of the sent text + // Expect one token to be transferred at once, but you can transfer several tokens. + s_lastReceivedTokenAddress = any2EvmMessage.destTokenAmounts[0].token; + s_lastReceivedTokenAmount = any2EvmMessage.destTokenAmounts[0].amount; + emit MessageReceived( + any2EvmMessage.messageId, + any2EvmMessage.sourceChainSelector, // fetch the source chain identifier (aka selector) + abi.decode(any2EvmMessage.sender, (address)), // abi-decoding of the sender address, + abi.decode(any2EvmMessage.data, (string)), + any2EvmMessage.destTokenAmounts[0].token, + any2EvmMessage.destTokenAmounts[0].amount + ); + } + + /// @notice Construct a CCIP message. + /// @dev This function will create an EVM2AnyMessage struct with all the necessary information for programmable tokens + /// transfer. + /// @param _receiver The address of the receiver. + /// @param _text The string data to be sent. + /// @param _token The token to be transferred. + /// @param _amount The amount of the token to be transferred. + /// @param _feeTokenAddress The address of the token used for fees. Set address(0) for native gas. + /// @return Client.EVM2AnyMessage Returns an EVM2AnyMessage struct which contains information for sending a CCIP + /// message. + function _buildCCIPMessage( + address _receiver, + string calldata _text, + address _token, + uint256 _amount, + address _feeTokenAddress + ) private pure returns (Client.EVM2AnyMessage memory) { + // Set the token amounts + Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1); + Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({token: _token, amount: _amount}); + tokenAmounts[0] = tokenAmount; + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({ + receiver: abi.encode(_receiver), // ABI-encoded receiver address + data: abi.encode(_text), // ABI-encoded string + tokenAmounts: tokenAmounts, // The amount and type of token being transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 400_000, // Gas limit for the callback on the destination chain + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender + }) + ), + // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees + feeToken: _feeTokenAddress + }); + return evm2AnyMessage; + } + + /// @notice Fallback function to allow the contract to receive Ether. + /// @dev This function has no function body, making it a default function for receiving Ether. + /// It is automatically called when Ether is sent to the contract without any data. + receive() external payable {} + + /// @notice Allows the contract owner to withdraw the entire balance of Ether from the contract. + /// @dev This function reverts if there are no funds to withdraw or if the transfer fails. + /// It should only be callable by the owner of the contract. + /// @param _beneficiary The address to which the Ether should be sent. + function withdraw( + address _beneficiary + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = address(this).balance; + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + // Attempt to send the funds, capturing the success status and discarding any return data + (bool sent,) = _beneficiary.call{value: amount}(""); + + // Revert if the send failed, with information about the attempted transfer + if (!sent) revert FailedToWithdrawEth(msg.sender, _beneficiary, amount); + } + + /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + /// @param _token The contract address of the ERC20 token to be withdrawn. + function withdrawToken( + address _beneficiary, + address _token + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = IERC20(_token).balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + IERC20(_token).safeTransfer(_beneficiary, amount); + } +} +``` + ### Deploy your contracts To use this contract: @@ -6005,7 +8402,7 @@ If you have existing token(s) that you've already deployed, you can use the Toke Before selecting a token pool type, be sure to review [CCIP token handling mechanisms](/ccip/concepts/cross-chain-token/overview#token-handling-mechanisms). -3. On the **Networks** page, select the additional blockchain networks where you'd like to deploy your new token. For additional networks, Token Manager Wizard workflow automatically configures all tokens with the Burn & Mint mechanism. (Refer to the [token contract](https://github.com/smartcontractkit/chainlink/blob/contracts-ccip/v1.6.0-beta.0/contracts/src/v0.8/ccip/tokenAdminRegistry/TokenPoolFactory/FactoryBurnMintERC20.sol) and [token pool contract](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/src/v0.8/ccip/pools/BurnMintTokenPool.sol) for the Burn & Mint mechanism.) +3. On the **Networks** page, select the additional blockchain networks where you'd like to deploy your new token. For additional networks, Token Manager Wizard workflow automatically configures all tokens with the Burn & Mint mechanism. (Refer to the [token contract](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) and [token pool contract](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-v1.6.1/chains/evm/contracts/pools/BurnMintTokenPool.sol) for the Burn & Mint mechanism.) 4. On the **Summary** page, each network you've selected appears along with an expandable list of the transactions the Token Manager will guide you through to deploy your token for each network. @@ -6401,7 +8798,7 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y ## Before you begin -1. [Install Node.js 18](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 18`. +1. [Install Node.js 22](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 22`. ```shell node -v @@ -6409,7 +8806,7 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y ```shell $ node -v - v18.7.0 + v22.15.0 ``` 2. Your [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) must have both AVAX and LINK tokens on *Avalanche Fuji* to pay for the gas fees and CCIP fees. @@ -6767,7 +9164,6 @@ These tutorials demonstrate how to use [CCIP Tools](https://github.com/smartcont - [Transfer Tokens Between EOAs](/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa): Learn how to transfer tokens between Externally Owned Accounts (EOAs) across different blockchains using Chainlink CCIP. - [Check CCIP Message Status Off-Chain](/ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain): Learn how to verify the status of Chainlink CCIP messages off-chain. -- [Get Supported Tokens](/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens): Learn how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP. --- @@ -6786,7 +9182,7 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y ## Before you begin -1. [Install Node.js 18](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 18`. +1. [Install Node.js 22](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 22`. ```shell node -v @@ -6794,14 +9190,14 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y ```shell $ node -v - v18.7.0 + v22.15.0 ``` 2. Your [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) must have both AVAX and LINK tokens on *Avalanche Fuji* to pay for the gas fees and CCIP fees. - [Configure MetaMask to use LINK tokens](/resources/acquire-link#configure-metamask-to-use-link-tokens) - Acquire testnet AVAX and LINK from [faucets.chain.link/fuji](https://faucets.chain.link/fuji) -3. Check the [CCIP Directory](/ccip/directory) to confirm that the tokens you will transfer are supported for your lane. In this example, you will transfer tokens from *Avalanche Fuji* to *Ethereum Sepolia* so check the list of supported tokens [here](/ccip/directory/testnet/chain/avalanche-fuji-testnet). Alternatively, you can use the [Get Supported Tokens](/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens) tutorial to retrieve the list of supported tokens programmatically. +3. Check the [CCIP Directory](/ccip/directory) to confirm that the tokens you will transfer are supported for your lane. In this example, you will transfer tokens from *Avalanche Fuji* to *Ethereum Sepolia* so check the list of supported tokens [here](/ccip/directory/testnet/chain/avalanche-fuji-testnet). 4. Learn how to [acquire CCIP test tokens](/ccip/test-tokens#evm-chains). After following this guide, your [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) should have CCIP-BnM tokens, and CCIP-BnM should appear in the list of your tokens in MetaMask. @@ -6821,7 +9217,7 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y 7. To make sure that the installation is correct and the `ccip-tools` CLI commands are available, run the following command: ```shell - ./dist/ccip-tools-ts --help + ./ccip-cli/ccip-cli --help ``` 8. Inside the project's root folder, i.e., `ccip-tools-ts`, create a `.env` file and add two environment variables to store the RPC URLs: @@ -6856,7 +9252,7 @@ In this example, you will transfer CCIP-BnM tokens from your EOA on *Avalanche F For this example, CCIP fees are paid in LINK tokens. To learn how to pay CCIP fees in native AVAX, read the [Pay in native](#transfer-tokens-and-pay-in-native) section. To transfer tokens and pay in LINK, use the following command: ``` -./src/index.ts send <source> <router> <dest> \ +./ccip-cli/ccip-cli send <source> <router> <dest> \ --receiver <destinationAccount> \ --fee-token <feeTokenAddress> \ --transfer-tokens <tokenAddress>=<amount> @@ -6867,7 +9263,7 @@ For this example, CCIP fees are paid in LINK tokens. To learn how to pay CCIP fe If you have Foundry installed and have imported your private key into an encrypted keystore using the [`cast wallet import`](https://book.getfoundry.sh/reference/cast/cast-wallet-import) command, you can pass the path to that keystore file as the value of the `--wallet` flag in your command, like this: ``` - ./src/index.ts send <source> <router> <dest> \ + ./ccip-cli/ccip-cli send <source> <router> <dest> \ --receiver <destinationAccount> \ --fee-token <feeTokenAddress> \ --transfer-tokens <tokenAddress>=<amount> \ @@ -6888,7 +9284,7 @@ For this example, CCIP fees are paid in LINK tokens. To learn how to pay CCIP fe For example, `43113` for *Avalanche Fuji* or `11155111` for *Ethereum Sepolia*. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. You can find the supported network names and chain IDs that can be used for `source` in the - [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/src/lib/selectors.ts) file of the + [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-sdk/src/selectors.ts) file of the `ccip-tools` repository. - `router`: Router contract address on the source network. @@ -6898,7 +9294,7 @@ For this example, CCIP fees are paid in LINK tokens. To learn how to pay CCIP fe For example, `43113` for *Avalanche Fuji* or `11155111` for *Ethereum Sepolia*. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. You can find the supported network names and chain IDs that can be used for `dest` in the - [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/src/lib/selectors.ts) file of the + [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-sdk/src/selectors.ts) file of the `ccip-tools` repository. - `destinationAccount`: Address of the destination account on the destination network. Skip this argument to use the same address as the source account. @@ -6918,7 +9314,7 @@ Complete the following steps in your terminal: 1. Send 0.001 CCIP-BnM from your EOA on *Avalanche Fuji* to another account on *Ethereum Sepolia*: ``` - ./src/index.ts send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ + ./ccip-cli/ccip-cli send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ --receiver 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf \ --fee-token 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 \ --transfer-tokens 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4=0.001 \ @@ -6929,7 +9325,7 @@ Complete the following steps in your terminal: | Argument | Explanation | | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | ./src/index.ts send | This executes the `send` command of the `ccip-tools`. | + | ./ccip-cli/ccip-cli send | This executes the `send` command of the `ccip-tools`. | | 43113 | This specifies the source blockchain, in this case, *Avalanche Fuji*. | | 0xF694E193200268f9a4868e4Aa017A0118C9a8177 | This specifies the router address on the source blockchain, in this case, *Avalanche Fuji*. | | 11155111 | This specifies the destination blockchain, which is *Ethereum Sepolia* in this case. | @@ -6945,15 +9341,14 @@ Complete the following steps in your terminal: 2. Once you execute the command, you should see the following logs: ``` - $ ./src/index.ts send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ + $ ./ccip-cli/ccip-cli send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ --receiver 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf \ --fee-token 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 \ --transfer-tokens 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4=0.001 \ --gas-limit 0 - Approving 1000000000000000n 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 for 0xF694E193200268f9a4868e4Aa017A0118C9a8177 = 0xa3fd8053a74b71f34c4c280f10fdcba51ea105093998f8349db14485473da912 - Approving 23112499163862214n 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 for 0xF694E193200268f9a4868e4Aa017A0118C9a8177 = 0xb21d2822c7211a6bd39310ae78f4b59ef54ed6271fea21c949d9be78a30f12a7 - Sending message to 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf @ ethereum-testnet-sepolia , tx_hash = 0x70858cfeadcfbd1404a65dd4116b549801bde3d184eb324f895529286e15249a + Fee: 133133029529487157n = 0.133133029529487157 LINK + 🚀 Sending message to 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf @ ethereum-testnet-sepolia , tx => 0x76a472470de779bef81843abeb3e1d0541bf35d63f23b3229857638764f3e149 , messageId => 0xf6ae12f8cf81d389613a8de82b1fd1b39542a2c99a58a1c580be7b8dc0603f9d Lane: ┌────────────────┬──────────────────────────────────────────────┬────────────────────────────┐ │ (index) │ source │ dest │ @@ -6967,21 +9362,22 @@ Complete the following steps in your terminal: ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ - │ messageId │ '0x934f57925b5d8fbc763c2a06dfe2d003676816f8ea67392d3e7888a45469d4c1' │ + │ messageId │ '0xf6ae12f8cf81d389613a8de82b1fd1b39542a2c99a58a1c580be7b8dc0603f9d' │ │ origin │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ sender │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ receiver │ '0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf' │ - │ sequenceNumber │ 3859 │ - │ nonce │ 17 │ - │ gasLimit │ 0 │ - │ transactionHash │ '0x70858cfeadcfbd1404a65dd4116b549801bde3d184eb324f895529286e15249a' │ - │ logIndex │ 6 │ - │ blockNumber │ 41234897 │ - │ timestamp │ '2025-06-02 16:19:51 (10s ago)' │ + │ sequenceNumber │ 7388n │ + │ nonce │ 21n │ + │ gasLimit │ 0n │ + │ transactionHash │ '0x76a472470de779bef81843abeb3e1d0541bf35d63f23b3229857638764f3e149' │ + │ logIndex │ 14 │ + │ blockNumber │ 49144482 │ + │ timestamp │ '2025-12-16 14:31:03 (7s ago)' │ │ finalized │ true │ - │ fee │ '0.023112499163862214 LINK' │ + │ fee │ '0.133133029529487157 LINK' │ │ tokens │ '0.001 CCIP-BnM' │ │ data │ '0x' │ + │ strict │ false │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ ``` @@ -7007,7 +9403,7 @@ For this example, CCIP fees are paid in Avalanche Fuji's native AVAX. To learn h To transfer tokens and pay in native, use the following command: ``` -./src/index.ts send <source> <router> <dest> \ +./ccip-cli/ccip-cli send <source> <router> <dest> \ --receiver <destinationAccount> \ --transfer-tokens <tokenAddress>=<amount> \ --gas-limit 0 @@ -7017,7 +9413,7 @@ To transfer tokens and pay in native, use the following command: If you have Foundry installed and have imported your private key into an encrypted keystore using the [`cast wallet import`](https://book.getfoundry.sh/reference/cast/cast-wallet-import) command, you can pass the path to that keystore file as the value of the `--wallet` flag in your command, like this: ``` - ./src/index.ts send <source> <router> <dest> \ + ./ccip-cli/ccip-cli send <source> <router> <dest> \ --receiver <destinationAccount> \ --transfer-tokens <tokenAddress>=<amount> \ --gas-limit 0 \ @@ -7038,7 +9434,7 @@ Complete the following steps in your terminal: 1. Send 0.001 CCIP-BnM from your EOA on *Avalanche Fuji* to another account on *Ethereum Sepolia*: ``` - ./src/index.ts send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ + ./ccip-cli/ccip-cli send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ --receiver 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf \ --transfer-tokens 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4=0.001 \ --gas-limit 0 @@ -7048,7 +9444,7 @@ Complete the following steps in your terminal: | Argument | Explanation | | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | ./src/index.ts send | This executes the `send` command of the `ccip-tools`. | + | ./ccip-cli/ccip-cli send | This executes the `send` command of the `ccip-tools`. | | 43113 | This specifies the source blockchain, in this case, *Avalanche Fuji*. | | 0xF694E193200268f9a4868e4Aa017A0118C9a8177 | This specifies the router address on the source blockchain, in this case, *Avalanche Fuji*. | | 11155111 | This specifies the destination blockchain, which is *Ethereum Sepolia* in this case. | @@ -7062,13 +9458,13 @@ Complete the following steps in your terminal: 2. After you execute the command, you should see the following logs: ``` - $ ./src/index.ts send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ + $ ./ccip-cli/ccip-cli send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ --receiver 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf \ --transfer-tokens 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4=0.001 \ --gas-limit 0 - Approving 1000000000000000n 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 for 0xF694E193200268f9a4868e4Aa017A0118C9a8177 = 0x1ea6d165cf627fd4f6856520fc9afa2e08c4e04f79fd78bf7f4ef7da94692503 - Sending message to 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf @ ethereum-testnet-sepolia , tx_hash = 0x0a00f9240b6860e34a0664ad0aa8f8e86877d70b97e9787e08e270bea564edce + Fee: 104497184834156911n = 0.104497184834156911 AVAX + 🚀 Sending message to 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf @ ethereum-testnet-sepolia , tx => 0xcefd14da01d3d607ba98dae33b2941ef07499051eaa61e3a417b5734d91ad021 , messageId => 0xb9672cd93b24b9071c2eee11b27daca00dbdac58239c40bca06c23fbb172e992 Lane: ┌────────────────┬──────────────────────────────────────────────┬────────────────────────────┐ │ (index) │ source │ dest │ @@ -7082,21 +9478,22 @@ Complete the following steps in your terminal: ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ - │ messageId │ '0xd902134a69bff565005c354996386479f9b1204b1810f49e27abc8c413c64312' │ + │ messageId │ '0xb9672cd93b24b9071c2eee11b27daca00dbdac58239c40bca06c23fbb172e992' │ │ origin │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ sender │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ receiver │ '0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf' │ - │ sequenceNumber │ 3861 │ - │ nonce │ 18 │ - │ gasLimit │ 0 │ - │ transactionHash │ '0x0a00f9240b6860e34a0664ad0aa8f8e86877d70b97e9787e08e270bea564edce' │ - │ logIndex │ 11 │ - │ blockNumber │ 41235059 │ - │ timestamp │ '2025-06-02 16:25:12 (7s ago)' │ + │ sequenceNumber │ 7389n │ + │ nonce │ 22n │ + │ gasLimit │ 0n │ + │ transactionHash │ '0xcefd14da01d3d607ba98dae33b2941ef07499051eaa61e3a417b5734d91ad021' │ + │ logIndex │ 16 │ + │ blockNumber │ 49144702 │ + │ timestamp │ '2025-12-16 14:36:00 (6s ago)' │ │ finalized │ true │ - │ fee │ '0.019124641265363576 WAVAX' │ + │ fee │ '0.104497184834156911 WAVAX' │ │ tokens │ '0.001 CCIP-BnM' │ │ data │ '0x' │ + │ strict │ false │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ ``` @@ -7119,7 +9516,7 @@ Complete the following steps in your terminal: Source: https://docs.chain.link/ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain Last Updated: 2025-05-19 -In this tutorial, you will learn how to verify the status of a Chainlink CCIP transaction offchain using [CCIP Tools](https://github.com/smartcontractkit/ccip-tools-ts). Starting with a CCIP source transaction hash, you'll execute the [`show`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/README.md#show-default-command) command of the `ccip-tools` to query the current status of a cross-chain message. +In this tutorial, you will learn how to verify the status of a Chainlink CCIP transaction offchain using [CCIP Tools](https://github.com/smartcontractkit/ccip-tools-ts). Starting with a CCIP source transaction hash, you'll execute the [`show`](https://github.com/smartcontractkit/ccip-tools-ts/tree/main/ccip-cli#show-default-command) command of the `ccip-tools` to query the current status of a cross-chain message. ## Before you begin @@ -7128,7 +9525,7 @@ In this tutorial, you will learn how to verify the status of a Chainlink CCIP tr ## Tutorial -This tutorial shows you on how to check the status of a Chainlink CCIP transaction using the [`show`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/README.md#show-default-command) command of the `ccip-tools`. By supplying the command with the source transaction hash, you can verify the current status of your cross-chain message. +This tutorial shows you on how to check the status of a Chainlink CCIP transaction using the [`show`](https://github.com/smartcontractkit/ccip-tools-ts/tree/main/ccip-cli#show-default-command) command of the `ccip-tools`. By supplying the command with the source transaction hash, you can verify the current status of your cross-chain message. **Execute the script in your command line:** @@ -7142,7 +9539,7 @@ This tutorial shows you on how to check the status of a Chainlink CCIP transacti <Aside type="note" title="Note"> The `--page` option is used to limit the number of blocks to search for the message. The default value is `10000` - which could result in an error due to RPC limitations. Setting it to `500` is a good practice to avoid such issues. + which could result in an error due to RPC limitations. Setting it to `10` is a good practice to avoid such issues. </Aside> **Example Usage:** @@ -7150,7 +9547,7 @@ This tutorial shows you on how to check the status of a Chainlink CCIP transacti If you initiated a transaction from *Avalanche Fuji* to *Ethereum Sepolia* and received the source transaction hash, you can check the status of your CCIP message with the following command: ```text -$ ./src/index.ts show 0x980dacf245f9c6919678219e97d6ad20e0c1964795ec3801e688315f1f18defd --page 500 +$ ./ccip-cli/ccip-cli show 0xcefd14da01d3d607ba98dae33b2941ef07499051eaa61e3a417b5734d91ad021 --page 10 Lane: ┌────────────────┬──────────────────────────────────────────────┬────────────────────────────┐ @@ -7165,227 +9562,59 @@ Request (source): ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ -│ messageId │ '0x1ce5213bf9880b18be7f44d5ab1065e603ec3a83eb1bebf76af366ed3c0de0b3' │ +│ messageId │ '0xb9672cd93b24b9071c2eee11b27daca00dbdac58239c40bca06c23fbb172e992' │ │ origin │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ sender │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ receiver │ '0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf' │ -│ sequenceNumber │ 3835 │ -│ nonce │ 4 │ -│ gasLimit │ 200000 │ -│ transactionHash │ '0x980dacf245f9c6919678219e97d6ad20e0c1964795ec3801e688315f1f18defd' │ -│ logIndex │ 6 │ -│ blockNumber │ 40954056 │ -│ timestamp │ '2025-05-26 16:34:14 (2h8m33s ago)' │ +│ sequenceNumber │ 7389n │ +│ nonce │ 22n │ +│ gasLimit │ 0n │ +│ transactionHash │ '0xcefd14da01d3d607ba98dae33b2941ef07499051eaa61e3a417b5734d91ad021' │ +│ logIndex │ 16 │ +│ blockNumber │ 49144702 │ +│ timestamp │ '2025-12-16 14:36:00 (24m4s ago)' │ │ finalized │ true │ -│ fee │ '0.040903083926519498 LINK' │ +│ fee │ '0.104497184834156911 WAVAX' │ │ tokens │ '0.001 CCIP-BnM' │ │ data │ '0x' │ +│ strict │ false │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ Commit (dest): ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ -│ merkleRoot │ '0x1ce5213bf9880b18be7f44d5ab1065e603ec3a83eb1bebf76af366ed3c0de0b3' │ -│ min │ 3835 │ -│ max │ 3835 │ -│ origin │ '0x9e587c646d4f4e46B71a02179Fa8951CFB34A382' │ +│ merkleRoot │ '0xb9672cd93b24b9071c2eee11b27daca00dbdac58239c40bca06c23fbb172e992' │ +│ min │ 7389 │ +│ max │ 7389 │ +│ origin │ '0x94193d65DF1f4834081B7F1aF1ecB11CFdECc608' │ │ contract │ '0x139E06b6dBB1a0C41A1686C091795879c943765A' │ -│ transactionHash │ '0xbda1e294e59910e2929e6aec08e52426a9125c1ac20509b9d5b9441789b746b0' │ -│ blockNumber │ 8411619 │ -│ timestamp │ '2025-05-26 16:35:00 (46s after request)' │ +│ transactionHash │ '0x57020e1a913451bb9e44190452252150158ae0d71ff117e2889cf0dc99c77cee' │ +│ blockNumber │ 9853657 │ +│ timestamp │ '2025-12-16 14:36:48 (48s after request)' │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ Receipts (dest): ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ │ state │ '✅ success' │ -│ returnData │ '0x' │ -│ origin │ '0xdA743Ce0Eb7cC541093F030A3126bF9e3d427E93' │ -│ offRamp │ '0x1DEBa99dC8e2A77832461BD386d83D9FCb133137' │ -│ transactionHash │ '0xe68ae80ed0b77d6e22f066a08c169c873dd22112ef5f27287bbe85e737c6ec60' │ -│ logIndex │ 114 │ -│ blockNumber │ 8411627 │ -│ timestamp │ '2025-05-26 16:36:36 (2m22s after request)' │ +│ origin │ '0x9Fa36294177c7adf9df4cC35fFcF0f47Dd3468D9' │ +│ contract │ '0x1DEBa99dC8e2A77832461BD386d83D9FCb133137' │ +│ transactionHash │ '0x38b5edcc7b7fc24a97120b5ac57f8023308784a5a97c92c251d3a67886197630' │ +│ logIndex │ 3 │ +│ blockNumber │ 9853664 │ +│ timestamp │ '2025-12-16 14:38:12 (2m12s after request)' │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ ``` --- -# Get Supported Tokens -Source: https://docs.chain.link/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens -Last Updated: 2025-05-19 - -In this tutorial, you will learn how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP, with [CCIP Tools](https://github.com/smartcontractkit/ccip-tools-ts). You'll use the [`getSupportedTokens`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/README.md#getsupportedtokens) command of `ccip-tools` to query the list of supported tokens that can be transferred from a specific source chain to a specific destination chain. - -## Before you begin - -Complete the prerequisite steps of the [Transfer Tokens between EOAs](/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa#before-you-begin) tutorial. - -## Tutorial - -This tutorial shows you how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP. By supplying the [`getSupportedTokens`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/README.md#getsupportedtokens) command of `ccip-tools` with a source chain, source router address, and a destination chain, you can get the list of supported tokens that can be transferred from the source chain to the destination chain. - -**Execute the script in your command line:** - -```bash -./src/index.ts getSupportedTokens <source> <router> <dest> -``` - -**The script requires the following parameters:** - -- `source`: Chain ID or network name. - - For example, `43113` for *Avalanche Fuji* or `11155111` for *Ethereum Sepolia*. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. - - You can find the supported network names and chain IDs that can be used for `source` in the - [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/src/lib/selectors.ts) file of the - `ccip-tools` repository. - -- `router`: Router contract address on the source network. - - You can find the router contract address in the [CCIP Directory](https://docs.chain.link/ccip/directory) by searching for the relevant network. - -- `dest`: Chain ID or network name. - - For example, `43113` for *Avalanche Fuji* or `11155111` for *Ethereum Sepolia*. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. - - You can find the supported network names and chain IDs that can be used for `dest` in the - [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/src/lib/selectors.ts) file of the - `ccip-tools` repository. - -**Example Usage:** - -If you would like to retrieve the list of supported tokens that can be transferred from *Avalanche Fuji* to *Ethereum Sepolia*, you can run the following command: - -```text -$ ./src/index.ts getSupportedTokens 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 - -[INFO] Starting token discovery for cross-chain transfers -[INFO] Using TokenAdminRegistry 1.5.0 at 0xA92053a4a3922084d992fD2835bdBa4caC6877e6 from router 0xF694E193200268f9a4868e4Aa017A0118C9a8177 -┌────────────────────────────────────┬──────────────────────────────────────────────┐ -│ (index) │ Values │ -├────────────────────────────────────┼──────────────────────────────────────────────┤ -│ address │ '0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4' │ -│ symbol │ 'CCIP-BnM' │ -│ name │ 'CCIP-BnM' │ -│ decimals │ 18 │ -│ pool │ '0x10e3A37ff21c20CD802fdAF0204e2Ff04e5485ee' │ -│ pool.typeAndVersion │ 'BurnMintTokenPool 1.5.1' │ -│ remoteToken │ '0xFd57b4ddBf88a4e07fF4e34C487b99af2Fe82a05' │ -│ remotePools │ '0x4CcbDd6CF18800360161E4D2A519A2047176bDF0' │ -│ rateLimiters.outbound.tokens │ '100000.0' │ -│ rateLimiters.outbound.capacity │ '100000.0' │ -│ rateLimiters.outbound.rate │ '167.0' │ -│ rateLimiters.outbound.timeToRefill │ '9m58s' │ -│ rateLimiters.inbound.tokens │ '100000.0' │ -│ rateLimiters.inbound.capacity │ '100000.0' │ -│ rateLimiters.inbound.rate │ '167.0' │ -│ rateLimiters.inbound.timeToRefill │ '9m58s' │ -└────────────────────────────────────┴──────────────────────────────────────────────┘ -┌────────────────────────────────────┬──────────────────────────────────────────────┐ -│ (index) │ Values │ -├────────────────────────────────────┼──────────────────────────────────────────────┤ -│ address │ '0x70F5c5C40b873EA597776DA2C21929A8282A3b35' │ -│ symbol │ 'clCCIP-LnM' │ -│ name │ 'clCCIP-LnM' │ -│ decimals │ 18 │ -│ pool │ '0x8e35eB0dfb39Ec5F84254C3f863986a913171E0B' │ -│ pool.typeAndVersion │ 'BurnMintTokenPoolAndProxy 1.5.0' │ -│ remoteToken │ '0x466D489b6d36E7E3b824ef491C225F5830E81cC1' │ -│ remotePools │ '0x658FdaC59a197D5166151640b7a673F7dF1Ba324' │ -│ rateLimiters.outbound.tokens │ '100000.0' │ -│ rateLimiters.outbound.capacity │ '100000.0' │ -│ rateLimiters.outbound.rate │ '167.0' │ -│ rateLimiters.outbound.timeToRefill │ '9m58s' │ -│ rateLimiters.inbound.tokens │ '100000.0' │ -│ rateLimiters.inbound.capacity │ '100000.0' │ -│ rateLimiters.inbound.rate │ '167.0' │ -│ rateLimiters.inbound.timeToRefill │ '9m58s' │ -└────────────────────────────────────┴──────────────────────────────────────────────┘ -┌────────────────────────────────────┬──────────────────────────────────────────────┐ -│ (index) │ Values │ -├────────────────────────────────────┼──────────────────────────────────────────────┤ -│ address │ '0x5425890298aed601595a70AB815c96711a31Bc65' │ -│ symbol │ 'USDC' │ -│ name │ 'USD Coin' │ -│ decimals │ 6 │ -│ pool │ '0x5931822f394baBC2AACF4588E98FC77a9f5aa8C9' │ -│ pool.typeAndVersion │ 'USDCTokenPool 1.5.1' │ -│ remoteToken │ '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' │ -│ remotePools[0] │ '0xb48EacF882dC4899Ae750AF4a6E2892E11866d8D' │ -│ remotePools[1] │ '0xAff3fE524ea94118EF09DaDBE3c77ba6AA0005EC' │ -│ rateLimiters.outbound.tokens │ '100000.0' │ -│ rateLimiters.outbound.capacity │ '100000.0' │ -│ rateLimiters.outbound.rate │ '167.0' │ -│ rateLimiters.outbound.timeToRefill │ '9m58s' │ -│ rateLimiters.inbound.tokens │ '100000.0' │ -│ rateLimiters.inbound.capacity │ '100000.0' │ -│ rateLimiters.inbound.rate │ '167.0' │ -│ rateLimiters.inbound.timeToRefill │ '9m58s' │ -└────────────────────────────────────┴──────────────────────────────────────────────┘ -...... -...... -...... -┌───────────────────────┬──────────────────────────────────────────────┐ -│ (index) │ Values │ -├───────────────────────┼──────────────────────────────────────────────┤ -│ address │ '0x838AB8F15867440A41C4149bcbba6ae402EfAd38' │ -│ symbol │ 'USDf' │ -│ name │ 'Falcon USD' │ -│ decimals │ 18 │ -│ pool │ '0x8210c0634AB8f273806e4b7866E9Db353773c44B' │ -│ pool.typeAndVersion │ 'BurnMintTokenPool 1.5.1' │ -│ remoteToken │ '0x3E34bFC2872534C331b6db2E4b3593FA7eaEddFd' │ -│ remotePools │ '0x21017CEC5f89fEb2c4B0F6C114E55Fa8EFDB00f2' │ -│ rateLimiters.outbound │ 'disabled' │ -│ rateLimiters.inbound │ 'disabled' │ -└───────────────────────┴──────────────────────────────────────────────┘ -┌───────────────────────┬──────────────────────────────────────────────┐ -│ (index) │ Values │ -├───────────────────────┼──────────────────────────────────────────────┤ -│ address │ '0xDA89A6C2c9f6E8d94E4a65d8AEe482908e9D709A' │ -│ symbol │ 'CCTWT' │ -│ name │ 'CCT Wizard Token' │ -│ decimals │ 18 │ -│ pool │ '0x3cD3CFAFb82a1Fd711753bb1a51F06a284bbd972' │ -│ pool.typeAndVersion │ 'BurnMintTokenPool 1.5.1' │ -│ remoteToken │ '0x74Ef0b124f192e0990B5451Ad12A4EC20FCf2B44' │ -│ remotePools │ '0x4dC3aA202138B40CC15867f2ab59153cF6FF83c4' │ -│ rateLimiters.outbound │ 'disabled' │ -│ rateLimiters.inbound │ 'disabled' │ -└───────────────────────┴──────────────────────────────────────────────┘ -┌───────────────────────┬──────────────────────────────────────────────┐ -│ (index) │ Values │ -├───────────────────────┼──────────────────────────────────────────────┤ -│ address │ '0x9BDdEBA9B0c051Ad5C1819D2F2671Af8B4D360B3' │ -│ symbol │ 'TT1' │ -│ name │ 'Test Token 1' │ -│ decimals │ 18 │ -│ pool │ '0x4Fc3534dEB27Bb61AfFFC5c02222594aF3024A61' │ -│ pool.typeAndVersion │ 'BurnMintTokenPool 1.5.1' │ -│ remoteToken │ '0x0325d145398Eeb977a55B39CC7847C48b84D93f5' │ -│ remotePools │ '0x0020267Ef0F96666A8CA236DB592547b14106807' │ -│ rateLimiters.outbound │ 'disabled' │ -│ rateLimiters.inbound │ 'disabled' │ -└───────────────────────┴──────────────────────────────────────────────┘ -Summary: totalTokens = 1070 , supportedTokens = 196 -``` - -<Aside type="note" title="Note"> - The `totalTokens` value represents the complete number of tokens registered or recognized by the system, regardless of their current usability for cross-chain transfers. In contrast, `supportedTokens` refers specifically to the subset of tokens that are currently eligible and configured for cross-chain transfers—meaning they have the necessary pools, remote mappings, and rate limiters set up. - - The difference between these numbers exists because not all tokens in the registry are ready or enabled for cross-chain operations. Some tokens may be inactive, lack required configuration, or are intentionally excluded from cross-chain support for security or operational reasons. As a result, `supportedTokens` is typically less than `totalTokens`. -</Aside> - ---- - # Cross-Chain Token (CCT) Tutorials Source: https://docs.chain.link/ccip/tutorials/evm/cross-chain-tokens Last Updated: 2025-05-19 <Aside type="note" title="Prerequisites"> Familiarize yourself with the [CCT standard](/ccip/concepts/cross-chain-token/overview) and [CCIP - architecture](/ccip/concepts/architecture) before proceeding with these tutorials. + architecture](/ccip/concepts/architecture/overview) before proceeding with these tutorials. </Aside> Before diving into the [tutorials](#tutorials), it's important first to understand the overall procedure for enabling your tokens in CCIP. This procedure involves deploying tokens and token pools, registering administrative roles, and configuring token pools to enable secure token transfers using CCIP. The diagram below outlines the entire process: @@ -10713,7 +12942,7 @@ Chainlink CCIP maintains a consistent [API](/ccip/api-reference/evm/v1.6.1/i-rou - The sender has to interact with the CCIP router to initiate a cross-chain transaction, similar to the process for any other token transfers. See the [Transfer Tokens](/ccip/tutorials/evm/transfer-tokens-from-contract) guide to learn more. - The process uses the same onchain components including the Router, OnRamp, Commit Store, OffRamp, and Token Pool. - The process uses the same offchain components including the Committing DON, Executing DON, and the Risk Management Network. -- USDC transfers also benefit from CCIP additional security provided by the [Risk Management Network](/ccip/concepts/architecture/key-concepts#risk-management-network). +- USDC transfers also benefit from CCIP additional security provided by the Risk Management Network. #### Native USDC (CCTP-enabled) @@ -10941,6 +13170,252 @@ The smart contracts featured in this tutorial are designed to interact with CCIP ### Sender Contract +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; + +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +interface IStaker { + function stake( + address beneficiary, + uint256 amount + ) external; + + function redeem() external; +} + +/// @title - A simple messenger contract for transferring tokens to a receiver that calls a staker contract. +contract Sender is OwnerIsCreator { + using SafeERC20 for IERC20; + + // Custom errors to provide more descriptive revert messages. + error InvalidRouter(); // Used when the router address is 0 + error InvalidLinkToken(); // Used when the link token address is 0 + error InvalidUsdcToken(); // Used when the usdc token address is 0 + error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough + // balance to cover the fees. + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error InvalidDestinationChain(); // Used when the destination chain selector is 0. + error InvalidReceiverAddress(); // Used when the receiver address is 0. + error NoReceiverOnDestinationChain(uint64 destinationChainSelector); // Used when the receiver address is 0 for a + // given destination chain. + error AmountIsZero(); // Used if the amount to transfer is 0. + error InvalidGasLimit(); // Used if the gas limit is 0. + error NoGasLimitOnDestinationChain(uint64 destinationChainSelector); // Used when the gas limit is 0. + + // Event emitted when a message is sent to another chain. + // The chain selector of the destination chain. + // The address of the receiver contract on the destination chain. + // The beneficiary of the staked tokens on the destination chain. + // The token address that was transferred. + // The token amount that was transferred. + // the token address used to pay CCIP fees. + // The fees paid for sending the message. + event MessageSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address indexed receiver, + address beneficiary, + address token, + uint256 tokenAmount, + address feeToken, + uint256 fees + ); + + IRouterClient private immutable i_router; + IERC20 private immutable i_linkToken; + IERC20 private immutable i_usdcToken; + + // Mapping to keep track of the receiver contract per destination chain. + mapping(uint64 => address) public s_receivers; + // Mapping to store the gas limit per destination chain. + mapping(uint64 => uint256) public s_gasLimits; + + modifier validateDestinationChain( + uint64 _destinationChainSelector + ) { + if (_destinationChainSelector == 0) revert InvalidDestinationChain(); + _; + } + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + /// @param _usdcToken The address of the usdc contract. + constructor( + address _router, + address _link, + address _usdcToken + ) { + if (_router == address(0)) revert InvalidRouter(); + if (_link == address(0)) revert InvalidLinkToken(); + if (_usdcToken == address(0)) revert InvalidUsdcToken(); + i_router = IRouterClient(_router); + i_linkToken = IERC20(_link); + i_usdcToken = IERC20(_usdcToken); + } + + /// @dev Set the receiver contract for a given destination chain. + /// @notice This function can only be called by the owner. + /// @param _destinationChainSelector The selector of the destination chain. + /// @param _receiver The receiver contract on the destination chain . + function setReceiverForDestinationChain( + uint64 _destinationChainSelector, + address _receiver + ) external onlyOwner validateDestinationChain(_destinationChainSelector) { + if (_receiver == address(0)) revert InvalidReceiverAddress(); + s_receivers[_destinationChainSelector] = _receiver; + } + + /// @dev Set the gas limit for a given destination chain. + /// @notice This function can only be called by the owner. + /// @param _destinationChainSelector The selector of the destination chain. + /// @param _gasLimit The gas limit on the destination chain . + function setGasLimitForDestinationChain( + uint64 _destinationChainSelector, + uint256 _gasLimit + ) external onlyOwner validateDestinationChain(_destinationChainSelector) { + if (_gasLimit == 0) revert InvalidGasLimit(); + s_gasLimits[_destinationChainSelector] = _gasLimit; + } + + /// @dev Delete the receiver contract for a given destination chain. + /// @notice This function can only be called by the owner. + /// @param _destinationChainSelector The selector of the destination chain. + function deleteReceiverForDestinationChain( + uint64 _destinationChainSelector + ) external onlyOwner validateDestinationChain(_destinationChainSelector) { + if (s_receivers[_destinationChainSelector] == address(0)) { + revert NoReceiverOnDestinationChain(_destinationChainSelector); + } + delete s_receivers[_destinationChainSelector]; + } + + /// @notice Sends data and transfer tokens to receiver on the destination chain. + /// @notice Pay for fees in LINK. + /// @dev Assumes your contract has sufficient LINK to pay for CCIP fees. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _beneficiary The address of the beneficiary of the staked tokens on the destination blockchain. + /// @param _amount token amount. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayLINK( + uint64 _destinationChainSelector, + address _beneficiary, + uint256 _amount + ) external onlyOwner validateDestinationChain(_destinationChainSelector) returns (bytes32 messageId) { + address receiver = s_receivers[_destinationChainSelector]; + if (receiver == address(0)) { + revert NoReceiverOnDestinationChain(_destinationChainSelector); + } + if (_amount == 0) revert AmountIsZero(); + uint256 gasLimit = s_gasLimits[_destinationChainSelector]; + if (gasLimit == 0) { + revert NoGasLimitOnDestinationChain(_destinationChainSelector); + } + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + // address(linkToken) means fees are paid in LINK + Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1); + tokenAmounts[0] = Client.EVMTokenAmount({token: address(i_usdcToken), amount: _amount}); + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({ + receiver: abi.encode(receiver), // ABI-encoded receiver address + data: abi.encodeWithSelector(IStaker.stake.selector, _beneficiary, _amount), // Encode the function selector and + // the arguments of the stake function + tokenAmounts: tokenAmounts, // The amount and type of token being transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: gasLimit, // Gas limit for the callback on the destination chain + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender + }) + ), + // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees + feeToken: address(i_linkToken) + }); + + // Get the fee required to send the CCIP message + uint256 fees = i_router.getFee(_destinationChainSelector, evm2AnyMessage); + + if (fees > i_linkToken.balanceOf(address(this))) { + revert NotEnoughBalance(i_linkToken.balanceOf(address(this)), fees); + } + + // approve the Router to transfer LINK tokens on contract's behalf. It will spend the fees in LINK + i_linkToken.approve(address(i_router), fees); + + // approve the Router to spend usdc tokens on contract's behalf. It will spend the amount of the given token + i_usdcToken.approve(address(i_router), _amount); + + // Send the message through the router and store the returned message ID + messageId = i_router.ccipSend(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit MessageSent( + messageId, + _destinationChainSelector, + receiver, + _beneficiary, + address(i_usdcToken), + _amount, + address(i_linkToken), + fees + ); + + // Return the message ID + return messageId; + } + + /// @notice Allows the owner of the contract to withdraw all LINK tokens in the contract and transfer them to a + /// beneficiary. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + function withdrawLinkToken( + address _beneficiary + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = i_linkToken.balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + i_linkToken.safeTransfer(_beneficiary, amount); + } + + /// @notice Allows the owner of the contract to withdraw all usdc tokens in the contract and transfer them to a + /// beneficiary. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + function withdrawUsdcToken( + address _beneficiary + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = i_usdcToken.balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + i_usdcToken.safeTransfer(_beneficiary, amount); + } +} +``` + The Sender contract is responsible for initiating the transfer of USDC tokens and data. Here's how it works: 1. Initializing the contract: @@ -10971,6 +13446,80 @@ The Sender contract is responsible for initiating the transfer of USDC tokens an ### Staker Contract +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +interface IStaker { + function stake( + address beneficiary, + uint256 amount + ) external; + + function redeem() external; +} + +/// @title - A simple Staker contract for staking usc tokens and redeeming the staker contracts +contract Staker is IStaker, ERC20 { + using SafeERC20 for ERC20; + + error InvalidUsdcToken(); // Used when the usdc token address is 0 + error InvalidNumberOfDecimals(); // Used when the number of decimals is 0 + error InvalidBeneficiary(); // Used when the beneficiary address is 0 + error InvalidAmount(); // Used when the amount is 0 + error NothingToRedeem(); // Used when the balance of Staker tokens is 0 + + event UsdcStaked(address indexed beneficiary, uint256 amount); + event UsdcRedeemed(address indexed beneficiary, uint256 amount); + + ERC20 private immutable i_usdcToken; + uint8 private immutable i_decimals; + + /// @notice Constructor initializes the contract with the usdc token address. + /// @param _usdcToken The address of the usdc contract. + constructor( + address _usdcToken + ) ERC20("Simple Staker", "STK") { + if (_usdcToken == address(0)) revert InvalidUsdcToken(); + i_usdcToken = ERC20(_usdcToken); + i_decimals = i_usdcToken.decimals(); + if (i_decimals == 0) revert InvalidNumberOfDecimals(); + } + + function stake( + address _beneficiary, + uint256 _amount + ) external { + if (_beneficiary == address(0)) revert InvalidBeneficiary(); + if (_amount == 0) revert InvalidAmount(); + + i_usdcToken.safeTransferFrom(msg.sender, address(this), _amount); + _mint(_beneficiary, _amount); + emit UsdcStaked(_beneficiary, _amount); + } + + function redeem() external { + uint256 balance = balanceOf(msg.sender); + if (balance == 0) revert NothingToRedeem(); + _burn(msg.sender, balance); + i_usdcToken.safeTransfer(msg.sender, balance); + emit UsdcRedeemed(msg.sender, balance); + } + + function decimals() public view override returns (uint8) { + return i_decimals; + } +} +``` + The Staker contract manages the staking and redemption of USDC tokens. Here's how it works: 1. Initializing the contract: @@ -10987,6 +13536,256 @@ The Staker contract manages the staking and redemption of USDC tokens. Here's ho ### Receiver Contract +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/// @title - A simple receiver contract for receiving usdc tokens then calling a staking contract. +contract Receiver is CCIPReceiver, OwnerIsCreator { + using SafeERC20 for IERC20; + using EnumerableMap for EnumerableMap.Bytes32ToUintMap; + + error InvalidUsdcToken(); // Used when the usdc token address is 0 + error InvalidStaker(); // Used when the staker address is 0 + error InvalidSourceChain(); // Used when the source chain is 0 + error InvalidSenderAddress(); // Used when the sender address is 0 + error NoSenderOnSourceChain(uint64 sourceChainSelector); // Used when there is no sender for a given source chain + error WrongSenderForSourceChain(uint64 sourceChainSelector); // Used when the sender contract is not the correct one + error OnlySelf(); // Used when a function is called outside of the contract itself + error WrongReceivedToken(address usdcToken, address receivedToken); // Used if the received token is different than + // usdc token + error CallToStakerFailed(); // Used when the call to the stake function of the staker contract is not successful + error NoReturnDataExpected(); // Used if the call to the stake function of the staker contract returns data. This is + // not expected + error MessageNotFailed(bytes32 messageId); // Used if you try to retry a message that has no failed + + // Event emitted when a message is received from another chain. + // The chain selector of the source chain. + // The address of the sender from the source chain. + // The data that was received. + // The token address that was transferred. + // The token amount that was transferred. + event MessageReceived( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed sourceChainSelector, + address indexed sender, + bytes data, + address token, + uint256 tokenAmount + ); + + event MessageFailed(bytes32 indexed messageId, bytes reason); + event MessageRecovered(bytes32 indexed messageId); + + // Example error code, could have many different error codes. + enum ErrorCode { + // RESOLVED is first so that the default value is resolved. + RESOLVED, + // Could have any number of error codes here. + FAILED + } + + struct FailedMessage { + bytes32 messageId; + ErrorCode errorCode; + } + + IERC20 private immutable i_usdcToken; + address private immutable i_staker; + + // Mapping to keep track of the sender contract per source chain. + mapping(uint64 => address) public s_senders; + + // The message contents of failed messages are stored here. + mapping(bytes32 => Client.Any2EVMMessage) public s_messageContents; + + // Contains failed messages and their state. + EnumerableMap.Bytes32ToUintMap internal s_failedMessages; + + modifier validateSourceChain( + uint64 _sourceChainSelector + ) { + if (_sourceChainSelector == 0) revert InvalidSourceChain(); + _; + } + + /// @dev Modifier to allow only the contract itself to execute a function. + /// Throws an exception if called by any account other than the contract itself. + modifier onlySelf() { + if (msg.sender != address(this)) revert OnlySelf(); + _; + } + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _usdcToken The address of the usdc contract. + /// @param _staker The address of the staker contract. + constructor( + address _router, + address _usdcToken, + address _staker + ) CCIPReceiver(_router) { + if (_usdcToken == address(0)) revert InvalidUsdcToken(); + if (_staker == address(0)) revert InvalidStaker(); + i_usdcToken = IERC20(_usdcToken); + i_staker = _staker; + i_usdcToken.approve(_staker, type(uint256).max); + } + + /// @dev Set the sender contract for a given source chain. + /// @notice This function can only be called by the owner. + /// @param _sourceChainSelector The selector of the source chain. + /// @param _sender The sender contract on the source chain . + function setSenderForSourceChain( + uint64 _sourceChainSelector, + address _sender + ) external onlyOwner validateSourceChain(_sourceChainSelector) { + if (_sender == address(0)) revert InvalidSenderAddress(); + s_senders[_sourceChainSelector] = _sender; + } + + /// @dev Delete the sender contract for a given source chain. + /// @notice This function can only be called by the owner. + /// @param _sourceChainSelector The selector of the source chain. + function deleteSenderForSourceChain( + uint64 _sourceChainSelector + ) external onlyOwner validateSourceChain(_sourceChainSelector) { + if (s_senders[_sourceChainSelector] == address(0)) { + revert NoSenderOnSourceChain(_sourceChainSelector); + } + delete s_senders[_sourceChainSelector]; + } + + /// @notice The entrypoint for the CCIP router to call. This function should + /// never revert, all errors should be handled internally in this contract. + /// @param any2EvmMessage The message to process. + /// @dev Extremely important to ensure only router calls this. + function ccipReceive( + Client.Any2EVMMessage calldata any2EvmMessage + ) external override onlyRouter { + // validate the sender contract + if (abi.decode(any2EvmMessage.sender, (address)) != s_senders[any2EvmMessage.sourceChainSelector]) { + revert WrongSenderForSourceChain(any2EvmMessage.sourceChainSelector); + } + /* solhint-disable no-empty-blocks */ + try this.processMessage(any2EvmMessage) { + // Intentionally empty in this example; no action needed if processMessage succeeds + } + catch (bytes memory err) { + // Could set different error codes based on the caught error. Each could be + // handled differently. + s_failedMessages.set(any2EvmMessage.messageId, uint256(ErrorCode.FAILED)); + s_messageContents[any2EvmMessage.messageId] = any2EvmMessage; + // Don't revert so CCIP doesn't revert. Emit event instead. + // The message can be retried later without having to do manual execution of CCIP. + emit MessageFailed(any2EvmMessage.messageId, err); + return; + } + } + + /// @notice Serves as the entry point for this contract to process incoming messages. + /// @param any2EvmMessage Received CCIP message. + /// @dev Transfers specified token amounts to the owner of this contract. This function + /// must be external because of the try/catch for error handling. + /// It uses the `onlySelf`: can only be called from the contract. + function processMessage( + Client.Any2EVMMessage calldata any2EvmMessage + ) external onlySelf { + _ccipReceive(any2EvmMessage); // process the message - may revert + } + + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) internal override { + if (any2EvmMessage.destTokenAmounts[0].token != address(i_usdcToken)) { + revert WrongReceivedToken(address(i_usdcToken), any2EvmMessage.destTokenAmounts[0].token); + } + + (bool success, bytes memory returnData) = i_staker.call(any2EvmMessage.data); // low level call to the staker + // contract using the encoded function selector and arguments + if (!success) revert CallToStakerFailed(); + if (returnData.length > 0) revert NoReturnDataExpected(); + emit MessageReceived( + any2EvmMessage.messageId, + any2EvmMessage.sourceChainSelector, // fetch the source chain identifier (aka selector) + abi.decode(any2EvmMessage.sender, (address)), // abi-decoding of the sender address, + any2EvmMessage.data, // received data + any2EvmMessage.destTokenAmounts[0].token, + any2EvmMessage.destTokenAmounts[0].amount + ); + } + + /// @notice Allows the owner to retry a failed message in order to unblock the associated tokens. + /// @param messageId The unique identifier of the failed message. + /// @param beneficiary The address to which the tokens will be sent. + /// @dev This function is only callable by the contract owner. It changes the status of the message + /// from 'failed' to 'resolved' to prevent reentry and multiple retries of the same message. + function retryFailedMessage( + bytes32 messageId, + address beneficiary + ) external onlyOwner { + // Check if the message has failed; if not, revert the transaction. + if (s_failedMessages.get(messageId) != uint256(ErrorCode.FAILED)) { + revert MessageNotFailed(messageId); + } + + // Set the error code to RESOLVED to disallow reentry and multiple retries of the same failed message. + s_failedMessages.set(messageId, uint256(ErrorCode.RESOLVED)); + + // Retrieve the content of the failed message. + Client.Any2EVMMessage memory message = s_messageContents[messageId]; + + // This example expects one token to have been sent. + // Transfer the associated tokens to the specified receiver as an escape hatch. + IERC20(message.destTokenAmounts[0].token).safeTransfer(beneficiary, message.destTokenAmounts[0].amount); + + // Emit an event indicating that the message has been recovered. + emit MessageRecovered(messageId); + } + + /// @notice Retrieves a paginated list of failed messages. + /// @dev This function returns a subset of failed messages defined by `offset` and `limit` parameters. It ensures that + /// the pagination parameters are within the bounds of the available data set. + /// @param offset The index of the first failed message to return, enabling pagination by skipping a specified number + /// of messages from the start of the dataset. + /// @param limit The maximum number of failed messages to return, restricting the size of the returned array. + /// @return failedMessages An array of `FailedMessage` struct, each containing a `messageId` and an `errorCode` + /// (RESOLVED or FAILED), representing the requested subset of failed messages. The length of the returned array is + /// determined by the `limit` and the total number of failed messages. + function getFailedMessages( + uint256 offset, + uint256 limit + ) external view returns (FailedMessage[] memory) { + uint256 length = s_failedMessages.length(); + + // Calculate the actual number of items to return (can't exceed total length or requested limit) + uint256 returnLength = (offset + limit > length) ? length - offset : limit; + FailedMessage[] memory failedMessages = new FailedMessage[](returnLength); + + // Adjust loop to respect pagination (start at offset, end at offset + limit or total length) + for (uint256 i = 0; i < returnLength; i++) { + (bytes32 messageId, uint256 errorCode) = s_failedMessages.at(offset + i); + failedMessages[i] = FailedMessage(messageId, ErrorCode(errorCode)); + } + return failedMessages; + } +} +``` + The Receiver contract handles incoming cross-chain messages, processes them, and interacts with the Staker contract to stake USDC on behalf of the beneficiary. Here's how it works: 1. Initializing the Contract: @@ -11061,6 +13860,341 @@ In this tutorial, you will use Chainlink CCIP to send data between smart contrac In this tutorial, you will send a *string* text between smart contracts on *Avalanche Fuji* and *Ethereum Sepolia* using CCIP. First, you will pay [CCIP fees in LINK](#send-data-and-pay-in-link), then you will pay [CCIP fees in native gas](#send-data-and-pay-in-native). +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; +import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/// @title - A simple messenger contract for sending/receiving string data across chains. +contract Messenger is CCIPReceiver, OwnerIsCreator { + using SafeERC20 for IERC20; + + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough + // balance. + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error FailedToWithdrawEth(address owner, address target, uint256 value); // Used when the withdrawal of Ether fails. + error DestinationChainNotAllowlisted(uint64 destinationChainSelector); // Used when the destination chain has not been + // allowlisted by the contract owner. + error SourceChainNotAllowlisted(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by + // the contract owner. + error SenderNotAllowlisted(address sender); // Used when the sender has not been allowlisted by the contract owner. + error InvalidReceiverAddress(); // Used when the receiver address is 0. + + // Event emitted when a message is sent to another chain. + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The text being sent. + // the token address used to pay CCIP fees. + // The fees paid for sending the CCIP message. + event MessageSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address receiver, + string text, + address feeToken, + uint256 fees + ); + + // Event emitted when a message is received from another chain. + event MessageReceived( // The unique ID of the CCIP message. + // The chain selector of the source chain. + // The address of the sender from the source chain. + // The text that was received. + bytes32 indexed messageId, + uint64 indexed sourceChainSelector, + address sender, + string text + ); + + bytes32 private s_lastReceivedMessageId; // Store the last received messageId. + string private s_lastReceivedText; // Store the last received text. + + // Mapping to keep track of allowlisted destination chains. + mapping(uint64 => bool) public allowlistedDestinationChains; + + // Mapping to keep track of allowlisted source chains. + mapping(uint64 => bool) public allowlistedSourceChains; + + // Mapping to keep track of allowlisted senders. + mapping(address => bool) public allowlistedSenders; + + IERC20 private s_linkToken; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) CCIPReceiver(_router) { + s_linkToken = IERC20(_link); + } + + /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. + /// @param _destinationChainSelector The selector of the destination chain. + modifier onlyAllowlistedDestinationChain( + uint64 _destinationChainSelector + ) { + if (!allowlistedDestinationChains[_destinationChainSelector]) { + revert DestinationChainNotAllowlisted(_destinationChainSelector); + } + _; + } + + /// @dev Modifier that checks if the chain with the given sourceChainSelector is allowlisted and if the sender is + /// allowlisted. + /// @param _sourceChainSelector The selector of the destination chain. + /// @param _sender The address of the sender. + modifier onlyAllowlisted( + uint64 _sourceChainSelector, + address _sender + ) { + if (!allowlistedSourceChains[_sourceChainSelector]) { + revert SourceChainNotAllowlisted(_sourceChainSelector); + } + if (!allowlistedSenders[_sender]) revert SenderNotAllowlisted(_sender); + _; + } + + /// @dev Modifier that checks the receiver address is not 0. + /// @param _receiver The receiver address. + modifier validateReceiver( + address _receiver + ) { + if (_receiver == address(0)) revert InvalidReceiverAddress(); + _; + } + + /// @dev Updates the allowlist status of a destination chain for transactions. + function allowlistDestinationChain( + uint64 _destinationChainSelector, + bool allowed + ) external onlyOwner { + allowlistedDestinationChains[_destinationChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a source chain for transactions. + function allowlistSourceChain( + uint64 _sourceChainSelector, + bool allowed + ) external onlyOwner { + allowlistedSourceChains[_sourceChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a sender for transactions. + function allowlistSender( + address _sender, + bool allowed + ) external onlyOwner { + allowlistedSenders[_sender] = allowed; + } + + /// @notice Sends data to receiver on the destination chain. + /// @notice Pay for fees in LINK. + /// @dev Assumes your contract has sufficient LINK. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _text The text to be sent. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayLINK( + uint64 _destinationChainSelector, + address _receiver, + string calldata _text + ) + external + onlyOwner + onlyAllowlistedDestinationChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(_receiver, _text, address(s_linkToken)); + + // Initialize a router client instance to interact with cross-chain router + IRouterClient router = IRouterClient(this.getRouter()); + + // Get the fee required to send the CCIP message + uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); + + if (fees > s_linkToken.balanceOf(address(this))) { + revert NotEnoughBalance(s_linkToken.balanceOf(address(this)), fees); + } + + // approve the Router to transfer LINK tokens on contract's behalf. It will spend the fees in LINK + s_linkToken.approve(address(router), fees); + + // Send the CCIP message through the router and store the returned CCIP message ID + messageId = router.ccipSend(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit MessageSent(messageId, _destinationChainSelector, _receiver, _text, address(s_linkToken), fees); + + // Return the CCIP message ID + return messageId; + } + + /// @notice Sends data to receiver on the destination chain. + /// @notice Pay for fees in native gas. + /// @dev Assumes your contract has sufficient native gas tokens. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _text The text to be sent. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayNative( + uint64 _destinationChainSelector, + address _receiver, + string calldata _text + ) + external + onlyOwner + onlyAllowlistedDestinationChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(_receiver, _text, address(0)); + + // Initialize a router client instance to interact with cross-chain router + IRouterClient router = IRouterClient(this.getRouter()); + + // Get the fee required to send the CCIP message + uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); + + if (fees > address(this).balance) { + revert NotEnoughBalance(address(this).balance, fees); + } + + // Send the CCIP message through the router and store the returned CCIP message ID + messageId = router.ccipSend{value: fees}(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit MessageSent(messageId, _destinationChainSelector, _receiver, _text, address(0), fees); + + // Return the CCIP message ID + return messageId; + } + + /// handle a received message + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) + internal + override + onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Make sure + // source chain and sender are allowlisted + + { + s_lastReceivedMessageId = any2EvmMessage.messageId; // fetch the messageId + s_lastReceivedText = abi.decode(any2EvmMessage.data, (string)); // abi-decoding of the sent text + + emit MessageReceived( + any2EvmMessage.messageId, + any2EvmMessage.sourceChainSelector, // fetch the source chain identifier (aka selector) + abi.decode(any2EvmMessage.sender, (address)), // abi-decoding of the sender address, + abi.decode(any2EvmMessage.data, (string)) + ); + } + + /// @notice Construct a CCIP message. + /// @dev This function will create an EVM2AnyMessage struct with all the necessary information for sending a text. + /// @param _receiver The address of the receiver. + /// @param _text The string data to be sent. + /// @param _feeTokenAddress The address of the token used for fees. Set address(0) for native gas. + /// @return Client.EVM2AnyMessage Returns an EVM2AnyMessage struct which contains information for sending a CCIP + /// message. + function _buildCCIPMessage( + address _receiver, + string calldata _text, + address _feeTokenAddress + ) private pure returns (Client.EVM2AnyMessage memory) { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + return Client.EVM2AnyMessage({ + receiver: abi.encode(_receiver), // ABI-encoded receiver address + data: abi.encode(_text), // ABI-encoded string + tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array as no tokens are transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 200_000, // Gas limit for the callback on the destination chain + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender + }) + ), + // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees + feeToken: _feeTokenAddress + }); + } + + /// @notice Fetches the details of the last received message. + /// @return messageId The ID of the last received message. + /// @return text The last received text. + function getLastReceivedMessageDetails() external view returns (bytes32 messageId, string memory text) { + return (s_lastReceivedMessageId, s_lastReceivedText); + } + + /// @notice Fallback function to allow the contract to receive Ether. + /// @dev This function has no function body, making it a default function for receiving Ether. + /// It is automatically called when Ether is sent to the contract without any data. + receive() external payable {} + + /// @notice Allows the contract owner to withdraw the entire balance of Ether from the contract. + /// @dev This function reverts if there are no funds to withdraw or if the transfer fails. + /// It should only be callable by the owner of the contract. + /// @param _beneficiary The address to which the Ether should be sent. + function withdraw( + address _beneficiary + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = address(this).balance; + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + // Attempt to send the funds, capturing the success status and discarding any return data + (bool sent,) = _beneficiary.call{value: amount}(""); + + // Revert if the send failed, with information about the attempted transfer + if (!sent) revert FailedToWithdrawEth(msg.sender, _beneficiary, amount); + } + + /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + /// @param _token The contract address of the ERC20 token to be withdrawn. + function withdrawToken( + address _beneficiary, + address _token + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = IERC20(_token).balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + IERC20(_token).safeTransfer(_beneficiary, amount); + } +} +``` + ### Deploy your contracts To use this contract: @@ -11346,6 +14480,319 @@ Deploy the `MessageTracker.sol` contract on *Avalanche Fuji* and enable it to se 1. [Open the MessageTracker.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/CCIP/MessageTracker.sol) in Remix. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity 0.8.24; + + import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; + import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; + import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; + import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; + + import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + + using SafeERC20 for IERC20; + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + + /// @title - A simple messenger contract for sending/receiving data across chains and tracking the status of sent + /// messages. + contract MessageTracker is CCIPReceiver, OwnerIsCreator { + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough + // balance. + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error DestinationChainNotAllowlisted(uint64 destinationChainSelector); // Used when the destination chain has not been + // allowlisted by the contract owner. + error SourceChainNotAllowlisted(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by + // the contract owner. + error SenderNotAllowlisted(address sender); // Used when the sender has not been allowlisted by the contract owner. + error InvalidReceiverAddress(); // Used when the receiver address is 0. + error MessageWasNotSentByMessageTracker(bytes32 msgId); // Triggered when attempting to confirm a message not + // recognized as sent by this tracker. + error MessageHasAlreadyBeenProcessedOnDestination(bytes32 msgId); // Triggered when trying to mark a message as + // `ProcessedOnDestination` when it is already marked as such. + + // Enum is used to track the status of messages sent via CCIP. + // `NotSent` indicates a message has not yet been sent. + // `Sent` indicates that a message has been sent to the Acknowledger contract but not yet acknowledged. + // `ProcessedOnDestination` indicates that the Acknowledger contract has processed the message and that + // the Message Tracker contract has received the acknowledgment from the Acknowledger contract. + enum MessageStatus { + NotSent, // 0 + Sent, // 1 + ProcessedOnDestination // 2 + } + + // Struct to store the status and acknowledger message ID of a message. + struct MessageInfo { + MessageStatus status; + bytes32 acknowledgerMessageId; + } + + // Mapping to keep track of allowlisted destination chains. + mapping(uint64 => bool) public allowlistedDestinationChains; + + // Mapping to keep track of allowlisted source chains. + mapping(uint64 => bool) public allowlistedSourceChains; + + // Mapping to keep track of allowlisted senders. + mapping(address => bool) public allowlistedSenders; + + // Mapping to keep track of message IDs to their info (status & acknowledger message ID). + mapping(bytes32 => MessageInfo) public messagesInfo; + + // Event emitted when a message is sent to another chain. + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The text being sent. + // the token address used to pay CCIP fees. + // The fees paid for sending the CCIP message. + event MessageSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address receiver, + string text, + address feeToken, + uint256 fees + ); + + // Event emitted when the sender contract receives an acknowledgment + // that the receiver contract has successfully received and processed the message. + event MessageProcessedOnDestination( // The unique ID of the CCIP acknowledgment message. + // The unique ID of the message acknowledged by the receiver. + // The chain selector of the source chain. + // The address of the sender from the source chain. + bytes32 indexed messageId, + bytes32 indexed acknowledgedMsgId, + uint64 indexed sourceChainSelector, + address sender + ); + + IERC20 private s_linkToken; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) CCIPReceiver(_router) { + s_linkToken = IERC20(_link); + } + + /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. + /// @param _destinationChainSelector The selector of the destination chain. + modifier onlyAllowlistedDestinationChain( + uint64 _destinationChainSelector + ) { + if (!allowlistedDestinationChains[_destinationChainSelector]) { + revert DestinationChainNotAllowlisted(_destinationChainSelector); + } + _; + } + + /// @dev Modifier that checks if the chain with the given sourceChainSelector is allowlisted and if the sender is + /// allowlisted. + /// @param _sourceChainSelector The selector of the destination chain. + /// @param _sender The address of the sender. + modifier onlyAllowlisted( + uint64 _sourceChainSelector, + address _sender + ) { + if (!allowlistedSourceChains[_sourceChainSelector]) { + revert SourceChainNotAllowlisted(_sourceChainSelector); + } + if (!allowlistedSenders[_sender]) revert SenderNotAllowlisted(_sender); + _; + } + + /// @dev Modifier that checks the receiver address is not 0. + /// @param _receiver The receiver address. + modifier validateReceiver( + address _receiver + ) { + if (_receiver == address(0)) revert InvalidReceiverAddress(); + _; + } + + /// @dev Updates the allowlist status of a destination chain for transactions. + function allowlistDestinationChain( + uint64 _destinationChainSelector, + bool allowed + ) external onlyOwner { + allowlistedDestinationChains[_destinationChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a source chain for transactions. + function allowlistSourceChain( + uint64 _sourceChainSelector, + bool allowed + ) external onlyOwner { + allowlistedSourceChains[_sourceChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a sender for transactions. + function allowlistSender( + address _sender, + bool allowed + ) external onlyOwner { + allowlistedSenders[_sender] = allowed; + } + + /// @notice Sends data to receiver on the destination chain. + /// @notice Pay for fees in LINK. + /// @dev Assumes your contract has sufficient LINK. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _text The text to be sent. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayLINK( + uint64 _destinationChainSelector, + address _receiver, + string calldata _text + ) + external + onlyOwner + onlyAllowlistedDestinationChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(_receiver, _text, address(s_linkToken)); + + // Initialize a router client instance to interact with cross-chain router + IRouterClient router = IRouterClient(this.getRouter()); + + // Get the fee required to send the CCIP message + uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); + + if (fees > s_linkToken.balanceOf(address(this))) { + revert NotEnoughBalance(s_linkToken.balanceOf(address(this)), fees); + } + + // approve the Router to transfer LINK tokens on contract's behalf. It will spend the fees in LINK + s_linkToken.approve(address(router), fees); + + // Send the CCIP message through the router and store the returned CCIP message ID + messageId = router.ccipSend(_destinationChainSelector, evm2AnyMessage); + + // Update the message status to `Sent` + messagesInfo[messageId].status = MessageStatus.Sent; + + // Emit an event with message details + emit MessageSent(messageId, _destinationChainSelector, _receiver, _text, address(s_linkToken), fees); + + // Return the CCIP message ID + return messageId; + } + + /** + * @dev Receives and processes messages sent via the Chainlink CCIP from allowed chains and senders. + * Upon receiving a message, this function checks if the message's associated data indicates a previously + * sent message awaiting acknowledgment. If the message is valid (i.e., its status is `Sent`), it updates + * the message's status to `ProcessedOnDestination`, thereby acknowledging its receipt. It then emits a + * `MessageProcessedOnDestination` + * event. If the message cannot be validated (e.g., it was not sent or has been tampered with), the function + * reverts with a `MessageWasNotSentByMessageTracker` error. This mechanism ensures that only messages + * genuinely sent and awaiting acknowledgment are marked as `ProcessedOnDestination`. + * @param any2EvmMessage The CCIP message received, which includes the message ID, the data being acknowledged, + * the source chain selector, and the sender's address. + */ + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) + internal + override + onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Ensure the + // source chain and sender are allowlisted for added security + + { + bytes32 initialMsgId = abi.decode(any2EvmMessage.data, (bytes32)); // Decode the data sent by the receiver + bytes32 acknowledgerMsgId = any2EvmMessage.messageId; + messagesInfo[initialMsgId].acknowledgerMessageId = acknowledgerMsgId; // Store the messageId of the received message + + if (messagesInfo[initialMsgId].status == MessageStatus.Sent) { + // Updates the status of the message to 'ProcessedOnDestination' to reflect that an acknowledgment + // of receipt has been received and emits an event to log this confirmation along with relevant details. + messagesInfo[initialMsgId].status = MessageStatus.ProcessedOnDestination; + emit MessageProcessedOnDestination( + acknowledgerMsgId, + initialMsgId, + any2EvmMessage.sourceChainSelector, + abi.decode(any2EvmMessage.sender, (address)) + ); + } else if (messagesInfo[initialMsgId].status == MessageStatus.ProcessedOnDestination) { + // If the message is already marked as 'ProcessedOnDestination', this indicates an attempt to + // re-confirm a message that has already been processed on the destination chain and marked as such. + revert MessageHasAlreadyBeenProcessedOnDestination(initialMsgId); + } else { + // If the message status is neither 'Sent' nor 'ProcessedOnDestination', it implies that the + // message ID provided for acknowledgment does not correspond to a valid, previously + // sent message. + revert MessageWasNotSentByMessageTracker(initialMsgId); + } + } + + /// @notice Construct a CCIP message. + /// @dev This function will create an EVM2AnyMessage struct with all the necessary information for sending a text. + /// @param _receiver The address of the receiver. + /// @param _text The string data to be sent. + /// @param _feeTokenAddress The address of the token used for fees. Set address(0) for native gas. + /// @return Client.EVM2AnyMessage Returns an EVM2AnyMessage struct which contains information for sending a CCIP + /// message. + function _buildCCIPMessage( + address _receiver, + string calldata _text, + address _feeTokenAddress + ) private pure returns (Client.EVM2AnyMessage memory) { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + return Client.EVM2AnyMessage({ + receiver: abi.encode(_receiver), // ABI-encoded receiver address + data: abi.encode(_text), // ABI-encoded string + tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array as no tokens are transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 300_000, + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender + }) + ), + // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees + feeToken: _feeTokenAddress + }); + } + + /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + /// @param _token The contract address of the ERC20 token to be withdrawn. + function withdrawToken( + address _beneficiary, + address _token + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = IERC20(_token).balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + IERC20(_token).safeTransfer(_beneficiary, amount); + } + } + ``` + Note: The contract code is also available in the [Examine the code](/ccip/tutorials/evm/send-arbitrary-data-receipt-acknowledgment#messagetrackersol) section. 2. Compile the contract. @@ -11380,6 +14827,254 @@ Deploy the `Acknowledger.sol` contract on *Ethereum Sepolia* and enable it to se 1. [Open the Acknowledger.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/CCIP/Acknowledger.sol) contract in Remix. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity 0.8.24; + + import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; + import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; + import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; + import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; + + import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + + using SafeERC20 for IERC20; + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + + /// @title - A simple acknowledger contract for receiving data and sending acknowledgement of receipt messages across + /// chains. + contract Acknowledger is CCIPReceiver, OwnerIsCreator { + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough + // balance. + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error DestinationChainNotAllowlisted(uint64 destinationChainSelector); // Used when the destination chain has not been + // allowlisted by the contract owner. + error InvalidReceiverAddress(); // Used when the receiver address is 0. + error SourceChainNotAllowlisted(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by + // the contract owner. + error SenderNotAllowlisted(address sender); // Used when the sender has not been allowlisted by the contract owner. + + string private s_lastReceivedText; // Store the last received text. + + // Mapping to keep track of allowlisted destination chains. + mapping(uint64 => bool) public allowlistedDestinationChains; + + // Mapping to keep track of allowlisted source chains. + mapping(uint64 => bool) public allowlistedSourceChains; + + // Mapping to keep track of allowlisted senders. + mapping(address => bool) public allowlistedSenders; + + // Emitted when an acknowledgment message is successfully sent back to the sender contract. + // This event signifies that the Acknowledger contract has recognized the receipt of an initial message + // and has informed the original sender contract by sending an acknowledgment message, + // including the original message ID. + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The data being sent back, containing the message ID of the initial message to acknowledge. + // The token address used to pay CCIP fees for sending the acknowledgment. + // The fees paid for sending the acknowledgment message via CCIP. + event AcknowledgmentSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address indexed receiver, + bytes32 data, + address feeToken, + uint256 fees + ); + + IERC20 private s_linkToken; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) CCIPReceiver(_router) { + s_linkToken = IERC20(_link); + } + + /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. + /// @param _destinationChainSelector The selector of the destination chain. + modifier onlyAllowlistedDestinationChain( + uint64 _destinationChainSelector + ) { + if (!allowlistedDestinationChains[_destinationChainSelector]) { + revert DestinationChainNotAllowlisted(_destinationChainSelector); + } + _; + } + + /// @dev Modifier that checks if the chain with the given sourceChainSelector is allowlisted and if the sender is + /// allowlisted. + /// @param _sourceChainSelector The selector of the destination chain. + /// @param _sender The address of the sender. + modifier onlyAllowlisted( + uint64 _sourceChainSelector, + address _sender + ) { + if (!allowlistedSourceChains[_sourceChainSelector]) { + revert SourceChainNotAllowlisted(_sourceChainSelector); + } + if (!allowlistedSenders[_sender]) revert SenderNotAllowlisted(_sender); + _; + } + + /// @dev Updates the allowlist status of a destination chain for transactions. + function allowlistDestinationChain( + uint64 _destinationChainSelector, + bool allowed + ) external onlyOwner { + allowlistedDestinationChains[_destinationChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a source chain for transactions. + function allowlistSourceChain( + uint64 _sourceChainSelector, + bool allowed + ) external onlyOwner { + allowlistedSourceChains[_sourceChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a sender for transactions. + function allowlistSender( + address _sender, + bool allowed + ) external onlyOwner { + allowlistedSenders[_sender] = allowed; + } + + /// @notice Sends an acknowledgment message back to the sender contract on the source chain + /// and pays the fees using LINK tokens. + /// @dev This function constructs and sends an acknowledgment message using CCIP, + /// indicating the receipt and processing of an initial message. It emits the `AcknowledgmentSent` event + /// upon successful sending. This function should be called after processing the received message + /// to inform the sender contract about the successful message reception. + /// @param _messageIdToAcknowledge The message ID of the initial message being acknowledged. + /// @param _messageTrackerAddress The address of the message tracker contract on the source chain. + /// @param _messageTrackerChainSelector The chain selector of the source chain. + function _acknowledgePayLINK( + bytes32 _messageIdToAcknowledge, + address _messageTrackerAddress, + uint64 _messageTrackerChainSelector + ) private { + if (_messageTrackerAddress == address(0)) { + revert InvalidReceiverAddress(); + } + + // Construct the CCIP message for acknowledgment, including the message ID of the initial message. + Client.EVM2AnyMessage memory acknowledgment = Client.EVM2AnyMessage({ + receiver: abi.encode(_messageTrackerAddress), // ABI-encoded receiver address + data: abi.encode(_messageIdToAcknowledge), // ABI-encoded message ID to acknowledge + tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array aas no tokens are transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 200_000, + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender. + }) + ), + // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees + feeToken: address(s_linkToken) + }); + + // Initialize a router client instance to interact with the cross-chain router. + IRouterClient router = IRouterClient(this.getRouter()); + + // Calculate the fee required to send the CCIP acknowledgment message. + uint256 fees = router.getFee( + _messageTrackerChainSelector, // The chain selector for routing the message. + acknowledgment // The acknowledgment message data. + ); + + // Ensure the contract has sufficient balance to cover the message sending fees. + if (fees > s_linkToken.balanceOf(address(this))) { + revert NotEnoughBalance(s_linkToken.balanceOf(address(this)), fees); + } + + // Approve the router to transfer LINK tokens on behalf of this contract to cover the sending fees. + s_linkToken.approve(address(router), fees); + + // Send the acknowledgment message via the CCIP router and capture the resulting message ID. + bytes32 messageId = router.ccipSend( + _messageTrackerChainSelector, // The destination chain selector. + acknowledgment // The CCIP message payload for acknowledgment. + ); + + // Emit an event detailing the acknowledgment message sending, for external tracking and verification. + emit AcknowledgmentSent( + messageId, // The ID of the sent acknowledgment message. + _messageTrackerChainSelector, // The destination chain selector. + _messageTrackerAddress, // The receiver of the acknowledgment, typically the original sender. + _messageIdToAcknowledge, // The original message ID that was acknowledged. + address(s_linkToken), // The fee token used. + fees // The fees paid for sending the message. + ); + } + + /// @dev Handles a received CCIP message, processes it, and acknowledges its receipt. + /// This internal function is called upon the receipt of a new message via CCIP from an allowlisted source chain and + /// sender. + /// It decodes the message and acknowledges its receipt by calling `_acknowledgePayLINK`. + /// @param any2EvmMessage The CCIP message received + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) + internal + override + onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Make sure + // source chain and sender are allowlisted + + { + bytes32 messageIdToAcknowledge = any2EvmMessage.messageId; // The message ID of the received message to acknowledge + address messageTrackerAddress = abi.decode(any2EvmMessage.sender, (address)); // ABI-decoding of the message tracker + // address + uint64 messageTrackerChainSelector = any2EvmMessage.sourceChainSelector; // The chain selector of the received + // message + s_lastReceivedText = abi.decode(any2EvmMessage.data, (string)); // abi-decoding of the sent text + + _acknowledgePayLINK(messageIdToAcknowledge, messageTrackerAddress, messageTrackerChainSelector); + } + + /// @notice Fetches the details of the last received message. + /// @return text The last received text. + function getLastReceivedMessage() external view returns (string memory text) { + return (s_lastReceivedText); + } + + /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + /// @param _token The contract address of the ERC20 token to be withdrawn. + function withdrawToken( + address _beneficiary, + address _token + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = IERC20(_token).balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + IERC20(_token).safeTransfer(_beneficiary, amount); + } + } + ``` + Note: The contract code is also available in the [Examine the code](/ccip/tutorials/evm/send-arbitrary-data-receipt-acknowledgment#acknowledgersol) section. 2. Compile the contract. @@ -11625,8 +15320,569 @@ Both contracts use allowlists to process only messages from and to allowed sourc ### MessageTracker.sol +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; +import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +using SafeERC20 for IERC20; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/// @title - A simple messenger contract for sending/receiving data across chains and tracking the status of sent +/// messages. +contract MessageTracker is CCIPReceiver, OwnerIsCreator { + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough + // balance. + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error DestinationChainNotAllowlisted(uint64 destinationChainSelector); // Used when the destination chain has not been + // allowlisted by the contract owner. + error SourceChainNotAllowlisted(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by + // the contract owner. + error SenderNotAllowlisted(address sender); // Used when the sender has not been allowlisted by the contract owner. + error InvalidReceiverAddress(); // Used when the receiver address is 0. + error MessageWasNotSentByMessageTracker(bytes32 msgId); // Triggered when attempting to confirm a message not + // recognized as sent by this tracker. + error MessageHasAlreadyBeenProcessedOnDestination(bytes32 msgId); // Triggered when trying to mark a message as + // `ProcessedOnDestination` when it is already marked as such. + + // Enum is used to track the status of messages sent via CCIP. + // `NotSent` indicates a message has not yet been sent. + // `Sent` indicates that a message has been sent to the Acknowledger contract but not yet acknowledged. + // `ProcessedOnDestination` indicates that the Acknowledger contract has processed the message and that + // the Message Tracker contract has received the acknowledgment from the Acknowledger contract. + enum MessageStatus { + NotSent, // 0 + Sent, // 1 + ProcessedOnDestination // 2 + } + + // Struct to store the status and acknowledger message ID of a message. + struct MessageInfo { + MessageStatus status; + bytes32 acknowledgerMessageId; + } + + // Mapping to keep track of allowlisted destination chains. + mapping(uint64 => bool) public allowlistedDestinationChains; + + // Mapping to keep track of allowlisted source chains. + mapping(uint64 => bool) public allowlistedSourceChains; + + // Mapping to keep track of allowlisted senders. + mapping(address => bool) public allowlistedSenders; + + // Mapping to keep track of message IDs to their info (status & acknowledger message ID). + mapping(bytes32 => MessageInfo) public messagesInfo; + + // Event emitted when a message is sent to another chain. + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The text being sent. + // the token address used to pay CCIP fees. + // The fees paid for sending the CCIP message. + event MessageSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address receiver, + string text, + address feeToken, + uint256 fees + ); + + // Event emitted when the sender contract receives an acknowledgment + // that the receiver contract has successfully received and processed the message. + event MessageProcessedOnDestination( // The unique ID of the CCIP acknowledgment message. + // The unique ID of the message acknowledged by the receiver. + // The chain selector of the source chain. + // The address of the sender from the source chain. + bytes32 indexed messageId, + bytes32 indexed acknowledgedMsgId, + uint64 indexed sourceChainSelector, + address sender + ); + + IERC20 private s_linkToken; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) CCIPReceiver(_router) { + s_linkToken = IERC20(_link); + } + + /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. + /// @param _destinationChainSelector The selector of the destination chain. + modifier onlyAllowlistedDestinationChain( + uint64 _destinationChainSelector + ) { + if (!allowlistedDestinationChains[_destinationChainSelector]) { + revert DestinationChainNotAllowlisted(_destinationChainSelector); + } + _; + } + + /// @dev Modifier that checks if the chain with the given sourceChainSelector is allowlisted and if the sender is + /// allowlisted. + /// @param _sourceChainSelector The selector of the destination chain. + /// @param _sender The address of the sender. + modifier onlyAllowlisted( + uint64 _sourceChainSelector, + address _sender + ) { + if (!allowlistedSourceChains[_sourceChainSelector]) { + revert SourceChainNotAllowlisted(_sourceChainSelector); + } + if (!allowlistedSenders[_sender]) revert SenderNotAllowlisted(_sender); + _; + } + + /// @dev Modifier that checks the receiver address is not 0. + /// @param _receiver The receiver address. + modifier validateReceiver( + address _receiver + ) { + if (_receiver == address(0)) revert InvalidReceiverAddress(); + _; + } + + /// @dev Updates the allowlist status of a destination chain for transactions. + function allowlistDestinationChain( + uint64 _destinationChainSelector, + bool allowed + ) external onlyOwner { + allowlistedDestinationChains[_destinationChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a source chain for transactions. + function allowlistSourceChain( + uint64 _sourceChainSelector, + bool allowed + ) external onlyOwner { + allowlistedSourceChains[_sourceChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a sender for transactions. + function allowlistSender( + address _sender, + bool allowed + ) external onlyOwner { + allowlistedSenders[_sender] = allowed; + } + + /// @notice Sends data to receiver on the destination chain. + /// @notice Pay for fees in LINK. + /// @dev Assumes your contract has sufficient LINK. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _text The text to be sent. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayLINK( + uint64 _destinationChainSelector, + address _receiver, + string calldata _text + ) + external + onlyOwner + onlyAllowlistedDestinationChain(_destinationChainSelector) + validateReceiver(_receiver) + returns (bytes32 messageId) + { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(_receiver, _text, address(s_linkToken)); + + // Initialize a router client instance to interact with cross-chain router + IRouterClient router = IRouterClient(this.getRouter()); + + // Get the fee required to send the CCIP message + uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); + + if (fees > s_linkToken.balanceOf(address(this))) { + revert NotEnoughBalance(s_linkToken.balanceOf(address(this)), fees); + } + + // approve the Router to transfer LINK tokens on contract's behalf. It will spend the fees in LINK + s_linkToken.approve(address(router), fees); + + // Send the CCIP message through the router and store the returned CCIP message ID + messageId = router.ccipSend(_destinationChainSelector, evm2AnyMessage); + + // Update the message status to `Sent` + messagesInfo[messageId].status = MessageStatus.Sent; + + // Emit an event with message details + emit MessageSent(messageId, _destinationChainSelector, _receiver, _text, address(s_linkToken), fees); + + // Return the CCIP message ID + return messageId; + } + + /** + * @dev Receives and processes messages sent via the Chainlink CCIP from allowed chains and senders. + * Upon receiving a message, this function checks if the message's associated data indicates a previously + * sent message awaiting acknowledgment. If the message is valid (i.e., its status is `Sent`), it updates + * the message's status to `ProcessedOnDestination`, thereby acknowledging its receipt. It then emits a + * `MessageProcessedOnDestination` + * event. If the message cannot be validated (e.g., it was not sent or has been tampered with), the function + * reverts with a `MessageWasNotSentByMessageTracker` error. This mechanism ensures that only messages + * genuinely sent and awaiting acknowledgment are marked as `ProcessedOnDestination`. + * @param any2EvmMessage The CCIP message received, which includes the message ID, the data being acknowledged, + * the source chain selector, and the sender's address. + */ + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) + internal + override + onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Ensure the + // source chain and sender are allowlisted for added security + + { + bytes32 initialMsgId = abi.decode(any2EvmMessage.data, (bytes32)); // Decode the data sent by the receiver + bytes32 acknowledgerMsgId = any2EvmMessage.messageId; + messagesInfo[initialMsgId].acknowledgerMessageId = acknowledgerMsgId; // Store the messageId of the received message + + if (messagesInfo[initialMsgId].status == MessageStatus.Sent) { + // Updates the status of the message to 'ProcessedOnDestination' to reflect that an acknowledgment + // of receipt has been received and emits an event to log this confirmation along with relevant details. + messagesInfo[initialMsgId].status = MessageStatus.ProcessedOnDestination; + emit MessageProcessedOnDestination( + acknowledgerMsgId, + initialMsgId, + any2EvmMessage.sourceChainSelector, + abi.decode(any2EvmMessage.sender, (address)) + ); + } else if (messagesInfo[initialMsgId].status == MessageStatus.ProcessedOnDestination) { + // If the message is already marked as 'ProcessedOnDestination', this indicates an attempt to + // re-confirm a message that has already been processed on the destination chain and marked as such. + revert MessageHasAlreadyBeenProcessedOnDestination(initialMsgId); + } else { + // If the message status is neither 'Sent' nor 'ProcessedOnDestination', it implies that the + // message ID provided for acknowledgment does not correspond to a valid, previously + // sent message. + revert MessageWasNotSentByMessageTracker(initialMsgId); + } + } + + /// @notice Construct a CCIP message. + /// @dev This function will create an EVM2AnyMessage struct with all the necessary information for sending a text. + /// @param _receiver The address of the receiver. + /// @param _text The string data to be sent. + /// @param _feeTokenAddress The address of the token used for fees. Set address(0) for native gas. + /// @return Client.EVM2AnyMessage Returns an EVM2AnyMessage struct which contains information for sending a CCIP + /// message. + function _buildCCIPMessage( + address _receiver, + string calldata _text, + address _feeTokenAddress + ) private pure returns (Client.EVM2AnyMessage memory) { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + return Client.EVM2AnyMessage({ + receiver: abi.encode(_receiver), // ABI-encoded receiver address + data: abi.encode(_text), // ABI-encoded string + tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array as no tokens are transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 300_000, + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender + }) + ), + // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees + feeToken: _feeTokenAddress + }); + } + + /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + /// @param _token The contract address of the ERC20 token to be withdrawn. + function withdrawToken( + address _beneficiary, + address _token + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = IERC20(_token).balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + IERC20(_token).safeTransfer(_beneficiary, amount); + } +} +``` + ### Acknowledger.sol +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; +import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +using SafeERC20 for IERC20; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/// @title - A simple acknowledger contract for receiving data and sending acknowledgement of receipt messages across +/// chains. +contract Acknowledger is CCIPReceiver, OwnerIsCreator { + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough + // balance. + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error DestinationChainNotAllowlisted(uint64 destinationChainSelector); // Used when the destination chain has not been + // allowlisted by the contract owner. + error InvalidReceiverAddress(); // Used when the receiver address is 0. + error SourceChainNotAllowlisted(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by + // the contract owner. + error SenderNotAllowlisted(address sender); // Used when the sender has not been allowlisted by the contract owner. + + string private s_lastReceivedText; // Store the last received text. + + // Mapping to keep track of allowlisted destination chains. + mapping(uint64 => bool) public allowlistedDestinationChains; + + // Mapping to keep track of allowlisted source chains. + mapping(uint64 => bool) public allowlistedSourceChains; + + // Mapping to keep track of allowlisted senders. + mapping(address => bool) public allowlistedSenders; + + // Emitted when an acknowledgment message is successfully sent back to the sender contract. + // This event signifies that the Acknowledger contract has recognized the receipt of an initial message + // and has informed the original sender contract by sending an acknowledgment message, + // including the original message ID. + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The data being sent back, containing the message ID of the initial message to acknowledge. + // The token address used to pay CCIP fees for sending the acknowledgment. + // The fees paid for sending the acknowledgment message via CCIP. + event AcknowledgmentSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address indexed receiver, + bytes32 data, + address feeToken, + uint256 fees + ); + + IERC20 private s_linkToken; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) CCIPReceiver(_router) { + s_linkToken = IERC20(_link); + } + + /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. + /// @param _destinationChainSelector The selector of the destination chain. + modifier onlyAllowlistedDestinationChain( + uint64 _destinationChainSelector + ) { + if (!allowlistedDestinationChains[_destinationChainSelector]) { + revert DestinationChainNotAllowlisted(_destinationChainSelector); + } + _; + } + + /// @dev Modifier that checks if the chain with the given sourceChainSelector is allowlisted and if the sender is + /// allowlisted. + /// @param _sourceChainSelector The selector of the destination chain. + /// @param _sender The address of the sender. + modifier onlyAllowlisted( + uint64 _sourceChainSelector, + address _sender + ) { + if (!allowlistedSourceChains[_sourceChainSelector]) { + revert SourceChainNotAllowlisted(_sourceChainSelector); + } + if (!allowlistedSenders[_sender]) revert SenderNotAllowlisted(_sender); + _; + } + + /// @dev Updates the allowlist status of a destination chain for transactions. + function allowlistDestinationChain( + uint64 _destinationChainSelector, + bool allowed + ) external onlyOwner { + allowlistedDestinationChains[_destinationChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a source chain for transactions. + function allowlistSourceChain( + uint64 _sourceChainSelector, + bool allowed + ) external onlyOwner { + allowlistedSourceChains[_sourceChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a sender for transactions. + function allowlistSender( + address _sender, + bool allowed + ) external onlyOwner { + allowlistedSenders[_sender] = allowed; + } + + /// @notice Sends an acknowledgment message back to the sender contract on the source chain + /// and pays the fees using LINK tokens. + /// @dev This function constructs and sends an acknowledgment message using CCIP, + /// indicating the receipt and processing of an initial message. It emits the `AcknowledgmentSent` event + /// upon successful sending. This function should be called after processing the received message + /// to inform the sender contract about the successful message reception. + /// @param _messageIdToAcknowledge The message ID of the initial message being acknowledged. + /// @param _messageTrackerAddress The address of the message tracker contract on the source chain. + /// @param _messageTrackerChainSelector The chain selector of the source chain. + function _acknowledgePayLINK( + bytes32 _messageIdToAcknowledge, + address _messageTrackerAddress, + uint64 _messageTrackerChainSelector + ) private { + if (_messageTrackerAddress == address(0)) { + revert InvalidReceiverAddress(); + } + + // Construct the CCIP message for acknowledgment, including the message ID of the initial message. + Client.EVM2AnyMessage memory acknowledgment = Client.EVM2AnyMessage({ + receiver: abi.encode(_messageTrackerAddress), // ABI-encoded receiver address + data: abi.encode(_messageIdToAcknowledge), // ABI-encoded message ID to acknowledge + tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array aas no tokens are transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 200_000, + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender. + }) + ), + // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees + feeToken: address(s_linkToken) + }); + + // Initialize a router client instance to interact with the cross-chain router. + IRouterClient router = IRouterClient(this.getRouter()); + + // Calculate the fee required to send the CCIP acknowledgment message. + uint256 fees = router.getFee( + _messageTrackerChainSelector, // The chain selector for routing the message. + acknowledgment // The acknowledgment message data. + ); + + // Ensure the contract has sufficient balance to cover the message sending fees. + if (fees > s_linkToken.balanceOf(address(this))) { + revert NotEnoughBalance(s_linkToken.balanceOf(address(this)), fees); + } + + // Approve the router to transfer LINK tokens on behalf of this contract to cover the sending fees. + s_linkToken.approve(address(router), fees); + + // Send the acknowledgment message via the CCIP router and capture the resulting message ID. + bytes32 messageId = router.ccipSend( + _messageTrackerChainSelector, // The destination chain selector. + acknowledgment // The CCIP message payload for acknowledgment. + ); + + // Emit an event detailing the acknowledgment message sending, for external tracking and verification. + emit AcknowledgmentSent( + messageId, // The ID of the sent acknowledgment message. + _messageTrackerChainSelector, // The destination chain selector. + _messageTrackerAddress, // The receiver of the acknowledgment, typically the original sender. + _messageIdToAcknowledge, // The original message ID that was acknowledged. + address(s_linkToken), // The fee token used. + fees // The fees paid for sending the message. + ); + } + + /// @dev Handles a received CCIP message, processes it, and acknowledges its receipt. + /// This internal function is called upon the receipt of a new message via CCIP from an allowlisted source chain and + /// sender. + /// It decodes the message and acknowledges its receipt by calling `_acknowledgePayLINK`. + /// @param any2EvmMessage The CCIP message received + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) + internal + override + onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Make sure + // source chain and sender are allowlisted + + { + bytes32 messageIdToAcknowledge = any2EvmMessage.messageId; // The message ID of the received message to acknowledge + address messageTrackerAddress = abi.decode(any2EvmMessage.sender, (address)); // ABI-decoding of the message tracker + // address + uint64 messageTrackerChainSelector = any2EvmMessage.sourceChainSelector; // The chain selector of the received + // message + s_lastReceivedText = abi.decode(any2EvmMessage.data, (string)); // abi-decoding of the sent text + + _acknowledgePayLINK(messageIdToAcknowledge, messageTrackerAddress, messageTrackerChainSelector); + } + + /// @notice Fetches the details of the last received message. + /// @return text The last received text. + function getLastReceivedMessage() external view returns (string memory text) { + return (s_lastReceivedText); + } + + /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + /// @param _token The contract address of the ERC20 token to be withdrawn. + function withdrawToken( + address _beneficiary, + address _token + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = IERC20(_token).balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + IERC20(_token).safeTransfer(_beneficiary, amount); + } +} +``` + ## Final note In this example, the *message tracker* contract emits an event when it receives the acknowledgment message confirming the initial message reception and processing on the counterpart chain. However, you could think of any other logic to execute when the *message tracker* receives the acknowledgment. This tutorial demonstrates the pattern for sending arbitrary data, but you can apply the same pattern to programmable token transfers. @@ -11677,6 +15933,308 @@ In this tutorial, you'll send a text *string* and CCIP-BnM tokens between smart 2. Manually retry the execution. 3. Observe successful execution after the gas limit adjustment. +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; +import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {OwnerIsCreator} from "@chainlink/contracts@1.4.0/src/v0.8/shared/access/OwnerIsCreator.sol"; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/// @title - A simple messenger contract for transferring/receiving tokens and data across chains. +contract ProgrammableTokenTransfersLowGasLimit is CCIPReceiver, OwnerIsCreator { + using SafeERC20 for IERC20; + + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 requiredBalance); // Used to make sure contract has enough + // token balance + error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. + error DestinationChainNotAllowed(uint64 destinationChainSelector); // Used when the destination chain has not been + // allowlisted by the contract owner. + error SourceChainNotAllowed(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by the + // contract owner. + error SenderNotAllowed(address sender); // Used when the sender has not been allowlisted by the contract owner. + + // Event emitted when a message is sent to another chain. + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The text being sent. + // The token address that was transferred. + // The token amount that was transferred. + // the token address used to pay CCIP fees. + // The fees paid for sending the message. + event MessageSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address receiver, + string text, + address token, + uint256 tokenAmount, + address feeToken, + uint256 fees + ); + + // Event emitted when a message is received from another chain. + // The chain selector of the source chain. + // The address of the sender from the source chain. + // The text that was received. + // The token address that was transferred. + // The token amount that was transferred. + event MessageReceived( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed sourceChainSelector, + address sender, + string text, + address token, + uint256 tokenAmount + ); + + bytes32 private s_lastReceivedMessageId; // Store the last received messageId. + address private s_lastReceivedTokenAddress; // Store the last received token address. + uint256 private s_lastReceivedTokenAmount; // Store the last received amount. + string private s_lastReceivedText; // Store the last received text. + + // Mapping to keep track of allowlisted destination chains. + mapping(uint64 => bool) public allowlistedDestinationChains; + + // Mapping to keep track of allowlisted source chains. + mapping(uint64 => bool) public allowlistedSourceChains; + + // Mapping to keep track of allowlisted senders. + mapping(address => bool) public allowlistedSenders; + + IERC20 private s_linkToken; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) CCIPReceiver(_router) { + s_linkToken = IERC20(_link); + } + + /// @dev Modifier that checks if the chain with the given destinationChainSelector is allowlisted. + /// @param _destinationChainSelector The selector of the destination chain. + modifier onlyAllowlistedDestinationChain( + uint64 _destinationChainSelector + ) { + if (!allowlistedDestinationChains[_destinationChainSelector]) { + revert DestinationChainNotAllowed(_destinationChainSelector); + } + _; + } + + /// @dev Modifier that checks if the chain with the given sourceChainSelector is allowlisted and if the sender is + /// allowlisted. + /// @param _sourceChainSelector The selector of the destination chain. + /// @param _sender The address of the sender. + modifier onlyAllowlisted( + uint64 _sourceChainSelector, + address _sender + ) { + if (!allowlistedSourceChains[_sourceChainSelector]) { + revert SourceChainNotAllowed(_sourceChainSelector); + } + if (!allowlistedSenders[_sender]) revert SenderNotAllowed(_sender); + _; + } + + /// @dev Updates the allowlist status of a destination chain for transactions. + /// @notice This function can only be called by the owner. + /// @param _destinationChainSelector The selector of the destination chain to be updated. + /// @param allowed The allowlist status to be set for the destination chain. + function allowlistDestinationChain( + uint64 _destinationChainSelector, + bool allowed + ) external onlyOwner { + allowlistedDestinationChains[_destinationChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a source chain + /// @notice This function can only be called by the owner. + /// @param _sourceChainSelector The selector of the source chain to be updated. + /// @param allowed The allowlist status to be set for the source chain. + function allowlistSourceChain( + uint64 _sourceChainSelector, + bool allowed + ) external onlyOwner { + allowlistedSourceChains[_sourceChainSelector] = allowed; + } + + /// @dev Updates the allowlist status of a sender for transactions. + /// @notice This function can only be called by the owner. + /// @param _sender The address of the sender to be updated. + /// @param allowed The allowlist status to be set for the sender. + function allowlistSender( + address _sender, + bool allowed + ) external onlyOwner { + allowlistedSenders[_sender] = allowed; + } + + /// @notice Sends data and transfer tokens to receiver on the destination chain. + /// @notice Pay for fees in LINK. + /// @notice the gasLimit is set to 20_000 on purpose to force the execution to fail on the destination chain + /// @dev Assumes your contract has sufficient LINK to pay for CCIP fees. + /// @param _destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param _receiver The address of the recipient on the destination blockchain. + /// @param _text The string data to be sent. + /// @param _token token address. + /// @param _amount token amount. + /// @return messageId The ID of the CCIP message that was sent. + function sendMessagePayLINK( + uint64 _destinationChainSelector, + address _receiver, + string calldata _text, + address _token, + uint256 _amount + ) external onlyOwner onlyAllowlistedDestinationChain(_destinationChainSelector) returns (bytes32 messageId) { + // Set the token amounts + Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1); + tokenAmounts[0] = Client.EVMTokenAmount({token: _token, amount: _amount}); + + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + // address(linkToken) means fees are paid in LINK + + Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({ + receiver: abi.encode(_receiver), // ABI-encoded receiver address + data: abi.encode(_text), // ABI-encoded string + tokenAmounts: tokenAmounts, // The amount and type of token being transferred + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 20_000, // Gas limit for the callback on the destination chain + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender + }) + ), + // Set the feeToken to a LINK token address + feeToken: address(s_linkToken) + }); + + // Initialize a router client instance to interact with cross-chain router + IRouterClient router = IRouterClient(this.getRouter()); + + // Get the fee required to send the CCIP message + uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage); + + uint256 requiredLinkBalance; + if (_token == address(s_linkToken)) { + // Required LINK Balance is the sum of fees and amount to transfer, if the token to transfer is LINK + requiredLinkBalance = fees + _amount; + } else { + requiredLinkBalance = fees; + } + + uint256 linkBalance = s_linkToken.balanceOf(address(this)); + + if (requiredLinkBalance > linkBalance) { + revert NotEnoughBalance(linkBalance, requiredLinkBalance); + } + + // approve the Router to transfer LINK tokens on contract's behalf. It will spend the requiredLinkBalance + s_linkToken.approve(address(router), requiredLinkBalance); + + // If sending a token other than LINK, approve it separately + if (_token != address(s_linkToken)) { + uint256 tokenBalance = IERC20(_token).balanceOf(address(this)); + if (_amount > tokenBalance) { + revert NotEnoughBalance(tokenBalance, _amount); + } + // approve the Router to spend tokens on contract's behalf. It will spend the amount of the given token + IERC20(_token).approve(address(router), _amount); + } + + // Send the message through the router and store the returned message ID + messageId = router.ccipSend(_destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit MessageSent( + messageId, _destinationChainSelector, _receiver, _text, _token, _amount, address(s_linkToken), fees + ); + + // Return the message ID + return messageId; + } + + /** + * @notice Returns the details of the last CCIP received message. + * @dev This function retrieves the ID, text, token address, and token amount of the last received CCIP message. + * @return messageId The ID of the last received CCIP message. + * @return text The text of the last received CCIP message. + * @return tokenAddress The address of the token in the last CCIP received message. + * @return tokenAmount The amount of the token in the last CCIP received message. + */ + function getLastReceivedMessageDetails() + public + view + returns (bytes32 messageId, string memory text, address tokenAddress, uint256 tokenAmount) + { + return (s_lastReceivedMessageId, s_lastReceivedText, s_lastReceivedTokenAddress, s_lastReceivedTokenAmount); + } + + /// handle a received message + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) + internal + override + onlyAllowlisted(any2EvmMessage.sourceChainSelector, abi.decode(any2EvmMessage.sender, (address))) // Make sure + // source chain and sender are allowlisted + + { + s_lastReceivedMessageId = any2EvmMessage.messageId; // fetch the messageId + s_lastReceivedText = abi.decode(any2EvmMessage.data, (string)); // abi-decoding of the sent text + // Expect one token to be transferred at once, but you can transfer several tokens. + s_lastReceivedTokenAddress = any2EvmMessage.destTokenAmounts[0].token; + s_lastReceivedTokenAmount = any2EvmMessage.destTokenAmounts[0].amount; + + emit MessageReceived( + any2EvmMessage.messageId, + any2EvmMessage.sourceChainSelector, // fetch the source chain identifier (aka selector) + abi.decode(any2EvmMessage.sender, (address)), // abi-decoding of the sender address, + abi.decode(any2EvmMessage.data, (string)), + any2EvmMessage.destTokenAmounts[0].token, + any2EvmMessage.destTokenAmounts[0].amount + ); + } + + /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token. + /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw. + /// @param _beneficiary The address to which the tokens will be sent. + /// @param _token The contract address of the ERC20 token to be withdrawn. + function withdrawToken( + address _beneficiary, + address _token + ) public onlyOwner { + // Retrieve the balance of this contract + uint256 amount = IERC20(_token).balanceOf(address(this)); + + // Revert if there is nothing to withdraw + if (amount == 0) revert NothingToWithdraw(); + + IERC20(_token).safeTransfer(_beneficiary, amount); + } +} +``` + ### Deploy your contracts To use this contract: @@ -12161,7 +16719,7 @@ To estimate the gas usage of the `ccipReceive` function within your own Hardhat 2. Create a testing file in your project's `test` directory. -3. Inside the `deployFixture` function, deploy the `MockCCIPRouter` contract and use its address to deploy your CCIP Sender and CCIP Receiver contracts. For more details, check this [example](https://github.com/smartcontractkit/smart-contract-examples/blob/ccip/estimate-gas/hardhat/test/Send-Receive.ts#L14). +3. Inside the `deployFixture` function, deploy the `MockCCIPRouter` contract and use its address to deploy your CCIP Sender and CCIP Receiver contracts. For more details, check this [example](https://github.com/smartcontractkit/smart-contract-examples/blob/main/ccip/estimate-gas/hardhat/test/Send-Receive.ts#L11). 4. In your test cases: 1. Send the CCIP message to the `MockCCIPRouter` contract. For more details, check this [example](https://github.com/smartcontractkit/smart-contract-examples/blob/main/ccip/estimate-gas/hardhat/test/Send-Receive.ts#L77). @@ -12436,7 +16994,7 @@ Last Updated: 2025-07-25 framework](https://www.anchor-lang.com/) - [Solana program development](https://solana.com/docs) - - [CCIP architecture](/ccip/concepts/architecture) + - [CCIP architecture](/ccip/concepts/architecture/overview) </Aside> # Implementing CCIP Receivers for Solana @@ -12768,7 +17326,7 @@ When implementing CCIP Receivers, follow these best practices: ## Example Implementation -For a complete, audited reference implementation of a CCIP Receiver, you can examine the [example-ccip-receiver](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/example-ccip-receiver) in the Chainlink CCIP repository. This example demonstrates all the security patterns and best practices covered in this guide and can serve as a starting point for your own implementation. +For a complete, audited reference implementation of a CCIP Receiver, you can examine the [example-ccip-receiver](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/example-ccip-receiver) in the Chainlink CCIP repository. This example demonstrates all the security patterns and best practices covered in this guide and can serve as a starting point for your own implementation. <Aside type="caution" title="Educational Example Disclaimer"> This page includes an educational example to use a Chainlink system, product, or service and is provided to @@ -16007,7 +20565,7 @@ This tutorial implements production-grade cross-chain tokens using a three-termi | Terminal | Repository | Purpose | Commands | | -------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------- | -| **Terminal 1** | [CCIP Solana base58 Generator](https://github.com/smartcontractkit/ccip-solana-base58-generator) | Generate governance transactions | `pnpm bs58` | +| **Terminal 1** | [CCIP Solana base58 Generator](https://github.com/smartcontractkit/ccip-solana-bs58-generator) | Generate governance transactions | `pnpm bs58` | | **Terminal 2** | [Smart Contract Examples (Hardhat)](https://github.com/smartcontractkit/smart-contract-examples/tree/main/ccip/cct/hardhat) | Deploy EVM components | `npx hardhat` | | **Terminal 3** | [Solana Starter Kit](https://github.com/smartcontractkit/solana-starter-kit) | Test cross-chain transfers | `yarn` | @@ -17116,7 +21674,7 @@ This tutorial implements production-grade cross-chain tokens using a three-termi | Terminal | Repository | Purpose | Commands | | -------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------- | -| **Terminal 1** | [CCIP Solana base58 Generator](https://github.com/smartcontractkit/ccip-solana-base58-generator) | Generate governance transactions | `pnpm bs58` | +| **Terminal 1** | [CCIP Solana base58 Generator](https://github.com/smartcontractkit/ccip-solana-bs58-generator) | Generate governance transactions | `pnpm bs58` | | **Terminal 2** | [Smart Contract Examples (Hardhat)](https://github.com/smartcontractkit/smart-contract-examples/tree/main/ccip/cct/hardhat) | Deploy EVM components | `npx hardhat` | | **Terminal 3** | [Solana Starter Kit](https://github.com/smartcontractkit/solana-starter-kit) | Test cross-chain transfers | `yarn` | @@ -17992,7 +22550,7 @@ Last Updated: 2025-09-03 - The [Move language](https://move-language.github.io/move/) and the [Aptos framework](https://aptos.dev/en/network/blockchain/move) - [Aptos module development and deployment](https://aptos.dev/en/build/smart-contracts) - - The [CCIP architecture](/ccip/concepts/architecture) + - The [CCIP architecture](/ccip/concepts/architecture/overview) </Aside> # Implementing CCIP Receivers for Aptos @@ -19864,7 +24422,7 @@ A programmable token transfer combines the features of a token transfer and an a <Aside title="Disclaimer" type="caution"> The `ccip_message_receiver` module used in this tutorial **should only be used with non-dispatchable tokens**, as it is currently incompatible with [dispatchable - tokens](https://aptosfoundation.org/currents/dispatchable-fungible-assets-101). + tokens](https://aptos.dev/build/smart-contracts/fungible-asset#dispatchable-fungible-asset-advanced). </Aside> This tutorial uses the `ccip_message_receiver` module from the `aptos-starter-kit`. Its `ccip_receive` function contains dispatcher logic. For this tutorial, we will trigger the part of its logic that handles a message containing both tokens and data. @@ -21178,7 +25736,7 @@ Source: https://docs.chain.link/ccip/api-reference/evm/v1.6.1/i-type-and-version An interface that provides type and version information for contracts. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/interfaces/ITypeAndVersion.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/interfaces/ITypeAndVersion.sol) ## Functions @@ -25386,7 +29944,7 @@ Source: https://docs.chain.link/ccip/api-reference/evm/v1.6.1/burn-mint-erc20 An ERC20-compliant token contract that extends the standard functionality with controlled minting and burning capabilities through role-based access control. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) <Aside> Key features of this token contract: @@ -26301,7 +30859,7 @@ Source: https://docs.chain.link/ccip/api-reference/evm/v1.6.1/ownable-2-step A minimal contract that implements 2-step ownership transfer and nothing more. It's made to be minimal to reduce the impact of the bytecode size on any contract that inherits from it. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/access/Ownable2Step.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/access/Ownable2Step.sol) <Aside type="note"> This contract implements a secure two-step ownership transfer process: @@ -26566,7 +31124,7 @@ A contract that facilitates two-step ownership transfer, providing enhanced secu This prevents accidental transfers to incorrect or inaccessible addresses. </Aside> -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/access/Ownable2StepMsgSender.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/access/Ownable2StepMsgSender.sol) ## Functions @@ -27275,7 +31833,7 @@ Source: https://docs.chain.link/ccip/api-reference/evm/v1.6.0/i-type-and-version An interface that provides type and version information for contracts. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/interfaces/ITypeAndVersion.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/interfaces/ITypeAndVersion.sol) ## Functions @@ -31459,7 +36017,7 @@ Source: https://docs.chain.link/ccip/api-reference/evm/v1.6.0/burn-mint-erc20 An ERC20-compliant token contract that extends the standard functionality with controlled minting and burning capabilities through role-based access control. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) <Aside> Key features of this token contract: @@ -32374,7 +36932,7 @@ Source: https://docs.chain.link/ccip/api-reference/evm/v1.6.0/ownable-2-step A minimal contract that implements 2-step ownership transfer and nothing more. It's made to be minimal to reduce the impact of the bytecode size on any contract that inherits from it. -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/access/Ownable2Step.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/access/Ownable2Step.sol) <Aside type="note"> This contract implements a secure two-step ownership transfer process: @@ -32639,7 +37197,7 @@ A contract that facilitates two-step ownership transfer, providing enhanced secu This prevents accidental transfers to incorrect or inaccessible addresses. </Aside> -[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-release/1.4.0/contracts/src/v0.8/shared/access/Ownable2StepMsgSender.sol) +[Git Source](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/access/Ownable2StepMsgSender.sol) ## Functions @@ -42864,7 +47422,7 @@ Source: https://docs.chain.link/ccip/api-reference/svm/v1.6.0/router ## Router -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/ccip-router) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/ccip-router) Below is a complete API reference for the CCIP Router program instructions. @@ -43308,7 +47866,7 @@ Source: https://docs.chain.link/ccip/api-reference/svm/v1.6.0/receiver ## Receiver -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/example-ccip-receiver) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/example-ccip-receiver) Below is a complete API reference for the `ccip_receive` instruction that must be implemented by any Solana program wishing to receive CCIP messages. @@ -43517,7 +48075,7 @@ Source: https://docs.chain.link/ccip/api-reference/svm/v1.6.0/base-token-pool ## Base Token Pool Library -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/base-token-pool) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/base-token-pool) The Base Token Pool library provides foundational components and shared functionality for CCIP token pool implementations on SVM-based blockchains. This library is not deployable as a standalone program but serves as a dependency for concrete token pool implementations like BurnMint and Lock-Release pools. @@ -43968,7 +48526,7 @@ Source: https://docs.chain.link/ccip/api-reference/svm/v1.6.0/burn-mint-token-po ## BurnMint Token Pool -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/burnmint-token-pool) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/burnmint-token-pool) Below is a complete API reference for the CCIP BurnMint Token Pool program instructions. This pool implementation burns tokens on the source chain and mints them on the destination chain. @@ -44639,7 +49197,7 @@ Source: https://docs.chain.link/ccip/api-reference/svm/v1.6.0/lock-release-token ## Lock-Release Token Pool -[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/lockrelease-token-pool) +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/lockrelease-token-pool) The Lock-Release Token Pool program implements a token pool that uses a lock/release strategy for cross-chain transfers. When tokens are sent cross-chain, they are locked in the pool on the source chain and released from the pool on the destination chain. @@ -60049,7 +64607,7 @@ This section explains the core architecture of the Cross-Chain Interoperability - **[Overview](/ccip/concepts/architecture/overview)**: Get a high-level summary of the CCIP architecture. - **[Key Concepts](/ccip/concepts/architecture/key-concepts)**: Understand the essential terms and components within the CCIP ecosystem. - **[Onchain Components](/ccip/concepts/architecture/onchain)**: Explore the on‑chain components, including EVM smart contracts and Solana programs, and Aptos modules, that operate directly on blockchains. -- **[Offchain Components](/ccip/concepts/architecture/offchain)**: Discover the offchain systems, like the Risk Management Network and Decentralized Oracle Network, that support CCIP operations. +- **[Offchain Components](/ccip/concepts/architecture/offchain/overview)**: Discover the offchain systems that support CCIP operations. --- @@ -60061,14 +64619,6 @@ This section details the onchain components of the CCIP architecture, including --- -# CCIP Best Practices -Source: https://docs.chain.link/ccip/concepts/best-practices -Last Updated: 2025-05-19 - -This section outlines recommended practices for using Chainlink CCIP effectively and securely across different blockchain families. Learn about security considerations, message verification, token administration, liquidity management, multi-signature patterns, and blockchain-specific guidelines to build robust cross-chain applications on EVM-compatible chains, Solana, and Aptos. - ---- - # Cross-Chain Token Standard (EVM) Source: https://docs.chain.link/ccip/concepts/cross-chain-token/evm Last Updated: 2025-05-19 @@ -60111,7 +64661,7 @@ Last Updated: 2025-06-09 This section explores the foundational concepts of the Cross-Chain Interoperability Protocol (CCIP). Understanding these concepts will help you effectively build and deploy secure cross-chain applications. -- **[Architecture](/ccip/concepts/architecture)**: Understand the core components and structure of CCIP, including onchain and offchain systems. +- **[Architecture](/ccip/concepts/architecture/overview)**: Understand the core components and structure of CCIP, including onchain and offchain systems. - **[Cross-Chain Token Standard](/ccip/concepts/cross-chain-token)**: Learn about the Cross-Chain Token (CCT) standard that enables secure token transfers across different blockchains. - **[Best Practices](/ccip/concepts/best-practices)**: Discover recommended guidelines for using CCIP effectively and securely on both EVM and SVM blockchains. - **[Manual Execution](/ccip/concepts/manual-execution)**: Learn why some CCIP messages might require manual execution and how to handle these situations. @@ -61766,7 +66316,6 @@ You can explore several comprehensive guides to learn about cross-chain interope - [Using CCIP CLI](/ccip/tutorials/evm/offchain/ccip-tools) - [Transfer Tokens between EOAs](/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa) - [Checking CCIP Message Status](/ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain) - - [Get Supported Tokens](/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens) - [Transfer USDC with Data](/ccip/tutorials/evm/usdc) - [Send Arbitrary Data](/ccip/tutorials/evm/send-arbitrary-data) - [Send Arbitrary Data and Receive Transfer Confirmation: A -> B -> A](/ccip/tutorials/evm/send-arbitrary-data-receipt-acknowledgment) @@ -61776,6 +66325,174 @@ You can explore several comprehensive guides to learn about cross-chain interope --- +# Get Supported Tokens +Source: https://docs.chain.link/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens +Last Updated: 2025-05-19 + +In this tutorial, you will learn how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP, with [CCIP Tools](https://github.com/smartcontractkit/ccip-tools-ts). You'll use the [`getSupportedTokens`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-cli/README.md#getsupportedtokens) command of `ccip-tools` to query the list of supported tokens that can be transferred from a specific source chain to a specific destination chain. + +## Before you begin + +Complete the prerequisite steps of the [Transfer Tokens between EOAs](/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa#before-you-begin) tutorial. + +## Tutorial + +This tutorial shows you how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP. By supplying the [`getSupportedTokens`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-cli/README.md#getsupportedtokens) command of `ccip-tools` with a source chain, source router address, and a destination chain, you can get the list of supported tokens that can be transferred from the source chain to the destination chain. + +**Execute the script in your command line:** + +```bash +./ccip-cli/ccip-cli getSupportedTokens <source> <router> <dest> +``` + +**The script requires the following parameters:** + +- `source`: Chain ID or network name. + + For example, `43113` for *Avalanche Fuji* or `11155111` for *Ethereum Sepolia*. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. + + You can find the supported network names and chain IDs that can be used for `source` in the + [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-sdk/src/selectors.ts) file of the + `ccip-tools` repository. + +- `router`: Router contract address on the source network. + + You can find the router contract address in the [CCIP Directory](https://docs.chain.link/ccip/directory) by searching for the relevant network. + +- `dest`: Chain ID or network name. + + For example, `43113` for *Avalanche Fuji* or `11155111` for *Ethereum Sepolia*. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. + + You can find the supported network names and chain IDs that can be used for `dest` in the + [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-sdk/src/selectors.ts) file of the + `ccip-tools` repository. + +**Example Usage:** + +If you would like to retrieve the list of supported tokens that can be transferred from *Avalanche Fuji* to *Ethereum Sepolia*, you can run the following command: + +```text +$ ./ccip-cli/ccip-cli getSupportedTokens 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 + +[INFO] Starting token discovery for cross-chain transfers +[INFO] Using TokenAdminRegistry 1.5.0 at 0xA92053a4a3922084d992fD2835bdBa4caC6877e6 from router 0xF694E193200268f9a4868e4Aa017A0118C9a8177 +┌────────────────────────────────────┬──────────────────────────────────────────────┐ +│ (index) │ Values │ +├────────────────────────────────────┼──────────────────────────────────────────────┤ +│ address │ '0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4' │ +│ symbol │ 'CCIP-BnM' │ +│ name │ 'CCIP-BnM' │ +│ decimals │ 18 │ +│ pool │ '0x10e3A37ff21c20CD802fdAF0204e2Ff04e5485ee' │ +│ pool.typeAndVersion │ 'BurnMintTokenPool 1.5.1' │ +│ remoteToken │ '0xFd57b4ddBf88a4e07fF4e34C487b99af2Fe82a05' │ +│ remotePools │ '0x4CcbDd6CF18800360161E4D2A519A2047176bDF0' │ +│ rateLimiters.outbound.tokens │ '100000.0' │ +│ rateLimiters.outbound.capacity │ '100000.0' │ +│ rateLimiters.outbound.rate │ '167.0' │ +│ rateLimiters.outbound.timeToRefill │ '9m58s' │ +│ rateLimiters.inbound.tokens │ '100000.0' │ +│ rateLimiters.inbound.capacity │ '100000.0' │ +│ rateLimiters.inbound.rate │ '167.0' │ +│ rateLimiters.inbound.timeToRefill │ '9m58s' │ +└────────────────────────────────────┴──────────────────────────────────────────────┘ +┌────────────────────────────────────┬──────────────────────────────────────────────┐ +│ (index) │ Values │ +├────────────────────────────────────┼──────────────────────────────────────────────┤ +│ address │ '0x70F5c5C40b873EA597776DA2C21929A8282A3b35' │ +│ symbol │ 'clCCIP-LnM' │ +│ name │ 'clCCIP-LnM' │ +│ decimals │ 18 │ +│ pool │ '0x8e35eB0dfb39Ec5F84254C3f863986a913171E0B' │ +│ pool.typeAndVersion │ 'BurnMintTokenPoolAndProxy 1.5.0' │ +│ remoteToken │ '0x466D489b6d36E7E3b824ef491C225F5830E81cC1' │ +│ remotePools │ '0x658FdaC59a197D5166151640b7a673F7dF1Ba324' │ +│ rateLimiters.outbound.tokens │ '100000.0' │ +│ rateLimiters.outbound.capacity │ '100000.0' │ +│ rateLimiters.outbound.rate │ '167.0' │ +│ rateLimiters.outbound.timeToRefill │ '9m58s' │ +│ rateLimiters.inbound.tokens │ '100000.0' │ +│ rateLimiters.inbound.capacity │ '100000.0' │ +│ rateLimiters.inbound.rate │ '167.0' │ +│ rateLimiters.inbound.timeToRefill │ '9m58s' │ +└────────────────────────────────────┴──────────────────────────────────────────────┘ +┌────────────────────────────────────┬──────────────────────────────────────────────┐ +│ (index) │ Values │ +├────────────────────────────────────┼──────────────────────────────────────────────┤ +│ address │ '0x5425890298aed601595a70AB815c96711a31Bc65' │ +│ symbol │ 'USDC' │ +│ name │ 'USD Coin' │ +│ decimals │ 6 │ +│ pool │ '0x5931822f394baBC2AACF4588E98FC77a9f5aa8C9' │ +│ pool.typeAndVersion │ 'USDCTokenPool 1.5.1' │ +│ remoteToken │ '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' │ +│ remotePools[0] │ '0xb48EacF882dC4899Ae750AF4a6E2892E11866d8D' │ +│ remotePools[1] │ '0xAff3fE524ea94118EF09DaDBE3c77ba6AA0005EC' │ +│ rateLimiters.outbound.tokens │ '100000.0' │ +│ rateLimiters.outbound.capacity │ '100000.0' │ +│ rateLimiters.outbound.rate │ '167.0' │ +│ rateLimiters.outbound.timeToRefill │ '9m58s' │ +│ rateLimiters.inbound.tokens │ '100000.0' │ +│ rateLimiters.inbound.capacity │ '100000.0' │ +│ rateLimiters.inbound.rate │ '167.0' │ +│ rateLimiters.inbound.timeToRefill │ '9m58s' │ +└────────────────────────────────────┴──────────────────────────────────────────────┘ +...... +...... +...... +┌───────────────────────┬──────────────────────────────────────────────┐ +│ (index) │ Values │ +├───────────────────────┼──────────────────────────────────────────────┤ +│ address │ '0x838AB8F15867440A41C4149bcbba6ae402EfAd38' │ +│ symbol │ 'USDf' │ +│ name │ 'Falcon USD' │ +│ decimals │ 18 │ +│ pool │ '0x8210c0634AB8f273806e4b7866E9Db353773c44B' │ +│ pool.typeAndVersion │ 'BurnMintTokenPool 1.5.1' │ +│ remoteToken │ '0x3E34bFC2872534C331b6db2E4b3593FA7eaEddFd' │ +│ remotePools │ '0x21017CEC5f89fEb2c4B0F6C114E55Fa8EFDB00f2' │ +│ rateLimiters.outbound │ 'disabled' │ +│ rateLimiters.inbound │ 'disabled' │ +└───────────────────────┴──────────────────────────────────────────────┘ +┌───────────────────────┬──────────────────────────────────────────────┐ +│ (index) │ Values │ +├───────────────────────┼──────────────────────────────────────────────┤ +│ address │ '0xDA89A6C2c9f6E8d94E4a65d8AEe482908e9D709A' │ +│ symbol │ 'CCTWT' │ +│ name │ 'CCT Wizard Token' │ +│ decimals │ 18 │ +│ pool │ '0x3cD3CFAFb82a1Fd711753bb1a51F06a284bbd972' │ +│ pool.typeAndVersion │ 'BurnMintTokenPool 1.5.1' │ +│ remoteToken │ '0x74Ef0b124f192e0990B5451Ad12A4EC20FCf2B44' │ +│ remotePools │ '0x4dC3aA202138B40CC15867f2ab59153cF6FF83c4' │ +│ rateLimiters.outbound │ 'disabled' │ +│ rateLimiters.inbound │ 'disabled' │ +└───────────────────────┴──────────────────────────────────────────────┘ +┌───────────────────────┬──────────────────────────────────────────────┐ +│ (index) │ Values │ +├───────────────────────┼──────────────────────────────────────────────┤ +│ address │ '0x9BDdEBA9B0c051Ad5C1819D2F2671Af8B4D360B3' │ +│ symbol │ 'TT1' │ +│ name │ 'Test Token 1' │ +│ decimals │ 18 │ +│ pool │ '0x4Fc3534dEB27Bb61AfFFC5c02222594aF3024A61' │ +│ pool.typeAndVersion │ 'BurnMintTokenPool 1.5.1' │ +│ remoteToken │ '0x0325d145398Eeb977a55B39CC7847C48b84D93f5' │ +│ remotePools │ '0x0020267Ef0F96666A8CA236DB592547b14106807' │ +│ rateLimiters.outbound │ 'disabled' │ +│ rateLimiters.inbound │ 'disabled' │ +└───────────────────────┴──────────────────────────────────────────────┘ +Summary: totalTokens = 1070 , supportedTokens = 196 +``` + +<Aside type="note" title="Note"> + The `totalTokens` value represents the complete number of tokens registered or recognized by the system, regardless of their current usability for cross-chain transfers. In contrast, `supportedTokens` refers specifically to the subset of tokens that are currently eligible and configured for cross-chain transfers—meaning they have the necessary pools, remote mappings, and rate limiters set up. + + The difference between these numbers exists because not all tokens in the registry are ready or enabled for cross-chain operations. Some tokens may be inactive, lack required configuration, or are intentionally excluded from cross-chain support for security or operational reasons. As a result, `supportedTokens` is typically less than `totalTokens`. +</Aside> + +--- + # ChainlinkCCIP Tutorials Source: https://docs.chain.link/ccip/tutorials Last Updated: 2025-05-19 diff --git a/src/content/ccip/service-responsibility.mdx b/src/content/ccip/service-responsibility.mdx index 8a5f59355ea..83c01b33f54 100644 --- a/src/content/ccip/service-responsibility.mdx +++ b/src/content/ccip/service-responsibility.mdx @@ -58,7 +58,7 @@ Token Developers may enable token transfers on CCIP for the tokens that they adm - **Authorization**: Token Developers must verify that they are authorized to create token pools for a given token. Although anyone may create a token pool, the token developer must properly register that token with Chainlink CCIP. Token Developers must also properly configure the TokenAdminRegistry. - **Token pool configurations for [Rebasable Tokens](/ccip/concepts/cross-chain-token/evm/token-pools#tokens-with-rebasing-or-fee-on-transfer-mechanisms)**: Token Developers must properly write the logic in their token pool for burning and minting tokens based on the rebasing mechanism. - **Token transfer rate limits**: Token DeveloperToken Owners must select and configure appropriate token transfer rate limits for tokens on each lane where they choose to enable their token. -- **Token transfer types**: Token Developers must select appropriate token transfer type for their tokens; either [Burn and Mint](/ccip/concepts/cross-chain-token/overview#burn-and-mint), [Lock and Mint](/ccip/concepts/cross-chain-token/overview#lock-and-mint), or [Lock and Unlock](/ccip/concepts/cross-chain-token/overview#lock-and-unlock). Token Developers are responsible for implementing the burn and mint functions, lock and mint functions or lock and unlock functions in their token contracts correctly on all applicable chains. +- **Token transfer types**: Token Developers must select appropriate token transfer type for their tokens; either [Burn and Mint](/ccip/concepts/cross-chain-token/overview#burn-and-mint), [Lock and Mint](/ccip/concepts/cross-chain-token/overview#lock-and-mint), or [Lock and Unlock](/ccip/concepts/cross-chain-token/overview#lock-and-unlock). Token Developers are responsible for implementing the burn / mint / transfer functions in their token contracts correctly on all applicable chains. - **Migration between CCIP versions**: Token Developers who wish to adopt future versions of CCIP are responsible for all migration tasks required to adopt new features and functionality. - **Best Practices**: Token Developers are responsible for following the appropriate best practices for creating, managing, and enabling transfers of their tokens on Chainlink CCIP. - **Token Developer Attestation**: Token Developers are responsible for ensuring the quality, reliability, and security of their associated attestation endpoint(s). Token Developers are responsible for adhering to Chainlink-defined specifications and maintaining an up-to-date implementation. Neither Chainlink Labs nor the Chainlink Foundation are responsible for the development, maintenance, or operation of Token Developer Attestation endpoints. diff --git a/src/content/ccip/tutorials/aptos/destination/programmable-token-transfers.mdx b/src/content/ccip/tutorials/aptos/destination/programmable-token-transfers.mdx index bff311532f2..ed800e9a2e7 100644 --- a/src/content/ccip/tutorials/aptos/destination/programmable-token-transfers.mdx +++ b/src/content/ccip/tutorials/aptos/destination/programmable-token-transfers.mdx @@ -57,7 +57,7 @@ A programmable token transfer combines the features of a token transfer and an a <Aside title="Disclaimer" type="caution"> The `ccip_message_receiver` module used in this tutorial **should only be used with non-dispatchable tokens**, as it is currently incompatible with [dispatchable - tokens](https://aptosfoundation.org/currents/dispatchable-fungible-assets-101). + tokens](https://aptos.dev/build/smart-contracts/fungible-asset#dispatchable-fungible-asset-advanced). </Aside> This tutorial uses the `ccip_message_receiver` module from the `aptos-starter-kit`. Its `ccip_receive` function contains dispatcher logic. For this tutorial, we will trigger the part of its logic that handles a message containing both tokens and data. diff --git a/src/content/ccip/tutorials/aptos/receivers.mdx b/src/content/ccip/tutorials/aptos/receivers.mdx index 5aa87ecef4b..c72e5cca84b 100644 --- a/src/content/ccip/tutorials/aptos/receivers.mdx +++ b/src/content/ccip/tutorials/aptos/receivers.mdx @@ -23,7 +23,7 @@ This reference guide assumes familiarity with: - The [Move language](https://move-language.github.io/move/) and the [Aptos framework](https://aptos.dev/en/network/blockchain/move) - [Aptos module development and deployment](https://aptos.dev/en/build/smart-contracts) -- The [CCIP architecture](/ccip/concepts/architecture) +- The [CCIP architecture](/ccip/concepts/architecture/overview) </Aside> diff --git a/src/content/ccip/tutorials/evm/ccipreceive-gaslimit.mdx b/src/content/ccip/tutorials/evm/ccipreceive-gaslimit.mdx index e7b48b9fd10..dda635ec85a 100644 --- a/src/content/ccip/tutorials/evm/ccipreceive-gaslimit.mdx +++ b/src/content/ccip/tutorials/evm/ccipreceive-gaslimit.mdx @@ -306,7 +306,7 @@ To estimate the gas usage of the `ccipReceive` function within your own Hardhat **_Note_:** The `MockCCIPRouter` receives the CCIP message from your CCIP Sender, calls the `ccipReceive` function on your CCIP Receiver, and emits the `MsgExecuted` event with the gas used. 1. Create a testing file in your project's `test` directory. -1. Inside the `deployFixture` function, deploy the `MockCCIPRouter` contract and use its address to deploy your CCIP Sender and CCIP Receiver contracts. For more details, check this [example](https://github.com/smartcontractkit/smart-contract-examples/blob/ccip/estimate-gas/hardhat/test/Send-Receive.ts#L14). +1. Inside the `deployFixture` function, deploy the `MockCCIPRouter` contract and use its address to deploy your CCIP Sender and CCIP Receiver contracts. For more details, check this [example](https://github.com/smartcontractkit/smart-contract-examples/blob/main/ccip/estimate-gas/hardhat/test/Send-Receive.ts#L11). 1. In your test cases: 1. Send the CCIP message to the `MockCCIPRouter` contract. For more details, check this [example](https://github.com/smartcontractkit/smart-contract-examples/blob/main/ccip/estimate-gas/hardhat/test/Send-Receive.ts#L77). 1. Parse the logs to find the `MsgExecuted(bool,bytes,uint256)` event and extract the gas used. For more details, check this [example](https://github.com/smartcontractkit/smart-contract-examples/blob/main/ccip/estimate-gas/hardhat/test/Send-Receive.ts#L59). diff --git a/src/content/ccip/tutorials/evm/cross-chain-tokens/index.mdx b/src/content/ccip/tutorials/evm/cross-chain-tokens/index.mdx index e4c5f5249dc..5e624468435 100644 --- a/src/content/ccip/tutorials/evm/cross-chain-tokens/index.mdx +++ b/src/content/ccip/tutorials/evm/cross-chain-tokens/index.mdx @@ -18,7 +18,7 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" <Aside type="note" title="Prerequisites"> Familiarize yourself with the [CCT standard](/ccip/concepts/cross-chain-token/overview) and [CCIP - architecture](/ccip/concepts/architecture) before proceeding with these tutorials. + architecture](/ccip/concepts/architecture/overview) before proceeding with these tutorials. </Aside> Before diving into the [tutorials](#tutorials), it's important first to understand the overall procedure for enabling your tokens in CCIP. This procedure involves deploying tokens and token pools, registering administrative roles, and configuring token pools to enable secure token transfers using CCIP. The diagram below outlines the entire process: diff --git a/src/content/ccip/tutorials/evm/index.mdx b/src/content/ccip/tutorials/evm/index.mdx index 9e2bccbbc49..c705e23d5b9 100644 --- a/src/content/ccip/tutorials/evm/index.mdx +++ b/src/content/ccip/tutorials/evm/index.mdx @@ -28,7 +28,6 @@ You can explore several comprehensive guides to learn about cross-chain interope - [Using CCIP CLI](/ccip/tutorials/evm/offchain/ccip-tools) - [Transfer Tokens between EOAs](/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa) - [Checking CCIP Message Status](/ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain) - - [Get Supported Tokens](/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens) - [Transfer USDC with Data](/ccip/tutorials/evm/usdc) - [Send Arbitrary Data](/ccip/tutorials/evm/send-arbitrary-data) - [Send Arbitrary Data and Receive Transfer Confirmation: A -> B -> A](/ccip/tutorials/evm/send-arbitrary-data-receipt-acknowledgment) diff --git a/src/content/ccip/tutorials/evm/manual-execution.mdx b/src/content/ccip/tutorials/evm/manual-execution.mdx index 8b7055a533b..517cd94526c 100644 --- a/src/content/ccip/tutorials/evm/manual-execution.mdx +++ b/src/content/ccip/tutorials/evm/manual-execution.mdx @@ -50,7 +50,10 @@ In this tutorial, you'll send a text _string_ and CCIP-BnM tokens between smart 1. Manually retry the execution. 1. Observe successful execution after the gas limit adjustment. -<CodeSample src="samples/CCIP/ProgrammableTokenTransfersLowGasLimit.sol" /> +<CodeSample + src="samples/CCIP/ProgrammableTokenTransfersLowGasLimit.sol" + filename="ProgrammableTokenTransfersLowGasLimit.sol" +/> ### Deploy your contracts diff --git a/src/content/ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain.mdx b/src/content/ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain.mdx index 86adb4397e4..fe419a5fd6f 100644 --- a/src/content/ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain.mdx +++ b/src/content/ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain.mdx @@ -10,14 +10,12 @@ metadata: lastModified: "2025-05-19" estimatedTime: "15 minutes" difficulty: "intermediate" -whatsnext: - "Get Supported Tokens": "/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens" --- import { CodeSample, ClickToZoom, CopyText, Aside } from "@components" import CcipCommon from "@features/ccip/CcipCommon.astro" -In this tutorial, you will learn how to verify the status of a Chainlink CCIP transaction offchain using [CCIP Tools](https://github.com/smartcontractkit/ccip-tools-ts). Starting with a CCIP source transaction hash, you'll execute the [`show`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/README.md#show-default-command) command of the `ccip-tools` to query the current status of a cross-chain message. +In this tutorial, you will learn how to verify the status of a Chainlink CCIP transaction offchain using [CCIP Tools](https://github.com/smartcontractkit/ccip-tools-ts). Starting with a CCIP source transaction hash, you'll execute the [`show`](https://github.com/smartcontractkit/ccip-tools-ts/tree/main/ccip-cli#show-default-command) command of the `ccip-tools` to query the current status of a cross-chain message. ## Before you begin @@ -26,7 +24,7 @@ In this tutorial, you will learn how to verify the status of a Chainlink CCIP tr ## Tutorial -This tutorial shows you on how to check the status of a Chainlink CCIP transaction using the [`show`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/README.md#show-default-command) command of the `ccip-tools`. By supplying the command with the source transaction hash, you can verify the current status of your cross-chain message. +This tutorial shows you on how to check the status of a Chainlink CCIP transaction using the [`show`](https://github.com/smartcontractkit/ccip-tools-ts/tree/main/ccip-cli#show-default-command) command of the `ccip-tools`. By supplying the command with the source transaction hash, you can verify the current status of your cross-chain message. **Execute the script in your command line:** @@ -40,7 +38,7 @@ This tutorial shows you on how to check the status of a Chainlink CCIP transacti <Aside type="note" title="Note"> The `--page` option is used to limit the number of blocks to search for the message. The default value is `10000` - which could result in an error due to RPC limitations. Setting it to `500` is a good practice to avoid such issues. + which could result in an error due to RPC limitations. Setting it to `10` is a good practice to avoid such issues. </Aside> **Example Usage:** @@ -48,7 +46,7 @@ This tutorial shows you on how to check the status of a Chainlink CCIP transacti If you initiated a transaction from _Avalanche Fuji_ to _Ethereum Sepolia_ and received the source transaction hash, you can check the status of your CCIP message with the following command: ```text -$ ./src/index.ts show 0x980dacf245f9c6919678219e97d6ad20e0c1964795ec3801e688315f1f18defd --page 500 +$ ./ccip-cli/ccip-cli show 0xcefd14da01d3d607ba98dae33b2941ef07499051eaa61e3a417b5734d91ad021 --page 10 Lane: ┌────────────────┬──────────────────────────────────────────────┬────────────────────────────┐ @@ -63,46 +61,46 @@ Request (source): ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ -│ messageId │ '0x1ce5213bf9880b18be7f44d5ab1065e603ec3a83eb1bebf76af366ed3c0de0b3' │ +│ messageId │ '0xb9672cd93b24b9071c2eee11b27daca00dbdac58239c40bca06c23fbb172e992' │ │ origin │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ sender │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ receiver │ '0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf' │ -│ sequenceNumber │ 3835 │ -│ nonce │ 4 │ -│ gasLimit │ 200000 │ -│ transactionHash │ '0x980dacf245f9c6919678219e97d6ad20e0c1964795ec3801e688315f1f18defd' │ -│ logIndex │ 6 │ -│ blockNumber │ 40954056 │ -│ timestamp │ '2025-05-26 16:34:14 (2h8m33s ago)' │ +│ sequenceNumber │ 7389n │ +│ nonce │ 22n │ +│ gasLimit │ 0n │ +│ transactionHash │ '0xcefd14da01d3d607ba98dae33b2941ef07499051eaa61e3a417b5734d91ad021' │ +│ logIndex │ 16 │ +│ blockNumber │ 49144702 │ +│ timestamp │ '2025-12-16 14:36:00 (24m4s ago)' │ │ finalized │ true │ -│ fee │ '0.040903083926519498 LINK' │ +│ fee │ '0.104497184834156911 WAVAX' │ │ tokens │ '0.001 CCIP-BnM' │ │ data │ '0x' │ +│ strict │ false │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ Commit (dest): ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ -│ merkleRoot │ '0x1ce5213bf9880b18be7f44d5ab1065e603ec3a83eb1bebf76af366ed3c0de0b3' │ -│ min │ 3835 │ -│ max │ 3835 │ -│ origin │ '0x9e587c646d4f4e46B71a02179Fa8951CFB34A382' │ +│ merkleRoot │ '0xb9672cd93b24b9071c2eee11b27daca00dbdac58239c40bca06c23fbb172e992' │ +│ min │ 7389 │ +│ max │ 7389 │ +│ origin │ '0x94193d65DF1f4834081B7F1aF1ecB11CFdECc608' │ │ contract │ '0x139E06b6dBB1a0C41A1686C091795879c943765A' │ -│ transactionHash │ '0xbda1e294e59910e2929e6aec08e52426a9125c1ac20509b9d5b9441789b746b0' │ -│ blockNumber │ 8411619 │ -│ timestamp │ '2025-05-26 16:35:00 (46s after request)' │ +│ transactionHash │ '0x57020e1a913451bb9e44190452252150158ae0d71ff117e2889cf0dc99c77cee' │ +│ blockNumber │ 9853657 │ +│ timestamp │ '2025-12-16 14:36:48 (48s after request)' │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ Receipts (dest): ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ │ state │ '✅ success' │ -│ returnData │ '0x' │ -│ origin │ '0xdA743Ce0Eb7cC541093F030A3126bF9e3d427E93' │ -│ offRamp │ '0x1DEBa99dC8e2A77832461BD386d83D9FCb133137' │ -│ transactionHash │ '0xe68ae80ed0b77d6e22f066a08c169c873dd22112ef5f27287bbe85e737c6ec60' │ -│ logIndex │ 114 │ -│ blockNumber │ 8411627 │ -│ timestamp │ '2025-05-26 16:36:36 (2m22s after request)' │ +│ origin │ '0x9Fa36294177c7adf9df4cC35fFcF0f47Dd3468D9' │ +│ contract │ '0x1DEBa99dC8e2A77832461BD386d83D9FCb133137' │ +│ transactionHash │ '0x38b5edcc7b7fc24a97120b5ac57f8023308784a5a97c92c251d3a67886197630' │ +│ logIndex │ 3 │ +│ blockNumber │ 9853664 │ +│ timestamp │ '2025-12-16 14:38:12 (2m12s after request)' │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ ``` diff --git a/src/content/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens.mdx b/src/content/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens.mdx index 281b457b685..802e54e23ff 100644 --- a/src/content/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens.mdx +++ b/src/content/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens.mdx @@ -15,7 +15,7 @@ metadata: import { CodeSample, ClickToZoom, CopyText, Aside } from "@components" import CcipCommon from "@features/ccip/CcipCommon.astro" -In this tutorial, you will learn how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP, with [CCIP Tools](https://github.com/smartcontractkit/ccip-tools-ts). You'll use the [`getSupportedTokens`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/README.md#getsupportedtokens) command of `ccip-tools` to query the list of supported tokens that can be transferred from a specific source chain to a specific destination chain. +In this tutorial, you will learn how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP, with [CCIP Tools](https://github.com/smartcontractkit/ccip-tools-ts). You'll use the [`getSupportedTokens`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-cli/README.md#getsupportedtokens) command of `ccip-tools` to query the list of supported tokens that can be transferred from a specific source chain to a specific destination chain. ## Before you begin @@ -23,12 +23,12 @@ Complete the prerequisite steps of the [Transfer Tokens between EOAs](/ccip/tuto ## Tutorial -This tutorial shows you how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP. By supplying the [`getSupportedTokens`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/README.md#getsupportedtokens) command of `ccip-tools` with a source chain, source router address, and a destination chain, you can get the list of supported tokens that can be transferred from the source chain to the destination chain. +This tutorial shows you how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP. By supplying the [`getSupportedTokens`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-cli/README.md#getsupportedtokens) command of `ccip-tools` with a source chain, source router address, and a destination chain, you can get the list of supported tokens that can be transferred from the source chain to the destination chain. **Execute the script in your command line:** ```bash -./src/index.ts getSupportedTokens <source> <router> <dest> +./ccip-cli/ccip-cli getSupportedTokens <source> <router> <dest> ``` **The script requires the following parameters:** @@ -38,7 +38,7 @@ This tutorial shows you how to retrieve the list of supported tokens that can be For example, `43113` for _Avalanche Fuji_ or `11155111` for _Ethereum Sepolia_. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. You can find the supported network names and chain IDs that can be used for `source` in the - [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/src/lib/selectors.ts) file of the + [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-sdk/src/selectors.ts) file of the `ccip-tools` repository. - `router`: Router contract address on the source network. @@ -50,7 +50,7 @@ This tutorial shows you how to retrieve the list of supported tokens that can be For example, `43113` for _Avalanche Fuji_ or `11155111` for _Ethereum Sepolia_. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. You can find the supported network names and chain IDs that can be used for `dest` in the - [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/src/lib/selectors.ts) file of the + [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-sdk/src/selectors.ts) file of the `ccip-tools` repository. **Example Usage:** @@ -58,7 +58,7 @@ This tutorial shows you how to retrieve the list of supported tokens that can be If you would like to retrieve the list of supported tokens that can be transferred from _Avalanche Fuji_ to _Ethereum Sepolia_, you can run the following command: ```text -$ ./src/index.ts getSupportedTokens 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 +$ ./ccip-cli/ccip-cli getSupportedTokens 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 [INFO] Starting token discovery for cross-chain transfers [INFO] Using TokenAdminRegistry 1.5.0 at 0xA92053a4a3922084d992fD2835bdBa4caC6877e6 from router 0xF694E193200268f9a4868e4Aa017A0118C9a8177 diff --git a/src/content/ccip/tutorials/evm/offchain/ccip-tools/index.mdx b/src/content/ccip/tutorials/evm/offchain/ccip-tools/index.mdx index 8b8df406e74..bfe54fc2a83 100644 --- a/src/content/ccip/tutorials/evm/offchain/ccip-tools/index.mdx +++ b/src/content/ccip/tutorials/evm/offchain/ccip-tools/index.mdx @@ -18,4 +18,3 @@ These tutorials demonstrate how to use [CCIP Tools](https://github.com/smartcont - [Transfer Tokens Between EOAs](/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa): Learn how to transfer tokens between Externally Owned Accounts (EOAs) across different blockchains using Chainlink CCIP. - [Check CCIP Message Status Off-Chain](/ccip/tutorials/evm/offchain/ccip-tools/get-status-offchain): Learn how to verify the status of Chainlink CCIP messages off-chain. -- [Get Supported Tokens](/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens): Learn how to retrieve the list of supported tokens that can be transferred between chains using Chainlink CCIP. diff --git a/src/content/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa.mdx b/src/content/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa.mdx index 08e52b91645..659f9f23c9e 100644 --- a/src/content/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa.mdx +++ b/src/content/ccip/tutorials/evm/offchain/ccip-tools/transfer-tokens-from-eoa.mdx @@ -28,7 +28,7 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y ## Before you begin -1. [Install Node.js 18](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 18`. +1. [Install Node.js 22](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 22`. ```shell node -v @@ -36,14 +36,14 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y ```shell $ node -v - v18.7.0 + v22.15.0 ``` 1. Your [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) must have both AVAX and LINK tokens on _Avalanche Fuji_ to pay for the gas fees and CCIP fees. - [Configure MetaMask to use LINK tokens](/resources/acquire-link#configure-metamask-to-use-link-tokens) - Acquire testnet AVAX and LINK from [faucets.chain.link/fuji](https://faucets.chain.link/fuji) -1. Check the [CCIP Directory](/ccip/directory) to confirm that the tokens you will transfer are supported for your lane. In this example, you will transfer tokens from _Avalanche Fuji_ to _Ethereum Sepolia_ so check the list of supported tokens [here](/ccip/directory/testnet/chain/avalanche-fuji-testnet). Alternatively, you can use the [Get Supported Tokens](/ccip/tutorials/evm/offchain/ccip-tools/get-supported-tokens) tutorial to retrieve the list of supported tokens programmatically. +1. Check the [CCIP Directory](/ccip/directory) to confirm that the tokens you will transfer are supported for your lane. In this example, you will transfer tokens from _Avalanche Fuji_ to _Ethereum Sepolia_ so check the list of supported tokens [here](/ccip/directory/testnet/chain/avalanche-fuji-testnet). 1. Learn how to [acquire CCIP test tokens](/ccip/test-tokens#evm-chains). After following this guide, your [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) should have CCIP-BnM tokens, and CCIP-BnM should appear in the list of your tokens in MetaMask. @@ -63,7 +63,7 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y 1. To make sure that the installation is correct and the `ccip-tools` CLI commands are available, run the following command: ```shell - ./dist/ccip-tools-ts --help + ./ccip-cli/ccip-cli --help ``` 1. Inside the project's root folder, i.e., `ccip-tools-ts`, create a `.env` file and add two environment variables to store the RPC URLs: @@ -101,7 +101,7 @@ In this example, you will transfer CCIP-BnM tokens from your EOA on _Avalanche F For this example, CCIP fees are paid in LINK tokens. To learn how to pay CCIP fees in native AVAX, read the [Pay in native](#transfer-tokens-and-pay-in-native) section. To transfer tokens and pay in LINK, use the following command: ``` -./src/index.ts send <source> <router> <dest> \ +./ccip-cli/ccip-cli send <source> <router> <dest> \ --receiver <destinationAccount> \ --fee-token <feeTokenAddress> \ --transfer-tokens <tokenAddress>=<amount> @@ -112,7 +112,7 @@ For this example, CCIP fees are paid in LINK tokens. To learn how to pay CCIP fe If you have Foundry installed and have imported your private key into an encrypted keystore using the [`cast wallet import`](https://book.getfoundry.sh/reference/cast/cast-wallet-import) command, you can pass the path to that keystore file as the value of the `--wallet` flag in your command, like this: ``` -./src/index.ts send <source> <router> <dest> \ +./ccip-cli/ccip-cli send <source> <router> <dest> \ --receiver <destinationAccount> \ --fee-token <feeTokenAddress> \ --transfer-tokens <tokenAddress>=<amount> \ @@ -135,7 +135,7 @@ export USER_KEY_PASSWORD=<YOUR_KEYSTORE_FILE_PASSWORD> For example, `43113` for _Avalanche Fuji_ or `11155111` for _Ethereum Sepolia_. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. You can find the supported network names and chain IDs that can be used for `source` in the - [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/src/lib/selectors.ts) file of the + [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-sdk/src/selectors.ts) file of the `ccip-tools` repository. - `router`: Router contract address on the source network. @@ -145,7 +145,7 @@ export USER_KEY_PASSWORD=<YOUR_KEYSTORE_FILE_PASSWORD> For example, `43113` for _Avalanche Fuji_ or `11155111` for _Ethereum Sepolia_. You can also use the network name, such as `avalanche-testnet-fuji` or `ethereum-testnet-sepolia`. You can find the supported network names and chain IDs that can be used for `dest` in the - [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/src/lib/selectors.ts) file of the + [`selectors.ts`](https://github.com/smartcontractkit/ccip-tools-ts/blob/main/ccip-sdk/src/selectors.ts) file of the `ccip-tools` repository. - `destinationAccount`: Address of the destination account on the destination network. Skip this argument to use the same address as the source account. @@ -161,7 +161,7 @@ Complete the following steps in your terminal: 1. Send 0.001 CCIP-BnM from your EOA on _Avalanche Fuji_ to another account on _Ethereum Sepolia_: ``` - ./src/index.ts send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ + ./ccip-cli/ccip-cli send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ --receiver 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf \ --fee-token 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 \ --transfer-tokens 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4=0.001 \ @@ -172,7 +172,7 @@ Complete the following steps in your terminal: | Argument | Explanation | | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | <CopyText text="./src/index.ts send" code/> | This executes the `send` command of the `ccip-tools`. | + | <CopyText text="./ccip-cli/ccip-cli send" code/> | This executes the `send` command of the `ccip-tools`. | | <CopyText text="43113" code/> | This specifies the source blockchain, in this case, _Avalanche Fuji_. | | <CopyText text="0xF694E193200268f9a4868e4Aa017A0118C9a8177" code/> | This specifies the router address on the source blockchain, in this case, _Avalanche Fuji_. | | <CopyText text="11155111" code/> | This specifies the destination blockchain, which is _Ethereum Sepolia_ in this case. | @@ -188,15 +188,14 @@ Complete the following steps in your terminal: 1. Once you execute the command, you should see the following logs: ``` - $ ./src/index.ts send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ + $ ./ccip-cli/ccip-cli send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ --receiver 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf \ --fee-token 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 \ --transfer-tokens 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4=0.001 \ --gas-limit 0 - Approving 1000000000000000n 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 for 0xF694E193200268f9a4868e4Aa017A0118C9a8177 = 0xa3fd8053a74b71f34c4c280f10fdcba51ea105093998f8349db14485473da912 - Approving 23112499163862214n 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 for 0xF694E193200268f9a4868e4Aa017A0118C9a8177 = 0xb21d2822c7211a6bd39310ae78f4b59ef54ed6271fea21c949d9be78a30f12a7 - Sending message to 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf @ ethereum-testnet-sepolia , tx_hash = 0x70858cfeadcfbd1404a65dd4116b549801bde3d184eb324f895529286e15249a + Fee: 133133029529487157n = 0.133133029529487157 LINK + 🚀 Sending message to 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf @ ethereum-testnet-sepolia , tx => 0x76a472470de779bef81843abeb3e1d0541bf35d63f23b3229857638764f3e149 , messageId => 0xf6ae12f8cf81d389613a8de82b1fd1b39542a2c99a58a1c580be7b8dc0603f9d Lane: ┌────────────────┬──────────────────────────────────────────────┬────────────────────────────┐ │ (index) │ source │ dest │ @@ -210,21 +209,22 @@ Complete the following steps in your terminal: ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ - │ messageId │ '0x934f57925b5d8fbc763c2a06dfe2d003676816f8ea67392d3e7888a45469d4c1' │ + │ messageId │ '0xf6ae12f8cf81d389613a8de82b1fd1b39542a2c99a58a1c580be7b8dc0603f9d' │ │ origin │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ sender │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ receiver │ '0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf' │ - │ sequenceNumber │ 3859 │ - │ nonce │ 17 │ - │ gasLimit │ 0 │ - │ transactionHash │ '0x70858cfeadcfbd1404a65dd4116b549801bde3d184eb324f895529286e15249a' │ - │ logIndex │ 6 │ - │ blockNumber │ 41234897 │ - │ timestamp │ '2025-06-02 16:19:51 (10s ago)' │ + │ sequenceNumber │ 7388n │ + │ nonce │ 21n │ + │ gasLimit │ 0n │ + │ transactionHash │ '0x76a472470de779bef81843abeb3e1d0541bf35d63f23b3229857638764f3e149' │ + │ logIndex │ 14 │ + │ blockNumber │ 49144482 │ + │ timestamp │ '2025-12-16 14:31:03 (7s ago)' │ │ finalized │ true │ - │ fee │ '0.023112499163862214 LINK' │ + │ fee │ '0.133133029529487157 LINK' │ │ tokens │ '0.001 CCIP-BnM' │ │ data │ '0x' │ + │ strict │ false │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ ``` @@ -255,7 +255,7 @@ For this example, CCIP fees are paid in Avalanche Fuji's native AVAX. To learn h To transfer tokens and pay in native, use the following command: ``` -./src/index.ts send <source> <router> <dest> \ +./ccip-cli/ccip-cli send <source> <router> <dest> \ --receiver <destinationAccount> \ --transfer-tokens <tokenAddress>=<amount> \ --gas-limit 0 @@ -265,7 +265,7 @@ To transfer tokens and pay in native, use the following command: If you have Foundry installed and have imported your private key into an encrypted keystore using the [`cast wallet import`](https://book.getfoundry.sh/reference/cast/cast-wallet-import) command, you can pass the path to that keystore file as the value of the `--wallet` flag in your command, like this: ``` -./src/index.ts send <source> <router> <dest> \ +./ccip-cli/ccip-cli send <source> <router> <dest> \ --receiver <destinationAccount> \ --transfer-tokens <tokenAddress>=<amount> \ --gas-limit 0 \ @@ -288,7 +288,7 @@ Complete the following steps in your terminal: 1. Send 0.001 CCIP-BnM from your EOA on _Avalanche Fuji_ to another account on _Ethereum Sepolia_: ``` - ./src/index.ts send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ + ./ccip-cli/ccip-cli send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ --receiver 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf \ --transfer-tokens 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4=0.001 \ --gas-limit 0 @@ -298,7 +298,7 @@ Complete the following steps in your terminal: | Argument | Explanation | | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | <CopyText text="./src/index.ts send" code/> | This executes the `send` command of the `ccip-tools`. | + | <CopyText text="./ccip-cli/ccip-cli send" code/> | This executes the `send` command of the `ccip-tools`. | | <CopyText text="43113" code/> | This specifies the source blockchain, in this case, _Avalanche Fuji_. | | <CopyText text="0xF694E193200268f9a4868e4Aa017A0118C9a8177" code/> | This specifies the router address on the source blockchain, in this case, _Avalanche Fuji_. | | <CopyText text="11155111" code/> | This specifies the destination blockchain, which is _Ethereum Sepolia_ in this case. | @@ -312,13 +312,13 @@ Complete the following steps in your terminal: 1. After you execute the command, you should see the following logs: ``` - $ ./src/index.ts send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ + $ ./ccip-cli/ccip-cli send 43113 0xF694E193200268f9a4868e4Aa017A0118C9a8177 11155111 \ --receiver 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf \ --transfer-tokens 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4=0.001 \ --gas-limit 0 - Approving 1000000000000000n 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 for 0xF694E193200268f9a4868e4Aa017A0118C9a8177 = 0x1ea6d165cf627fd4f6856520fc9afa2e08c4e04f79fd78bf7f4ef7da94692503 - Sending message to 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf @ ethereum-testnet-sepolia , tx_hash = 0x0a00f9240b6860e34a0664ad0aa8f8e86877d70b97e9787e08e270bea564edce + Fee: 104497184834156911n = 0.104497184834156911 AVAX + 🚀 Sending message to 0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf @ ethereum-testnet-sepolia , tx => 0xcefd14da01d3d607ba98dae33b2941ef07499051eaa61e3a417b5734d91ad021 , messageId => 0xb9672cd93b24b9071c2eee11b27daca00dbdac58239c40bca06c23fbb172e992 Lane: ┌────────────────┬──────────────────────────────────────────────┬────────────────────────────┐ │ (index) │ source │ dest │ @@ -332,21 +332,22 @@ Complete the following steps in your terminal: ┌─────────────────┬──────────────────────────────────────────────────────────────────────┐ │ (index) │ Values │ ├─────────────────┼──────────────────────────────────────────────────────────────────────┤ - │ messageId │ '0xd902134a69bff565005c354996386479f9b1204b1810f49e27abc8c413c64312' │ + │ messageId │ '0xb9672cd93b24b9071c2eee11b27daca00dbdac58239c40bca06c23fbb172e992' │ │ origin │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ sender │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │ │ receiver │ '0x27d7A69C878F9c8f51f4e53703abCE9bAcd2D9bf' │ - │ sequenceNumber │ 3861 │ - │ nonce │ 18 │ - │ gasLimit │ 0 │ - │ transactionHash │ '0x0a00f9240b6860e34a0664ad0aa8f8e86877d70b97e9787e08e270bea564edce' │ - │ logIndex │ 11 │ - │ blockNumber │ 41235059 │ - │ timestamp │ '2025-06-02 16:25:12 (7s ago)' │ + │ sequenceNumber │ 7389n │ + │ nonce │ 22n │ + │ gasLimit │ 0n │ + │ transactionHash │ '0xcefd14da01d3d607ba98dae33b2941ef07499051eaa61e3a417b5734d91ad021' │ + │ logIndex │ 16 │ + │ blockNumber │ 49144702 │ + │ timestamp │ '2025-12-16 14:36:00 (6s ago)' │ │ finalized │ true │ - │ fee │ '0.019124641265363576 WAVAX' │ + │ fee │ '0.104497184834156911 WAVAX' │ │ tokens │ '0.001 CCIP-BnM' │ │ data │ '0x' │ + │ strict │ false │ └─────────────────┴──────────────────────────────────────────────────────────────────────┘ ``` diff --git a/src/content/ccip/tutorials/evm/offchain/transfer-tokens-from-eoa.mdx b/src/content/ccip/tutorials/evm/offchain/transfer-tokens-from-eoa.mdx index 43c857739e0..ad7f746b1f0 100644 --- a/src/content/ccip/tutorials/evm/offchain/transfer-tokens-from-eoa.mdx +++ b/src/content/ccip/tutorials/evm/offchain/transfer-tokens-from-eoa.mdx @@ -28,7 +28,7 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y ## Before you begin -1. [Install Node.js 18](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 18`. +1. [Install Node.js 22](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 22`. ```shell node -v @@ -36,7 +36,7 @@ In this tutorial, you will use Chainlink CCIP to transfer tokens directly from y ```shell $ node -v - v18.7.0 + v22.15.0 ``` 1. Your [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) must have both AVAX and LINK tokens on _Avalanche Fuji_ to pay for the gas fees and CCIP fees. diff --git a/src/content/ccip/tutorials/evm/programmable-token-transfers-defensive.mdx b/src/content/ccip/tutorials/evm/programmable-token-transfers-defensive.mdx index 0b5d6141d56..972dd9696b3 100644 --- a/src/content/ccip/tutorials/evm/programmable-token-transfers-defensive.mdx +++ b/src/content/ccip/tutorials/evm/programmable-token-transfers-defensive.mdx @@ -50,7 +50,10 @@ In this guide, you'll initiate a transaction from a smart contract on _Avalanche that for successful scenarios. </Aside> -<CodeSample src="samples/CCIP/ProgrammableDefensiveTokenTransfers.sol" /> +<CodeSample + src="samples/CCIP/ProgrammableDefensiveTokenTransfers.sol" + filename="ProgrammableDefensiveTokenTransfers.sol" +/> ### Deploy your contracts diff --git a/src/content/ccip/tutorials/evm/token-manager.mdx b/src/content/ccip/tutorials/evm/token-manager.mdx index 3048f276956..9751170f3fa 100644 --- a/src/content/ccip/tutorials/evm/token-manager.mdx +++ b/src/content/ccip/tutorials/evm/token-manager.mdx @@ -142,7 +142,7 @@ If you have existing token(s) that you've already deployed, you can use the Toke Before selecting a token pool type, be sure to review [CCIP token handling mechanisms](/ccip/concepts/cross-chain-token/overview#token-handling-mechanisms). -1. On the **Networks** page, select the additional blockchain networks where you'd like to deploy your new token. For additional networks, Token Manager Wizard workflow automatically configures all tokens with the Burn & Mint mechanism. (Refer to the [token contract](https://github.com/smartcontractkit/chainlink/blob/contracts-ccip/v1.6.0-beta.0/contracts/src/v0.8/ccip/tokenAdminRegistry/TokenPoolFactory/FactoryBurnMintERC20.sol) and [token pool contract](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/src/v0.8/ccip/pools/BurnMintTokenPool.sol) for the Burn & Mint mechanism.) +1. On the **Networks** page, select the additional blockchain networks where you'd like to deploy your new token. For additional networks, Token Manager Wizard workflow automatically configures all tokens with the Burn & Mint mechanism. (Refer to the [token contract](https://github.com/smartcontractkit/chainlink-evm/blob/contracts-v1.4.0/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol) and [token pool contract](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-v1.6.1/chains/evm/contracts/pools/BurnMintTokenPool.sol) for the Burn & Mint mechanism.) 1. On the **Summary** page, each network you've selected appears along with an expandable list of the transactions the Token Manager will guide you through to deploy your token for each network. If you selected more than two networks during the previous step, the _Remove_ links are active, allowing you to remove a network before proceeding. If you only have two networks selected, the _Remove_ links are intentionally not active. If you need to add more networks, navigate back to the **Networks** page. diff --git a/src/content/ccip/tutorials/evm/usdc.mdx b/src/content/ccip/tutorials/evm/usdc.mdx index 3edeb44db87..608347f5778 100644 --- a/src/content/ccip/tutorials/evm/usdc.mdx +++ b/src/content/ccip/tutorials/evm/usdc.mdx @@ -46,7 +46,7 @@ Chainlink CCIP maintains a consistent [API](/ccip/api-reference/evm/v1.6.1/i-rou - The sender has to interact with the CCIP router to initiate a cross-chain transaction, similar to the process for any other token transfers. See the [Transfer Tokens](/ccip/tutorials/evm/transfer-tokens-from-contract) guide to learn more. - The process uses the same onchain components including the Router, OnRamp, Commit Store, OffRamp, and Token Pool. - The process uses the same offchain components including the Committing DON, Executing DON, and the Risk Management Network. -- USDC transfers also benefit from CCIP additional security provided by the [Risk Management Network](/ccip/concepts/architecture/key-concepts#risk-management-network). +- USDC transfers also benefit from CCIP additional security provided by the Risk Management Network. #### Native USDC (CCTP-enabled) diff --git a/src/content/ccip/tutorials/svm/receivers.mdx b/src/content/ccip/tutorials/svm/receivers.mdx index 8c92b8d0ccf..8072311a03c 100644 --- a/src/content/ccip/tutorials/svm/receivers.mdx +++ b/src/content/ccip/tutorials/svm/receivers.mdx @@ -25,7 +25,7 @@ This reference guide assumes familiarity with: framework](https://www.anchor-lang.com/) - [Solana program development](https://solana.com/docs) -- [CCIP architecture](/ccip/concepts/architecture) +- [CCIP architecture](/ccip/concepts/architecture/overview) </Aside> @@ -413,6 +413,6 @@ When implementing CCIP Receivers, follow these best practices: ## Example Implementation -For a complete, audited reference implementation of a CCIP Receiver, you can examine the [example-ccip-receiver](https://github.com/smartcontractkit/chainlink-ccip/tree/v1.6.0-solana/chains/solana/contracts/programs/example-ccip-receiver) in the Chainlink CCIP repository. This example demonstrates all the security patterns and best practices covered in this guide and can serve as a starting point for your own implementation. +For a complete, audited reference implementation of a CCIP Receiver, you can examine the [example-ccip-receiver](https://github.com/smartcontractkit/chainlink-ccip/tree/solana-v1.6.0/chains/solana/contracts/programs/example-ccip-receiver) in the Chainlink CCIP repository. This example demonstrates all the security patterns and best practices covered in this guide and can serve as a starting point for your own implementation. <CcipCommon callout="educationalDisclaimer" /> diff --git a/src/content/chainlink-automation/guides/compatible-contracts.mdx b/src/content/chainlink-automation/guides/compatible-contracts.mdx index d8f5eb561ac..81153e841ad 100644 --- a/src/content/chainlink-automation/guides/compatible-contracts.mdx +++ b/src/content/chainlink-automation/guides/compatible-contracts.mdx @@ -13,6 +13,9 @@ whatsnext: --- import { Aside, CodeSample } from "@components" +import ChainlinkAutomation from "@features/chainlink-automation/common/ChainlinkAutomation.astro" + +<ChainlinkAutomation callout="cre" /> Learn how to make smart contracts that are compatible with `Automation`. diff --git a/src/content/chainlink-automation/guides/job-scheduler.mdx b/src/content/chainlink-automation/guides/job-scheduler.mdx index c4039102800..201a40691d2 100644 --- a/src/content/chainlink-automation/guides/job-scheduler.mdx +++ b/src/content/chainlink-automation/guides/job-scheduler.mdx @@ -22,6 +22,16 @@ Create powerful automation for your smart contract using time schedules without Follow the [best practices](/chainlink-automation/concepts/best-practice) when creating an Automation-compatible contract and test your upkeep on a testnet before deploying it to a mainnet. </Aside> + +<Aside type="caution" title="Upgrade Time-Based Upkeep Recommended"> + The Automation “Time-based” upkeep contract has been updated so that only the unique forwarder for your upkeep can call it. If your upkeep was deployed before 11 December 2025, we recommend you replace your existing “Time-based” upkeeps using the new “Time-based” upkeep. + +To upgrade, simply follow the [Automation UI](https://automation.chain.link/) to register a new “Time-based” upkeep with the same details as your previous upkeep. Once registered, you can delete the previous upkeep. + +Upgrading to the latest “Time-based” upkeep removes i) the ability of 3rd parties to trigger your upkeep, and ii) the possibility that a call with insufficient gas ticks the Timer forward but fails to execute your desired function. + +</Aside> + ## Using the Chainlink Automation app In the [Chainlink Automation App](https://automation.chain.link/), click the blue **Register new Upkeep** button. diff --git a/src/content/chainlink-automation/index.mdx b/src/content/chainlink-automation/index.mdx index 33776f986ce..7a17799ed00 100644 --- a/src/content/chainlink-automation/index.mdx +++ b/src/content/chainlink-automation/index.mdx @@ -17,12 +17,19 @@ import { Aside } from "@components" import { ClickToZoom } from "@components" import ChainlinkAutomation from "@features/chainlink-automation/common/ChainlinkAutomation.astro" -<Aside type="note" title="Get Started"> - Try Chainlink Automation in the [Getting Started](/chainlink-automation/overview/getting-started) guide. -</Aside> +<ChainlinkAutomation callout="cre" /> <ChainlinkAutomation callout="deprecation" /> +<Aside type="caution" title="Upgrade Time-Based Upkeep Recommended"> + The Automation “Time-based” upkeep contract has been updated so that only the unique forwarder for your upkeep can call it. If your upkeep was deployed before 11 December 2025, we recommend you replace your existing “Time-based” upkeeps using the new “Time-based” upkeep. + +To upgrade, simply follow the [Automation UI](https://automation.chain.link/) to register a new “Time-based” upkeep with the same details as your previous upkeep. Once registered, you can delete the previous upkeep. + +Upgrading to the latest “Time-based” upkeep removes i) the ability of 3rd parties to trigger your upkeep, and ii) the possibility that a call with insufficient gas ticks the Timer forward but fails to execute your desired function. + +</Aside> + Automate your smart contracts using a secure and hyper-reliable decentralized network that uses the same external network of node operators that secures billions in value. Building on Chainlink Automation will accelerate your innovation, save you time and money, and help you get to market faster so you don't have to deal with the setup cost, ongoing maintenance, and risks associated with a centralized automation stack. To learn more about how the Chainlink Automation Network automates your smart contracts, visit the [Concepts](/chainlink-automation/concepts/automation-concepts) and [Architecture](/chainlink-automation/concepts/automation-architecture) pages. You can also learn more through our [additional Automation resources](https://chain.link/automation#masterclass). diff --git a/src/content/chainlink-automation/llms-full.txt b/src/content/chainlink-automation/llms-full.txt index ef118c4a74a..46d84dc8533 100644 --- a/src/content/chainlink-automation/llms-full.txt +++ b/src/content/chainlink-automation/llms-full.txt @@ -99,6 +99,8 @@ If your upkeep is on Automation v1, we recommend that you revalidate the conditi # Create Automation-Compatible Contracts Source: https://docs.chain.link/chainlink-automation/guides/compatible-contracts +<ChainlinkAutomation callout="cre" /> + Learn how to make smart contracts that are compatible with `Automation`. <Aside type="tip" title="Considerations and Best Practices"> @@ -129,6 +131,74 @@ Custom logic Automation compatible contracts must meet the following requirement Use these elements to create a compatible contract that will automatically increment a counter after every `updateInterval` seconds. After you register the contract as an upkeep, the Chainlink Automation Network frequently simulates your `checkUpkeep` offchain to determine if the `updateInterval` time has passed since the last increment (timestamp). When `checkUpkeep` returns true, the Chainlink Automation Network calls `performUpkeep` onchain and increments the counter. This cycle repeats until the upkeep is cancelled or runs out of funding. +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +// AutomationCompatible.sol imports the functions from both ./AutomationBase.sol and +// ./interfaces/AutomationCompatibleInterface.sol +import {AutomationCompatibleInterface} from "@chainlink/contracts/src/v0.8/automation/AutomationCompatible.sol"; + +/** + * @dev Example contract, use the Forwarder as needed for additional security. + * + * @notice important to implement {AutomationCompatibleInterface} + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract Counter is AutomationCompatibleInterface { + /** + * Public counter variable + */ + uint256 public counter; + + /** + * Use an interval in seconds and a timestamp to slow execution of Upkeep + */ + uint256 public immutable interval; + uint256 public lastTimeStamp; + + constructor( + uint256 updateInterval + ) { + interval = updateInterval; + lastTimeStamp = block.timestamp; + + counter = 0; + } + + function checkUpkeep( + bytes calldata /* checkData */ + ) + external + view + override + returns ( + bool upkeepNeeded, + bytes memory /* performData */ + ) + { + upkeepNeeded = (block.timestamp - lastTimeStamp) > interval; + // We don't use the checkData in this example. The checkData is defined when the Upkeep was registered. + } + + function performUpkeep( + bytes calldata /* performData */ + ) external override { + if ((block.timestamp - lastTimeStamp) > interval) { + lastTimeStamp = block.timestamp; + counter = counter + 1; + } + // We don't use the performData in this example. The performData is generated by the Automation Node's call to your + // checkUpkeep function + } +} +``` + Compile and deploy your own Automation Counter onto a [supported Testnet](/chainlink-automation/overview/supported-networks). 1. In the Remix example, select the compile tab on the left and press the compile button. Make sure that your contract compiles without any errors. Note that the Warning messages in this example are acceptable and will not block the deployment. @@ -183,6 +253,92 @@ The contract has the following components: - The `checkUpkeep()` function checks if the contract requires work to be done. If one array element has a balance of less than `LIMIT`, the function returns `upkeepNeeded == true`. - The `performUpkeep()` function to re-balances the elements. To demonstrate how this computation can cause high gas fees, this example does all of the computation within the transaction. The function finds all of the elements that are less than `LIMIT`, decreases the contract `liquidity`, and increases every found element to equal `LIMIT`. +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import { + AutomationCompatibleInterface +} from "@chainlink/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol"; + +/** + * @dev Example contract which perform all the computation in `performUpkeep` + * @notice important to implement {AutomationCompatibleInterface} + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract BalancerOnChain is AutomationCompatibleInterface { + uint256 public constant SIZE = 1000; + uint256 public constant LIMIT = 1000; + uint256[SIZE] public balances; + uint256 public liquidity = 1_000_000; + + constructor() { + // On the initialization of the contract, all the elements have a balance equal to the limit + for (uint256 i = 0; i < SIZE; i++) { + balances[i] = LIMIT; + } + } + + /// @dev called to increase the liquidity of the contract + function addLiquidity( + uint256 liq + ) public { + liquidity += liq; + } + + /// @dev withdraw an `amount`from multiple elements of `balances` array. The elements are provided in `indexes` + function withdraw( + uint256 amount, + uint256[] memory indexes + ) public { + for (uint256 i = 0; i < indexes.length; i++) { + require(indexes[i] < SIZE, "Provided index out of bound"); + balances[indexes[i]] -= amount; + } + } + + /// @dev this method is called by the Automation Nodes to check if `performUpkeep` should be performed + function checkUpkeep( + bytes calldata /* checkData */ + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + upkeepNeeded = false; + for (uint256 i = 0; i < SIZE && !upkeepNeeded; i++) { + if (balances[i] < LIMIT) { + // if one element has a balance < LIMIT then rebalancing is needed + upkeepNeeded = true; + } + } + return (upkeepNeeded, ""); + } + + /// @dev this method is called by the Automation Nodes. it increases all elements which balances are lower than the + /// LIMIT + function performUpkeep( + bytes calldata /* performData */ + ) external override { + uint256 increment; + uint256 _balance; + for (uint256 i = 0; i < SIZE; i++) { + _balance = balances[i]; + // best practice: reverify the upkeep is needed + if (_balance < LIMIT) { + // calculate the increment needed + increment = LIMIT - _balance; + // decrease the contract liquidity accordingly + liquidity -= increment; + // rebalance the element + balances[i] = LIMIT; + } + } + } +} +``` + Test this example using the following steps: 1. Deploy the contract using Remix on the [supported testnet](/chainlink-automation/overview/supported-networks) of your choice. @@ -217,6 +373,129 @@ Modify the contract and move the computation to the `checkUpkeep()` function. Th - The `checkUpkeep()` function receives [`checkData`](/chainlink-automation/reference/automation-interfaces/#checkdata), which passes arbitrary bytes to the function. Pass a `lowerBound` and an `upperBound` to scope the work to a sub-array of `balances`. This creates several upkeeps with different values of `checkData`. The function loops over the sub-array and looks for the indexes of the elements that require re-balancing and calculates the required `increments`. Then, it returns `upkeepNeeded == true` and `performData`, which is calculated by encoding `indexes` and `increments`. Note that `checkUpkeep()` is a view function, so computation does not consume any gas. - The `performUpkeep()` function takes [performData](/chainlink-automation/reference/automation-interfaces/#performdata) as a parameter and decodes it to fetch the `indexes` and the `increments`. +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import { + AutomationCompatibleInterface +} from "@chainlink/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol"; + +/** + * @dev Example contract which perform most of the computation in `checkUpkeep` + * + * @notice important to implement {AutomationCompatibleInterface} + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract BalancerOffChain is AutomationCompatibleInterface { + uint256 public constant SIZE = 1000; + uint256 public constant LIMIT = 1000; + uint256[SIZE] public balances; + uint256 public liquidity = 1_000_000; + + constructor() { + // On the initialization of the contract, all the elements have a balance equal to the limit + for (uint256 i = 0; i < SIZE; i++) { + balances[i] = LIMIT; + } + } + + /// @dev called to increase the liquidity of the contract + function addLiquidity( + uint256 liq + ) public { + liquidity += liq; + } + + /// @dev withdraw an `amount`from multiple elements of the `balances` array. The elements are provided in `indexes` + function withdraw( + uint256 amount, + uint256[] memory indexes + ) public { + for (uint256 i = 0; i < indexes.length; i++) { + require(indexes[i] < SIZE, "Provided index out of bound"); + balances[indexes[i]] -= amount; + } + } + + /* @dev this method is called by the Chainlink Automation Nodes to check if `performUpkeep` must be done. Note that + `checkData` is used to segment the computation to subarrays. + * + * @dev `checkData` is an encoded binary data and which contains the lower bound and upper bound on which to perform + the computation + * + * @dev return `upkeepNeeded`if rebalancing must be done and `performData` which contains an array of indexes that + require rebalancing and their increments. This will be used in `performUpkeep` + */ + function checkUpkeep( + bytes calldata checkData + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + // perform the computation to a subarray of `balances`. This opens the possibility of having several checkUpkeeps + // done at the same time + (uint256 lowerBound, uint256 upperBound) = abi.decode(checkData, (uint256, uint256)); + require(upperBound < SIZE && lowerBound < upperBound, "Lowerbound and Upperbound not correct"); + // first get number of elements requiring updates + uint256 counter; + for (uint256 i = 0; i < upperBound - lowerBound + 1; i++) { + if (balances[lowerBound + i] < LIMIT) { + counter++; + } + } + // initialize array of elements requiring increments as long as the increments + uint256[] memory indexes = new uint256[](counter); + uint256[] memory increments = new uint256[](counter); + + upkeepNeeded = false; + uint256 indexCounter; + + for (uint256 i = 0; i < upperBound - lowerBound + 1; i++) { + if (balances[lowerBound + i] < LIMIT) { + // if one element has a balance < LIMIT then rebalancing is needed + upkeepNeeded = true; + // store the index which needs increment as long as the increment + indexes[indexCounter] = lowerBound + i; + increments[indexCounter] = LIMIT - balances[lowerBound + i]; + indexCounter++; + } + } + performData = abi.encode(indexes, increments); + return (upkeepNeeded, performData); + } + + /* @dev this method is called by the Automation Nodes. it increases all elements whose balances are lower than the + LIMIT. Note that the elements are bounded by `lowerBound`and `upperBound` + * (provided by `performData` + * + * @dev `performData` is an encoded binary data which contains the lower bound and upper bound of the subarray on + which to perform the computation. + * it also contains the increments + * + * @dev return `upkeepNeeded`if rebalancing must be done and `performData` which contains an array of increments. This + will be used in `performUpkeep` + */ + function performUpkeep( + bytes calldata performData + ) external override { + (uint256[] memory indexes, uint256[] memory increments) = abi.decode(performData, (uint256[], uint256[])); + + uint256 _balance; + uint256 _liquidity = liquidity; + + for (uint256 i = 0; i < indexes.length; i++) { + _balance = balances[indexes[i]] + increments[i]; + _liquidity -= increments[i]; + balances[indexes[i]] = _balance; + } + liquidity = _liquidity; + } +} +``` + Run this example to compare the gas fees: 1. Deploy the contract using Remix on the [supported testnet](/chainlink-automation/overview/supported-networks) of your choice. @@ -292,6 +571,64 @@ After you register an upkeep, its forwarder address is available in the Chainlin The code sample below uses the Forwarder: +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/** + * @dev Example contract which uses the Forwarder + * + * @notice important to implement {AutomationCompatibleInterface} + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +import { + AutomationCompatibleInterface +} from "@chainlink/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol"; +import {OwnerIsCreator} from "@chainlink/contracts/src/v0.8/shared/access/OwnerIsCreator.sol"; + +contract CounterwForwarder is AutomationCompatibleInterface, OwnerIsCreator { + uint256 public counter; // counter counts the number of upkeeps performed + uint256 public interval; // interval specifies the time between upkeeps + uint256 public lastTimeStamp; // lastTimeStamp tracks the last upkeep performed + address public s_forwarderAddress; + + constructor( + uint256 updateInterval + ) { + interval = updateInterval; + } + + function checkUpkeep( + bytes calldata /*checkData*/ + ) external override returns (bool, bytes memory) { + bool needsUpkeep = (block.timestamp - lastTimeStamp) > interval; + return (needsUpkeep, bytes("")); + } + + function performUpkeep( + bytes calldata /*performData*/ + ) external override { + require(msg.sender == s_forwarderAddress, "This address does not have permission to call performUpkeep"); + lastTimeStamp = block.timestamp; + counter = counter + 1; + } + + /// @notice Set the address that `performUpkeep` is called from + /// @dev Only callable by the owner + /// @param forwarderAddress the address to set + function setForwarderAddress( + address forwarderAddress + ) external onlyOwner { + s_forwarderAddress = forwarderAddress; + } +} +``` + --- # Set a gas price threshold on your upkeep @@ -401,6 +738,14 @@ Create powerful automation for your smart contract using time schedules without contract and test your upkeep on a testnet before deploying it to a mainnet. </Aside> +<Aside type="caution" title="Upgrade Time-Based Upkeep Recommended"> + The Automation “Time-based” upkeep contract has been updated so that only the unique forwarder for your upkeep can call it. If your upkeep was deployed before 11 December 2025, we recommend you replace your existing “Time-based” upkeeps using the new “Time-based” upkeep. + + To upgrade, simply follow the [Automation UI](https://automation.chain.link/) to register a new “Time-based” upkeep with the same details as your previous upkeep. Once registered, you can delete the previous upkeep. + + Upgrading to the latest “Time-based” upkeep removes i) the ability of 3rd parties to trigger your upkeep, and ii) the possibility that a call with insufficient gas ticks the Timer forward but fails to execute your desired function. +</Aside> + ## Using the Chainlink Automation app In the [Chainlink Automation App](https://automation.chain.link/), click the blue **Register new Upkeep** button. @@ -501,14 +846,27 @@ Chainlink Automation processes a limited number of logs per block per upkeep. Se {" "} +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +contract CountEmitLog { + event WantsToCount(address indexed msgSender); + + constructor() {} + + function emitCountLog() public { + emit WantsToCount(msg.sender); + } +} +``` + 1. Under *Environment*, select the option **Injected Provider** to connect to your cryptocurrency wallet. 2. Deploy the contract and confirm the transaction. 3. You can view the contract on Etherscan by clicking the message in the terminal. You an view the address of the created contract and the original contract in Etherscan. - <ClickToZoom src="/images/automation/log-trig-addresses.png" /> 4. Navigate to the *Contract* tab. If the contract is already verified, you will see options to **Read Contract** and **Write Contract**. If your contract isn't verified, follow the prompts in Etherscan to verify the contract. 5. Click **Write Contract** and click the **emitCountLog** button to emit a log. 6. Navigate back to Etherscan and locate the *Events* tab. You should see the event of emitting a log recorded in this section. - <ClickToZoom src="/images/automation/log-trig-event.png" /> ## Using `ILogAutomation` Interface @@ -516,9 +874,66 @@ Chainlink Automation processes a limited number of logs per block per upkeep. Se {" "} +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +struct Log { + uint256 index; // Index of the log in the block + uint256 timestamp; // Timestamp of the block containing the log + bytes32 txHash; // Hash of the transaction containing the log + uint256 blockNumber; // Number of the block containing the log + bytes32 blockHash; // Hash of the block containing the log + address source; // Address of the contract that emitted the log + bytes32[] topics; // Indexed topics of the log + bytes data; // Data of the log +} + +interface ILogAutomation { + function checkLog( + Log calldata log, + bytes memory checkData + ) external returns (bool upkeepNeeded, bytes memory performData); + + function performUpkeep( + bytes calldata performData + ) external; +} + +contract CountWithLog is ILogAutomation { + event CountedBy(address indexed msgSender); + + uint256 public counted = 0; + + constructor() {} + + function checkLog( + Log calldata log, + bytes memory + ) external pure returns (bool upkeepNeeded, bytes memory performData) { + upkeepNeeded = true; + address logSender = bytes32ToAddress(log.topics[1]); + performData = abi.encode(logSender); + } + + function performUpkeep( + bytes calldata performData + ) external override { + counted += 1; + address logSender = abi.decode(performData, (address)); + emit CountedBy(logSender); + } + + function bytes32ToAddress( + bytes32 _address + ) public pure returns (address) { + return address(uint160(uint256(_address))); + } +} +``` + 1. Deploy the contract and confirm your transaction. 2. Under *Deployed Contracts*, expand `CountWithLog`. Click the **count** button to view the value of the count variable. It should be 0. - <ClickToZoom src="/images/automation/log-trig-count-0.png" /> 3. Copy the address of this contract either via Remix or Etherscan to register it on the Chainlink Automation app. ## Using the Chainlink Automation App @@ -836,6 +1251,76 @@ For upkeeps with triggers using onchain state only, the following parameters are #### Code sample +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +struct RegistrationParams { + string name; + bytes encryptedEmail; + address upkeepContract; + uint32 gasLimit; + address adminAddress; + uint8 triggerType; + bytes checkData; + bytes triggerConfig; + bytes offchainConfig; + uint96 amount; +} + +/** + * string name = "test upkeep"; + * bytes encryptedEmail = 0x; + * address upkeepContract = 0x...; + * uint32 gasLimit = 500000; + * address adminAddress = 0x....; + * uint8 triggerType = 0; + * bytes checkData = 0x; + * bytes triggerConfig = 0x; + * bytes offchainConfig = 0x; + * uint96 amount = 1000000000000000000; + */ +interface AutomationRegistrarInterface { + function registerUpkeep( + RegistrationParams calldata requestParams + ) external returns (uint256); +} + +contract UpkeepIDConditionalExample { + LinkTokenInterface public immutable i_link; + AutomationRegistrarInterface public immutable i_registrar; + + constructor( + LinkTokenInterface link, + AutomationRegistrarInterface registrar + ) { + i_link = link; + i_registrar = registrar; + } + + function registerAndPredictID( + RegistrationParams memory params + ) public { + // LINK must be approved for transfer - this can be done every time or once + // with an infinite approval + i_link.approve(address(i_registrar), params.amount); + uint256 upkeepID = i_registrar.registerUpkeep(params); + if (upkeepID != 0) { + // DEV - Use the upkeepID however you see fit + } else { + revert("auto-approve disabled"); + } + } +} +``` + ### Log trigger upkeeps #### Parameters @@ -868,6 +1353,96 @@ where filterSelector is a bitmask mapping and value is set depending on the sele #### Code sample +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +struct RegistrationParams { + string name; + bytes encryptedEmail; + address upkeepContract; + uint32 gasLimit; + address adminAddress; + uint8 triggerType; + bytes checkData; + bytes triggerConfig; + bytes offchainConfig; + uint96 amount; +} + +struct LogTriggerConfig { + address contractAddress; + uint8 filterSelector; + bytes32 topic0; + bytes32 topic1; + bytes32 topic2; + bytes32 topic3; +} + +/** + * Log trigger details + * address contractAddress = 0x...; // e.g. 0x2938ff7cAB3115f768397602EA1A1a0Aa20Ac42f + * uint8 filterSelector = 1; // see filterSelector + * bytes32 topic0 = 0x...; // e.g. 0x74500d2e71ee75a8a83dcc87f7316a89404a0d0ac0c725e80c956dbf16fb8133 for event called + * bump + * bytes32 topic1 = 0x...; // e.g. bytes32 of address 0x000000000000000000000000c26d7ef337e01a5cc5498d3cc2ff0610761ae637 + * bytes32 topic2 = 0x; // empty so 0x + * bytes32 topic3 = 0x; // empty so 0x + * + * Upkeep details + * string name = "test upkeep"; + * bytes encryptedEmail = 0x; + * address upkeepContract = 0x...; + * uint32 gasLimit = 500000; + * address adminAddress = 0x....; + * uint8 triggerType = 1; + * bytes checkData = 0x; + * bytes triggerConfig = abi.encode(address contractAddress, uint8 filterSelector,bytes32 topic0,bytes32 topic1,bytes32 + * topic2, bytes32 topic3); + * bytes offchainConfig = 0x; + * uint96 amount = 1000000000000000000; + */ +interface AutomationRegistrarInterface { + function registerUpkeep( + RegistrationParams calldata requestParams + ) external returns (uint256); +} + +contract UpkeepIDlogTriggerExample { + LinkTokenInterface public immutable i_link; + AutomationRegistrarInterface public immutable i_registrar; + + constructor( + LinkTokenInterface link, + AutomationRegistrarInterface registrar + ) { + i_link = link; + i_registrar = registrar; + } + + function registerAndPredictID( + RegistrationParams memory params + ) public { + // LINK must be approved for transfer - this can be done every time or once + // with an infinite approval + i_link.approve(address(i_registrar), params.amount); + uint256 upkeepID = i_registrar.registerUpkeep(params); + if (upkeepID != 0) { + // DEV - Use the upkeepID however you see fit + } else { + revert("auto-approve disabled"); + } + } +} +``` + --- # Register a Custom Logic Upkeep @@ -972,8 +1547,14 @@ Read our [debugging section](/chainlink-automation/reference/debugging-errors) t # Chainlink Automation Source: https://docs.chain.link/chainlink-automation -<Aside type="note" title="Get Started"> - Try Chainlink Automation in the [Getting Started](/chainlink-automation/overview/getting-started) guide. +<ChainlinkAutomation callout="cre" /> + +<Aside type="caution" title="Upgrade Time-Based Upkeep Recommended"> + The Automation “Time-based” upkeep contract has been updated so that only the unique forwarder for your upkeep can call it. If your upkeep was deployed before 11 December 2025, we recommend you replace your existing “Time-based” upkeeps using the new “Time-based” upkeep. + + To upgrade, simply follow the [Automation UI](https://automation.chain.link/) to register a new “Time-based” upkeep with the same details as your previous upkeep. Once registered, you can delete the previous upkeep. + + Upgrading to the latest “Time-based” upkeep removes i) the ability of 3rd parties to trigger your upkeep, and ii) the possibility that a call with insufficient gas ticks the Timer forward but fails to execute your desired function. </Aside> Automate your smart contracts using a secure and hyper-reliable decentralized network that uses the same external network of node operators that secures billions in value. Building on Chainlink Automation will accelerate your innovation, save you time and money, and help you get to market faster so you don't have to deal with the setup cost, ongoing maintenance, and risks associated with a centralized automation stack. @@ -1069,6 +1650,8 @@ For funding on mainnet, you will need ERC-677 LINK. Many token bridges give you # Getting Started with Chainlink Automation Source: https://docs.chain.link/chainlink-automation/overview/getting-started +<ChainlinkAutomation callout="cre" /> + Chainlink Automation will reliably execute smart contract functions using a variety of triggers. Explore the examples below to see how Chainlink Automation works for each type of trigger. Before you begin, you will need an active cryptocurrency wallet such as Metamask. - **Time-based trigger**: Use a time-based trigger to execute your function according to a time schedule. @@ -1568,6 +2151,15 @@ Below are the parameters and return values of the `checkUpkeep` function. Click You can pass information into your `checkUpkeep` function from your [upkeep registration](/chainlink-automation/guides/register-upkeep) to execute different code paths. For example, to check the balance on a specific address, set the `checkData` to abi encode the address. To learn how to create flexible upkeeps with checkData, please see our [flexible upkeeps](/chainlink-automation/guides/flexible-upkeeps) page. +```sol +function checkUpkeep( + bytes calldata checkData +) public view returns (bool, bytes memory) { + address wallet = abi.decode(checkData, (address)); + return (wallet.balance < 1 ether, bytes("")); +} +``` + Tips on using `checkData`: - **Managing unbounded upkeeps**: Limit the problem set of your onchain execution by creating a range bound for your upkeep to check and perform. This allows you to keep within predefined gas limits, which creates a predictable upper bound gas cost on your transactions. Break apart your problem into multiple upkeep registrations to limit the scope of work. diff --git a/src/content/chainlink-automation/overview/getting-started.mdx b/src/content/chainlink-automation/overview/getting-started.mdx index 3e20b5dae13..a1ebd093d62 100644 --- a/src/content/chainlink-automation/overview/getting-started.mdx +++ b/src/content/chainlink-automation/overview/getting-started.mdx @@ -15,6 +15,9 @@ whatsnext: import { Address, Aside, ClickToZoom, CopyText } from "@components" import { YouTube } from "@astro-community/astro-embed-youtube" import { Tabs } from "@components/Tabs" +import ChainlinkAutomation from "@features/chainlink-automation/common/ChainlinkAutomation.astro" + +<ChainlinkAutomation callout="cre" /> Chainlink Automation will reliably execute smart contract functions using a variety of triggers. Explore the examples below to see how Chainlink Automation works for each type of trigger. Before you begin, you will need an active cryptocurrency wallet such as Metamask. diff --git a/src/content/chainlink-functions/getting-started.mdx b/src/content/chainlink-functions/getting-started.mdx index 78144fa094f..03997098f3e 100644 --- a/src/content/chainlink-functions/getting-started.mdx +++ b/src/content/chainlink-functions/getting-started.mdx @@ -16,6 +16,8 @@ import { Tabs } from "@components/Tabs" import ChainlinkFunctions from "@features/chainlink-functions/common/ChainlinkFunctions.astro" import { YouTube } from "@astro-community/astro-embed-youtube" +<ChainlinkFunctions callout="cre" /> + Learn how to make requests to the Chainlink Functions Decentralized Oracle Network (DON) and make any computation or API calls offchain. Chainlink Functions is available on several blockchains (see the [supported networks page](/chainlink-functions/supported-networks)), but this guide uses Sepolia to simplify access to testnet funds. Complete the following tasks to get started with Chainlink Functions: - Set up your web3 wallet and fund it with testnet tokens. diff --git a/src/content/chainlink-functions/index.mdx b/src/content/chainlink-functions/index.mdx index 03c0934966d..988a30af7b9 100644 --- a/src/content/chainlink-functions/index.mdx +++ b/src/content/chainlink-functions/index.mdx @@ -12,6 +12,9 @@ whatsnext: --- import { Aside } from "@components" +import ChainlinkFunctions from "@features/chainlink-functions/common/ChainlinkFunctions.astro" + +<ChainlinkFunctions callout="cre" /> Chainlink Functions provides your smart contracts access to trust-minimized compute infrastructure, allowing you to fetch data from APIs and perform custom computation. Your smart contract sends source code in a request to a [Decentralized Oracle Network (DON)](/chainlink-functions/resources/concepts), and each node in the DON executes the code in a serverless environment. The DON then aggregates all the independent return values from each execution and sends the final result back to your smart contract. diff --git a/src/content/chainlink-functions/llms-full.txt b/src/content/chainlink-functions/llms-full.txt index bbce22a511f..771ba03a57b 100644 --- a/src/content/chainlink-functions/llms-full.txt +++ b/src/content/chainlink-functions/llms-full.txt @@ -397,6 +397,8 @@ const myArr = new Uint8Array(ARRAY_LENGTH) # Getting Started Source: https://docs.chain.link/chainlink-functions/getting-started +<ChainlinkFunctions callout="cre" /> + Learn how to make requests to the Chainlink Functions Decentralized Oracle Network (DON) and make any computation or API calls offchain. Chainlink Functions is available on several blockchains (see the [supported networks page](/chainlink-functions/supported-networks)), but this guide uses Sepolia to simplify access to testnet funds. Complete the following tasks to get started with Chainlink Functions: - Set up your web3 wallet and fund it with testnet tokens. @@ -413,6 +415,18 @@ Before making a Chainlink Functions request from your smart contract, it is alwa 2. Copy and paste the following source code into the playground's code block. + ```javascript + const characterId = args[0]; + const apiResponse = await Functions.makeHttpRequest({ + url: `https://swapi.info/api/people/${characterId}/`, + }); + if (apiResponse.error) { + throw Error("Request failed"); + } + const { data } = apiResponse; + return Functions.encodeString(data.name); + ``` + 3. Under *Argument*, set the first argument to 1. You are going to fetch the name of the first Star Wars character. 4. Click on *Run code*. Under *Output*, you should see *Luke Skywalker*. @@ -434,6 +448,112 @@ You will test on Sepolia, so you must have an Ethereum web3 wallet with enough t 1. Open the [GettingStartedFunctionsConsumer.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/GettingStartedFunctionsConsumer.sol) contract in Remix. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; + + import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; + + import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; + import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + + /** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/resources/link-token-contracts/ + */ + + /** + * @title GettingStartedFunctionsConsumer + * @notice This is an example contract to show how to make HTTP requests using Chainlink + * @dev This contract uses hardcoded values and should not be used in production. + */ + contract GettingStartedFunctionsConsumer is FunctionsClient, ConfirmedOwner { + using FunctionsRequest for FunctionsRequest.Request; + + // State variables to store the last request ID, response, and error + bytes32 public s_lastRequestId; + bytes public s_lastResponse; + bytes public s_lastError; + + // Custom error type + error UnexpectedRequestID(bytes32 requestId); + + // Event to log responses + event Response(bytes32 indexed requestId, string character, bytes response, bytes err); + + // Router address - Hardcoded for Sepolia + // Check to get the router address for your supported network + // https://docs.chain.link/chainlink-functions/supported-networks + address router = 0xb83E47C2bC239B3bf370bc41e1459A34b41238D0; + + // JavaScript source code + // Fetch character name from the Star Wars API. + // Documentation: https://swapi.info/people + string source = "const characterId = args[0];" "const apiResponse = await Functions.makeHttpRequest({" + "url: `https://swapi.info/api/people/${characterId}/`" "});" "if (apiResponse.error) {" + "throw Error('Request failed');" "}" "const { data } = apiResponse;" "return Functions.encodeString(data.name);"; + + //Callback gas limit + uint32 gasLimit = 300_000; + + // donID - Hardcoded for Sepolia + // Check to get the donID for your supported network https://docs.chain.link/chainlink-functions/supported-networks + bytes32 donID = 0x66756e2d657468657265756d2d7365706f6c69612d3100000000000000000000; + + // State variable to store the returned character information + string public character; + + /** + * @notice Initializes the contract with the Chainlink router address and sets the contract owner + */ + constructor() FunctionsClient(router) ConfirmedOwner(msg.sender) {} + + /** + * @notice Sends an HTTP request for character information + * @param subscriptionId The ID for the Chainlink subscription + * @param args The arguments to pass to the HTTP request + * @return requestId The ID of the request + */ + function sendRequest( + uint64 subscriptionId, + string[] calldata args + ) external onlyOwner returns (bytes32 requestId) { + FunctionsRequest.Request memory req; + req.initializeRequestForInlineJavaScript(source); // Initialize the request with JS code + if (args.length > 0) req.setArgs(args); // Set the arguments for the request + + // Send the request and store the request ID + s_lastRequestId = _sendRequest(req.encodeCBOR(), subscriptionId, gasLimit, donID); + + return s_lastRequestId; + } + + /** + * @notice Callback function for fulfilling a request + * @param requestId The ID of the request to fulfill + * @param response The HTTP response data + * @param err Any errors from the Functions request + */ + function fulfillRequest( + bytes32 requestId, + bytes memory response, + bytes memory err + ) internal override { + if (s_lastRequestId != requestId) { + revert UnexpectedRequestID(requestId); // Check if request IDs match + } + // Update the contract's state variables with the response and any errors + s_lastResponse = response; + character = string(response); + s_lastError = err; + + // Emit an event to log the response + emit Response(requestId, character, s_lastResponse, s_lastError); + } + } + ``` + 2. Compile the contract. 3. Open MetaMask and select the *Sepolia* network. @@ -506,6 +626,112 @@ Chainlink Functions is capable of much more than just retrieving data. Try one o ### Solidity code +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; + +import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/resources/link-token-contracts/ + */ + +/** + * @title GettingStartedFunctionsConsumer + * @notice This is an example contract to show how to make HTTP requests using Chainlink + * @dev This contract uses hardcoded values and should not be used in production. + */ +contract GettingStartedFunctionsConsumer is FunctionsClient, ConfirmedOwner { + using FunctionsRequest for FunctionsRequest.Request; + + // State variables to store the last request ID, response, and error + bytes32 public s_lastRequestId; + bytes public s_lastResponse; + bytes public s_lastError; + + // Custom error type + error UnexpectedRequestID(bytes32 requestId); + + // Event to log responses + event Response(bytes32 indexed requestId, string character, bytes response, bytes err); + + // Router address - Hardcoded for Sepolia + // Check to get the router address for your supported network + // https://docs.chain.link/chainlink-functions/supported-networks + address router = 0xb83E47C2bC239B3bf370bc41e1459A34b41238D0; + + // JavaScript source code + // Fetch character name from the Star Wars API. + // Documentation: https://swapi.info/people + string source = "const characterId = args[0];" "const apiResponse = await Functions.makeHttpRequest({" + "url: `https://swapi.info/api/people/${characterId}/`" "});" "if (apiResponse.error) {" + "throw Error('Request failed');" "}" "const { data } = apiResponse;" "return Functions.encodeString(data.name);"; + + //Callback gas limit + uint32 gasLimit = 300_000; + + // donID - Hardcoded for Sepolia + // Check to get the donID for your supported network https://docs.chain.link/chainlink-functions/supported-networks + bytes32 donID = 0x66756e2d657468657265756d2d7365706f6c69612d3100000000000000000000; + + // State variable to store the returned character information + string public character; + + /** + * @notice Initializes the contract with the Chainlink router address and sets the contract owner + */ + constructor() FunctionsClient(router) ConfirmedOwner(msg.sender) {} + + /** + * @notice Sends an HTTP request for character information + * @param subscriptionId The ID for the Chainlink subscription + * @param args The arguments to pass to the HTTP request + * @return requestId The ID of the request + */ + function sendRequest( + uint64 subscriptionId, + string[] calldata args + ) external onlyOwner returns (bytes32 requestId) { + FunctionsRequest.Request memory req; + req.initializeRequestForInlineJavaScript(source); // Initialize the request with JS code + if (args.length > 0) req.setArgs(args); // Set the arguments for the request + + // Send the request and store the request ID + s_lastRequestId = _sendRequest(req.encodeCBOR(), subscriptionId, gasLimit, donID); + + return s_lastRequestId; + } + + /** + * @notice Callback function for fulfilling a request + * @param requestId The ID of the request to fulfill + * @param response The HTTP response data + * @param err Any errors from the Functions request + */ + function fulfillRequest( + bytes32 requestId, + bytes memory response, + bytes memory err + ) internal override { + if (s_lastRequestId != requestId) { + revert UnexpectedRequestID(requestId); // Check if request IDs match + } + // Update the contract's state variables with the response and any errors + s_lastResponse = response; + character = string(response); + s_lastError = err; + + // Emit an event to log the response + emit Response(requestId, character, s_lastResponse, s_lastError); + } +} +``` + - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package so that you can import them from within your project. @@ -582,6 +808,18 @@ Chainlink Functions is capable of much more than just retrieving data. Try one o ### JavaScript code +```javascript +const characterId = args[0]; +const apiResponse = await Functions.makeHttpRequest({ + url: `https://swapi.info/api/people/${characterId}/`, +}); +if (apiResponse.error) { + throw Error("Request failed"); +} +const { data } = apiResponse; +return Functions.encodeString(data.name); +``` + This JavaScript source code uses [Functions.makeHttpRequest](/chainlink-functions/api-reference/javascript-source#http-requests) to make HTTP requests. The source code calls the `https://swapi.info/` API to request a Star Wars character name. If you read the [Functions.makeHttpRequest](/chainlink-functions/api-reference/javascript-source#http-requests) documentation and the [Star Wars API documentation](https://swapi.info/people), you notice that URL has the following format where `$characterId` is provided as parameter when making the HTTP request: ``` @@ -638,6 +876,8 @@ Now that you understand the structure of the API. Let's delve into the JavaScrip # Chainlink Functions Source: https://docs.chain.link/chainlink-functions +<ChainlinkFunctions callout="cre" /> + Chainlink Functions provides your smart contracts access to trust-minimized compute infrastructure, allowing you to fetch data from APIs and perform custom computation. Your smart contract sends source code in a request to a [Decentralized Oracle Network (DON)](/chainlink-functions/resources/concepts), and each node in the DON executes the code in a serverless environment. The DON then aggregates all the independent return values from each execution and sends the final result back to your smart contract. Chainlink Functions eliminates the need for you to manage your own Chainlink node and provides decentralized offchain computation and consensus, ensuring that a minority of the network cannot manipulate the response sent back to your smart contract. @@ -1697,6 +1937,147 @@ In this tutorial, you will use a different Chainlink Functions consumer contract 1. [Open the FunctionsConsumerDecoder.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerDecoder.sol) in Remix. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; + + import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; + + import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; + import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + contract FunctionsConsumerDecoder is FunctionsClient, ConfirmedOwner { + using FunctionsRequest for FunctionsRequest.Request; + + bytes32 public s_lastRequestId; + bytes public s_lastResponse; + bytes public s_lastError; + + uint256 public s_answer; + uint256 public s_updatedAt; + uint8 public s_decimals; + string public s_description; + + error UnexpectedRequestID(bytes32 requestId); + + event Response(bytes32 indexed requestId, bytes response, bytes err); + + event DecodedResponse( + bytes32 indexed requestId, uint256 answer, uint256 updatedAt, uint8 decimals, string description + ); + + constructor( + address router + ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} + + /** + * @notice Send a simple request + * @param source JavaScript source code + * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets + * @param donHostedSecretsSlotID Don hosted secrets slotId + * @param donHostedSecretsVersion Don hosted secrets version + * @param args List of arguments accessible from within the source code + * @param bytesArgs Array of bytes arguments, represented as hex strings + * @param subscriptionId Billing ID + */ + function sendRequest( + string memory source, + bytes memory encryptedSecretsUrls, + uint8 donHostedSecretsSlotID, + uint64 donHostedSecretsVersion, + string[] memory args, + bytes[] memory bytesArgs, + uint64 subscriptionId, + uint32 gasLimit, + bytes32 donID + ) external onlyOwner returns (bytes32 requestId) { + FunctionsRequest.Request memory req; + req.initializeRequestForInlineJavaScript(source); + if (encryptedSecretsUrls.length > 0) { + req.addSecretsReference(encryptedSecretsUrls); + } else if (donHostedSecretsVersion > 0) { + req.addDONHostedSecrets(donHostedSecretsSlotID, donHostedSecretsVersion); + } + if (args.length > 0) req.setArgs(args); + if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); + s_lastRequestId = _sendRequest(req.encodeCBOR(), subscriptionId, gasLimit, donID); + return s_lastRequestId; + } + + /** + * @notice Send a pre-encoded CBOR request + * @param request CBOR-encoded request data + * @param subscriptionId Billing ID + * @param gasLimit The maximum amount of gas the request can consume + * @param donID ID of the job to be invoked + * @return requestId The ID of the sent request + */ + function sendRequestCBOR( + bytes memory request, + uint64 subscriptionId, + uint32 gasLimit, + bytes32 donID + ) external onlyOwner returns (bytes32 requestId) { + s_lastRequestId = _sendRequest(request, subscriptionId, gasLimit, donID); + return s_lastRequestId; + } + + /** + * @dev Internal function to process the outcome of a data request. It stores the latest response or error and updates + * the contract state accordingly. This function is designed to handle only one of `response` or `err` at a time, not + * both. It decodes the response if present and emits events to log both raw and decoded data. + * + * @param requestId The unique identifier of the request, originally returned by `sendRequest`. Used to match + * responses with requests. + * @param response The raw aggregated response data from the external source. This data is ABI-encoded and is expected + * to contain specific information (e.g., answer, updatedAt) if no error occurred. The function attempts to decode + * this data if `response` is not empty. + * @param err The raw aggregated error information, indicating an issue either from the user's code or within the + * execution of the user Chainlink Function. + * + * Emits a `DecodedResponse` event if the `response` is successfully decoded, providing detailed information about the + * data received. + * Emits a `Response` event for every call to log the raw response and error data. + * + * Requirements: + * - The `requestId` must match the last stored request ID to ensure the response corresponds to the latest request + * sent. + * - Only one of `response` or `err` should contain data for a given call; the other should be empty. + */ + function fulfillRequest( + bytes32 requestId, + bytes memory response, + bytes memory err + ) internal override { + if (s_lastRequestId != requestId) { + revert UnexpectedRequestID(requestId); + } + + s_lastError = err; + s_lastResponse = response; + + if (response.length > 0) { + (uint256 answer, uint256 updatedAt, uint8 decimals, string memory description) = + abi.decode(response, (uint256, uint256, uint8, string)); + + s_answer = answer; + s_updatedAt = updatedAt; + s_decimals = decimals; + s_description = description; + + emit DecodedResponse(requestId, answer, updatedAt, decimals, description); + } + + emit Response(requestId, response, err); + } + } + ``` + 2. Compile the contract. 3. Open MetaMask and select the *Ethereum Sepolia* network. @@ -1793,6 +2174,147 @@ To run the example: ### FunctionsConsumerDecoder.sol +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; + +import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract FunctionsConsumerDecoder is FunctionsClient, ConfirmedOwner { + using FunctionsRequest for FunctionsRequest.Request; + + bytes32 public s_lastRequestId; + bytes public s_lastResponse; + bytes public s_lastError; + + uint256 public s_answer; + uint256 public s_updatedAt; + uint8 public s_decimals; + string public s_description; + + error UnexpectedRequestID(bytes32 requestId); + + event Response(bytes32 indexed requestId, bytes response, bytes err); + + event DecodedResponse( + bytes32 indexed requestId, uint256 answer, uint256 updatedAt, uint8 decimals, string description + ); + + constructor( + address router + ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} + + /** + * @notice Send a simple request + * @param source JavaScript source code + * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets + * @param donHostedSecretsSlotID Don hosted secrets slotId + * @param donHostedSecretsVersion Don hosted secrets version + * @param args List of arguments accessible from within the source code + * @param bytesArgs Array of bytes arguments, represented as hex strings + * @param subscriptionId Billing ID + */ + function sendRequest( + string memory source, + bytes memory encryptedSecretsUrls, + uint8 donHostedSecretsSlotID, + uint64 donHostedSecretsVersion, + string[] memory args, + bytes[] memory bytesArgs, + uint64 subscriptionId, + uint32 gasLimit, + bytes32 donID + ) external onlyOwner returns (bytes32 requestId) { + FunctionsRequest.Request memory req; + req.initializeRequestForInlineJavaScript(source); + if (encryptedSecretsUrls.length > 0) { + req.addSecretsReference(encryptedSecretsUrls); + } else if (donHostedSecretsVersion > 0) { + req.addDONHostedSecrets(donHostedSecretsSlotID, donHostedSecretsVersion); + } + if (args.length > 0) req.setArgs(args); + if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); + s_lastRequestId = _sendRequest(req.encodeCBOR(), subscriptionId, gasLimit, donID); + return s_lastRequestId; + } + + /** + * @notice Send a pre-encoded CBOR request + * @param request CBOR-encoded request data + * @param subscriptionId Billing ID + * @param gasLimit The maximum amount of gas the request can consume + * @param donID ID of the job to be invoked + * @return requestId The ID of the sent request + */ + function sendRequestCBOR( + bytes memory request, + uint64 subscriptionId, + uint32 gasLimit, + bytes32 donID + ) external onlyOwner returns (bytes32 requestId) { + s_lastRequestId = _sendRequest(request, subscriptionId, gasLimit, donID); + return s_lastRequestId; + } + + /** + * @dev Internal function to process the outcome of a data request. It stores the latest response or error and updates + * the contract state accordingly. This function is designed to handle only one of `response` or `err` at a time, not + * both. It decodes the response if present and emits events to log both raw and decoded data. + * + * @param requestId The unique identifier of the request, originally returned by `sendRequest`. Used to match + * responses with requests. + * @param response The raw aggregated response data from the external source. This data is ABI-encoded and is expected + * to contain specific information (e.g., answer, updatedAt) if no error occurred. The function attempts to decode + * this data if `response` is not empty. + * @param err The raw aggregated error information, indicating an issue either from the user's code or within the + * execution of the user Chainlink Function. + * + * Emits a `DecodedResponse` event if the `response` is successfully decoded, providing detailed information about the + * data received. + * Emits a `Response` event for every call to log the raw response and error data. + * + * Requirements: + * - The `requestId` must match the last stored request ID to ensure the response corresponds to the latest request + * sent. + * - Only one of `response` or `err` should contain data for a given call; the other should be empty. + */ + function fulfillRequest( + bytes32 requestId, + bytes memory response, + bytes memory err + ) internal override { + if (s_lastRequestId != requestId) { + revert UnexpectedRequestID(requestId); + } + + s_lastError = err; + s_lastResponse = response; + + if (response.length > 0) { + (uint256 answer, uint256 updatedAt, uint8 decimals, string memory description) = + abi.decode(response, (uint256, uint256, uint8, string)); + + s_answer = answer; + s_updatedAt = updatedAt; + s_decimals = decimals; + s_description = description; + + emit DecodedResponse(requestId, answer, updatedAt, decimals, description); + } + + emit Response(requestId, response, err); + } +} +``` + This Solidity contract is similar to the [FunctionsConsumer.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumer.sol) contract used in the [Using Imports with Functions](/chainlink-functions/tutorials/importing-packages) tutorial. The main difference is the processing of the response in the `fulfillRequest` function: - It uses Solidity `abi.decode` to decode the `response` to retrieve the `answer`, `updatedAt`, `decimals`, and `description`. @@ -3331,6 +3853,130 @@ The consumer contract for Custom Automated Functions is different from the consu 1. Open the [CustomAutomatedFunctionsConsumerExample.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/CustomAutomatedFunctionsConsumerExample.sol) in Remix. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; + + import {AutomationCompatibleInterface} from "@chainlink/contracts/src/v0.8/automation/AutomationCompatible.sol"; + import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; + + import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; + import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + + /** + * @title Functions contract used for Automation. + * @notice This contract is a demonstration of using Functions and Automation. + * @notice NOT FOR PRODUCTION USE + */ + contract CustomAutomatedFunctionsConsumerExample is FunctionsClient, AutomationCompatibleInterface, ConfirmedOwner { + uint256 public lastBlockNumber; + bytes public request; + uint64 public subscriptionId; + uint32 public gasLimit; + bytes32 public donID; + bytes32 public s_lastRequestId; + bytes public s_lastResponse; + bytes public s_lastError; + uint256 public s_upkeepCounter; + uint256 public s_requestCounter; + uint256 public s_responseCounter; + + error UnexpectedRequestID(bytes32 requestId); + + event Response(bytes32 indexed requestId, bytes response, bytes err); + event RequestRevertedWithErrorMsg(string reason); + event RequestRevertedWithoutErrorMsg(bytes data); + + constructor( + address router + ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} + + /** + * @notice Checks if upkeep is needed based on the difference between the current and the last block number. + * @dev This function checks if the current block number has incremented since the last recorded block number and + * returns a boolean indicating if upkeep is needed. + * @return upkeepNeeded A boolean indicating if upkeep is needed (true if the current block number has incremented + * since the last recorded block number). + * @return performData An empty bytes value since no additional data is needed for the upkeep in this implementation. + */ + function checkUpkeep( + bytes calldata /* checkData */ + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + upkeepNeeded = block.number - lastBlockNumber > 0; // Check if the current block number has incremented since the + // last recorded block number + // We don't use the checkData in this example. The checkData is defined when the Upkeep was registered. + return (upkeepNeeded, ""); // Return an empty bytes value for performData + } + + /** + * @notice Send a pre-encoded CBOR request if the current block number has incremented since the last recorded block + * number. + */ + function performUpkeep( + bytes calldata /* performData */ + ) external override { + if (block.number - lastBlockNumber > 0) { + lastBlockNumber = block.number; + s_upkeepCounter = s_upkeepCounter + 1; + try i_router.sendRequest( + subscriptionId, request, FunctionsRequest.REQUEST_DATA_VERSION, gasLimit, donID + ) returns ( + bytes32 requestId + ) { + s_lastRequestId = requestId; + s_requestCounter = s_requestCounter + 1; + emit RequestSent(requestId); + } catch Error(string memory reason) { + emit RequestRevertedWithErrorMsg(reason); + } catch (bytes memory data) { + emit RequestRevertedWithoutErrorMsg(data); + } + } + // We don't use the performData in this example. The performData is generated by the Automation Node's call to your + // checkUpkeep function + } + + /// @notice Update the request settings + /// @dev Only callable by the owner of the contract + /// @param _request The new encoded CBOR request to be set. The request is encoded offchain + /// @param _subscriptionId The new subscription ID to be set + /// @param _gasLimit The new gas limit to be set + /// @param _donID The new job ID to be set + function updateRequest( + bytes memory _request, + uint64 _subscriptionId, + uint32 _gasLimit, + bytes32 _donID + ) external onlyOwner { + request = _request; + subscriptionId = _subscriptionId; + gasLimit = _gasLimit; + donID = _donID; + } + + /** + * @notice Store latest result/error + * @param requestId The request ID, returned by sendRequest() + * @param response Aggregated response from the user code + * @param err Aggregated error from the user code or from the execution pipeline + * Either response or error parameter will be set, but never both + */ + function fulfillRequest( + bytes32 requestId, + bytes memory response, + bytes memory err + ) internal override { + if (s_lastRequestId != requestId) { + revert UnexpectedRequestID(requestId); + } + s_lastResponse = response; + s_lastError = err; + s_responseCounter = s_responseCounter + 1; + emit Response(requestId, s_lastResponse, s_lastError); + } + } + ``` + 2. Compile the contract. 3. Open MetaMask and select the *Ethereum Sepolia* network. @@ -3484,6 +4130,103 @@ The consumer contract for Automated Functions is different from the consumer in 1. Open the [AutomatedFunctionsConsumerExample.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/AutomatedFunctionsConsumerExample.sol) in Remix. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; + + import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; + import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + + /** + * @title Functions contract used for Automation. + * @notice This contract is a demonstration of using Functions and Automation. + * @notice You may need to add a Forwarder for additional security. + * @notice NOT FOR PRODUCTION USE + */ + contract AutomatedFunctionsConsumerExample is FunctionsClient, ConfirmedOwner { + address public upkeepContract; + bytes public request; + uint64 public subscriptionId; + uint32 public gasLimit; + bytes32 public donID; + bytes32 public s_lastRequestId; + bytes public s_lastResponse; + bytes public s_lastError; + + error NotAllowedCaller(address caller, address owner, address automationRegistry); + error UnexpectedRequestID(bytes32 requestId); + + event Response(bytes32 indexed requestId, bytes response, bytes err); + + constructor( + address router + ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} + + /** + * @notice Reverts if called by anyone other than the contract owner or automation registry. + */ + modifier onlyAllowed() { + if (msg.sender != owner() && msg.sender != upkeepContract) { + revert NotAllowedCaller(msg.sender, owner(), upkeepContract); + } + _; + } + + function setAutomationCronContract( + address _upkeepContract + ) external onlyOwner { + upkeepContract = _upkeepContract; + } + + /// @notice Update the request settings + /// @dev Only callable by the owner of the contract + /// @param _request The new encoded CBOR request to be set. The request is encoded offchain + /// @param _subscriptionId The new subscription ID to be set + /// @param _gasLimit The new gas limit to be set + /// @param _donID The new job ID to be set + function updateRequest( + bytes memory _request, + uint64 _subscriptionId, + uint32 _gasLimit, + bytes32 _donID + ) external onlyOwner { + request = _request; + subscriptionId = _subscriptionId; + gasLimit = _gasLimit; + donID = _donID; + } + + /** + * @notice Send a pre-encoded CBOR request + * @return requestId The ID of the sent request + */ + function sendRequestCBOR() external onlyAllowed returns (bytes32 requestId) { + s_lastRequestId = _sendRequest(request, subscriptionId, gasLimit, donID); + return s_lastRequestId; + } + + /** + * @notice Store latest result/error + * @param requestId The request ID, returned by sendRequest() + * @param response Aggregated response from the user code + * @param err Aggregated error from the user code or from the execution pipeline + * Either response or error parameter will be set, but never both + */ + function fulfillRequest( + bytes32 requestId, + bytes memory response, + bytes memory err + ) internal override { + if (s_lastRequestId != requestId) { + revert UnexpectedRequestID(requestId); + } + s_lastResponse = response; + s_lastError = err; + emit Response(requestId, s_lastResponse, s_lastError); + } + } + ``` + 2. Compile the contract. 3. Open MetaMask and select the *Ethereum Sepolia* network. diff --git a/src/content/chainlink-local/build/ccip/foundry/cct-burn-and-mint-fork.mdx b/src/content/chainlink-local/build/ccip/foundry/cct-burn-and-mint-fork.mdx index 4e3a49e6a34..1adf27d6485 100644 --- a/src/content/chainlink-local/build/ccip/foundry/cct-burn-and-mint-fork.mdx +++ b/src/content/chainlink-local/build/ccip/foundry/cct-burn-and-mint-fork.mdx @@ -17,7 +17,7 @@ This tutorial will guide you through the process of testing the procedure of ena <Aside type="note" title="Prerequisites"> Familiarize yourself with the [CCT standard](/ccip/concepts/cross-chain-token/overview) and [CCIP - architecture](/ccip/concepts/architecture) before proceeding with this tutorial. + architecture](/ccip/concepts/architecture/overview) before proceeding with this tutorial. </Aside> Before we start with this guide, let's recap parts of the CCT standard that we will need for it. diff --git a/src/content/chainlink-local/build/ccip/foundry/cct-lock-and-release-fork.mdx b/src/content/chainlink-local/build/ccip/foundry/cct-lock-and-release-fork.mdx index 3dedccb65c0..c58eb041a0d 100644 --- a/src/content/chainlink-local/build/ccip/foundry/cct-lock-and-release-fork.mdx +++ b/src/content/chainlink-local/build/ccip/foundry/cct-lock-and-release-fork.mdx @@ -17,7 +17,7 @@ This tutorial will guide you through the process of testing the procedure of ena <Aside type="note" title="Prerequisites"> Familiarize yourself with the [CCT standard](/ccip/concepts/cross-chain-token/overview) and [CCIP - architecture](/ccip/concepts/architecture) before proceeding with this tutorial. + architecture](/ccip/concepts/architecture/overview) before proceeding with this tutorial. </Aside> Before we start with this guide, let's recap parts of the CCT standard that we will need for it. diff --git a/src/content/chainlink-local/llms-full.txt b/src/content/chainlink-local/llms-full.txt index 78665fff997..2a3a13dbf28 100644 --- a/src/content/chainlink-local/llms-full.txt +++ b/src/content/chainlink-local/llms-full.txt @@ -5820,7 +5820,7 @@ This tutorial will guide you through the process of testing the procedure of ena <Aside type="note" title="Prerequisites"> Familiarize yourself with the [CCT standard](/ccip/concepts/cross-chain-token/overview) and [CCIP - architecture](/ccip/concepts/architecture) before proceeding with this tutorial. + architecture](/ccip/concepts/architecture/overview) before proceeding with this tutorial. </Aside> Before we start with this guide, let's recap parts of the CCT standard that we will need for it. @@ -6629,7 +6629,7 @@ This tutorial will guide you through the process of testing the procedure of ena <Aside type="note" title="Prerequisites"> Familiarize yourself with the [CCT standard](/ccip/concepts/cross-chain-token/overview) and [CCIP - architecture](/ccip/concepts/architecture) before proceeding with this tutorial. + architecture](/ccip/concepts/architecture/overview) before proceeding with this tutorial. </Aside> Before we start with this guide, let's recap parts of the CCT standard that we will need for it. @@ -8519,10 +8519,184 @@ does not persist the files that you open from an external source. To save files, 3. Copy the content of the [Test CCIP Local Simulator contract](https://docs.chain.link/samples/CCIP/TestCCIPLocalSimulator.sol) into a new file in the workspace. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity 0.8.24; + + // solhint-disable no-unused-import + // import {CCIPLocalSimulator} from "@chainlink/local/src/ccip/CCIPLocalSimulator.sol"; + ``` + 4. Copy the content of the [Sender contract](https://docs.chain.link/samples/CCIP/Sender.sol) into a new file in the workspace. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity 0.8.24; + + import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; + + import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; + import {OwnerIsCreator} from "@chainlink/contracts/src/v0.8/shared/access/OwnerIsCreator.sol"; + import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + + /// @title - A simple contract for sending string data across chains. + contract Sender is OwnerIsCreator { + // Custom errors to provide more descriptive revert messages. + error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough + // balance. + + // Event emitted when a message is sent to another chain. + // The chain selector of the destination chain. + // The address of the receiver on the destination chain. + // The text being sent. + // the token address used to pay CCIP fees. + // The fees paid for sending the CCIP message. + event MessageSent( // The unique ID of the CCIP message. + bytes32 indexed messageId, + uint64 indexed destinationChainSelector, + address receiver, + string text, + address feeToken, + uint256 fees + ); + + IRouterClient private s_router; + + LinkTokenInterface private s_linkToken; + + /// @notice Constructor initializes the contract with the router address. + /// @param _router The address of the router contract. + /// @param _link The address of the link contract. + constructor( + address _router, + address _link + ) { + s_router = IRouterClient(_router); + s_linkToken = LinkTokenInterface(_link); + } + + /// @notice Sends data to receiver on the destination chain. + /// @dev Assumes your contract has sufficient LINK. + /// @param destinationChainSelector The identifier (aka selector) for the destination blockchain. + /// @param receiver The address of the recipient on the destination blockchain. + /// @param text The string text to be sent. + /// @return messageId The ID of the message that was sent. + function sendMessage( + uint64 destinationChainSelector, + address receiver, + string calldata text + ) external onlyOwner returns (bytes32 messageId) { + // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message + Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({ + receiver: abi.encode(receiver), // ABI-encoded receiver address + data: abi.encode(text), // ABI-encoded string + tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array indicating no tokens are being sent + extraArgs: Client._argsToBytes( + // Additional arguments, setting gas limit and allowing out-of-order execution. + // Best Practice: For simplicity, the values are hardcoded. It is advisable to use a more dynamic approach + // where you set the extra arguments off-chain. This allows adaptation depending on the lanes, messages, + // and ensures compatibility with future CCIP upgrades. Read more about it here: + // https://docs.chain.link/ccip/concepts/best-practices/evm#using-extraargs + Client.GenericExtraArgsV2({ + gasLimit: 200_000, // Gas limit for the callback on the destination chain + allowOutOfOrderExecution: true // Allows the message to be executed out of order relative to other messages + // from + // the same sender + }) + ), + // Set the feeToken address, indicating LINK will be used for fees + feeToken: address(s_linkToken) + }); + + // Get the fee required to send the message + uint256 fees = s_router.getFee(destinationChainSelector, evm2AnyMessage); + + if (fees > s_linkToken.balanceOf(address(this))) { + revert NotEnoughBalance(s_linkToken.balanceOf(address(this)), fees); + } + + // approve the Router to transfer LINK tokens on contract's behalf. It will spend the fees in LINK + s_linkToken.approve(address(s_router), fees); + + // Send the message through the router and store the returned message ID + messageId = s_router.ccipSend(destinationChainSelector, evm2AnyMessage); + + // Emit an event with message details + emit MessageSent(messageId, destinationChainSelector, receiver, text, address(s_linkToken), fees); + + // Return the message ID + return messageId; + } + } + ``` + 5. Copy the content of the [Receiver contract](https://docs.chain.link/samples/CCIP/Receiver.sol) into a new file in the workspace. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity 0.8.24; + + import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; + import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + + /// @title - A simple contract for receiving string data across chains. + contract Receiver is CCIPReceiver { + // Event emitted when a message is received from another chain. + event MessageReceived( // The unique ID of the message. + // The chain selector of the source chain. + // The address of the sender from the source chain. + // The text that was received. + bytes32 indexed messageId, + uint64 indexed sourceChainSelector, + address sender, + string text + ); + + bytes32 private s_lastReceivedMessageId; // Store the last received messageId. + string private s_lastReceivedText; // Store the last received text. + + /// @notice Constructor initializes the contract with the router address. + /// @param router The address of the router contract. + constructor( + address router + ) CCIPReceiver(router) {} + + /// handle a received message + function _ccipReceive( + Client.Any2EVMMessage memory any2EvmMessage + ) internal override { + s_lastReceivedMessageId = any2EvmMessage.messageId; // fetch the messageId + s_lastReceivedText = abi.decode(any2EvmMessage.data, (string)); // abi-decoding of the sent text + + emit MessageReceived( + any2EvmMessage.messageId, + any2EvmMessage.sourceChainSelector, // fetch the source chain identifier (aka selector) + abi.decode(any2EvmMessage.sender, (address)), // abi-decoding of the sender address, + abi.decode(any2EvmMessage.data, (string)) + ); + } + + /// @notice Fetches the details of the last received message. + /// @return messageId The ID of the last received message. + /// @return text The last received text. + function getLastReceivedMessageDetails() external view returns (bytes32 messageId, string memory text) { + return (s_lastReceivedMessageId, s_lastReceivedText); + } + } + ``` + At this point, you should have three files in your workspace: - **TestCCIPLocalSimulator.sol**: The file imports the Chainlink CCIP local simulator contract. diff --git a/src/content/chainlink-nodes/llms-full.txt b/src/content/chainlink-nodes/llms-full.txt index 159ea772dce..680f39054bc 100644 --- a/src/content/chainlink-nodes/llms-full.txt +++ b/src/content/chainlink-nodes/llms-full.txt @@ -1250,6 +1250,40 @@ Source: https://docs.chain.link/chainlink-nodes/job-specs/direct-request-get-str This is an example v2 (TOML) job spec for returning a *string* in one Chainlink API Call. Note that the job calls the `fulfillOracleRequest2` function. If you are a node operator, use an [Operator contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/operatorforwarder/Operator.sol) with this job. To test it from a smart contract, see this [Example](/any-api/get-request/examples/array-response). + +```toml +# THIS IS EXAMPLE CODE THAT USES HARDCODED VALUES FOR CLARITY. +# THIS IS EXAMPLE CODE THAT USES UN-AUDITED CODE. +# DO NOT USE THIS CODE IN PRODUCTION. + +type = "directrequest" +# evmChainID for Sepolia Testnet +evmChainID = "11155111" +schemaVersion = 1 +name = "Get > String" +contractAddress = "YOUR_ORACLE_CONTRACT_ADDRESS" +maxTaskDuration = "0s" +minIncomingConfirmations = 0 +observationSource = """ + decode_log [type="ethabidecodelog" + abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" + data="$(jobRun.logData)" + topics="$(jobRun.logTopics)"] + + decode_cbor [type="cborparse" data="$(decode_log.data)"] + fetch [type="http" method=GET url="$(decode_cbor.get)" allowUnrestrictedNetworkAccess="true"] + parse [type="jsonparse" path="$(decode_cbor.path)" data="$(fetch)"] + encode_data [type="ethabiencode" abi="(bytes32 requestId, string value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(parse) }"] + encode_tx [type="ethabiencode" + abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" + data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" + ] + submit_tx [type="ethtx" to="YOUR_ORACLE_CONTRACT_ADDRESS" data="$(encode_tx)"] + + decode_log -> decode_cbor -> fetch -> parse -> encode_data -> encode_tx -> submit_tx +""" +``` + --- # GET > Uint256 Example Job Spec @@ -4034,6 +4068,44 @@ You will create a job that calls an OpenAPI , parses the response and then retur 2. Paste the job specification from above into the text field. + ```toml + # THIS IS EXAMPLE CODE THAT USES HARDCODED VALUES FOR CLARITY. + # THIS IS EXAMPLE CODE THAT USES UN-AUDITED CODE. + # DO NOT USE THIS CODE IN PRODUCTION. + + name = "Get > Uint256 - (TOML)" + schemaVersion = 1 + type = "directrequest" + # evmChainID for Sepolia Testnet + evmChainID = "11155111" + # Optional External Job ID: Automatically generated if unspecified + # externalJobID = "b1d42cd5-4a3a-4200-b1f7-25a68e48aad8" + contractAddress = "YOUR_OPERATOR_CONTRACT_ADDRESS" + maxTaskDuration = "0s" + minIncomingConfirmations = 0 + observationSource = """ + decode_log [type="ethabidecodelog" + abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" + data="$(jobRun.logData)" + topics="$(jobRun.logTopics)"] + + decode_cbor [type="cborparse" data="$(decode_log.data)"] + fetch [type="http" method=GET url="$(decode_cbor.get)" allowUnrestrictedNetworkAccess="true"] + parse [type="jsonparse" path="$(decode_cbor.path)" data="$(fetch)"] + + multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"] + + encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"] + encode_tx [type="ethabiencode" + abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" + data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" + ] + submit_tx [type="ethtx" to="YOUR_OPERATOR_CONTRACT_ADDRESS" data="$(encode_tx)"] + + decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx + """ + ``` + 3. Replace `YOUR_OPERATOR_CONTRACT_ADDRESS` with the address of your deployed operator contract address from the previous steps. 4. Click **Create Job**. If the node creates the job successfully, a notice with the job number appears. @@ -4434,6 +4506,7 @@ MaxBatchSize = 50 # Default SendInterval = '500ms' # Default SendTimeout = '10s' # Default UseBatchSend = true # Default +ChipIngressEnabled = false # Default ``` ### UniConn @@ -4492,6 +4565,14 @@ UseBatchSend = true # Default UseBatchSend toggles sending telemetry to the ingress server using the batch client. +### ChipIngressEnabled + +```toml +ChipIngressEnabled = false # Default +``` + +ChipIngressEnabled enables sending telemetry to CHIP Ingress. + ## TelemetryIngress.Endpoints ```toml @@ -5104,6 +5185,76 @@ UnauthenticatedPeriod = '20s' # Default UnauthenticatedPeriod defines the period to which unauthenticated requests get limited. +## WebServer.OIDC + +```toml +[WebServer.OIDC] +ClientID = "abc123" # Example +ProviderURL = "https://id.example.com/oauth2/default" # Example +RedirectURL = "https://your-node.example.com/signin" # Default +ClaimName = 'groups' # Default +AdminClaim = 'NodeAdmins' # Default +EditClaim = 'NodeEditors' # Default +RunClaim = 'NodeRunners' # Default +ReadClaim = 'NodeReadOnly' # Default +SessionTimeout = '15m0s' # Default +UserApiTokenEnabled = false # Default +UserAPITokenDuration = '240h0m0s' # Default +``` + +Optional OIDC configuration (when `WebServer.AuthenticationMethod` is set to `oidc`) enables SSO via OpenID Connect. Register a new OIDC application with your identity provider to get a Client ID and Secret for the TOML fields. When OIDC is enabled, the chainlink node will redirect users to the provider and use the returned ID token for authentication and role assignment. The Client Secret should be populated in the your `secrets.toml` as follows: + +```toml +[WebServer.OIDC] +clientSecret = "secret" # Example +``` + +### ClientID + +`ClientID` is the identifier issued by your OIDC provider when registering the Chainlink node application. It represents the expected audience of the ID token. **Required**. + +### ProviderURL + +`ProviderURL` is the base issuer or discovery URL for your OIDC provider (e.g., the `.well-known/openid-configuration` endpoint). **Required**. + +### RedirectURL + +`RedirectURL` is the callback URL on the Chainlink node (this should be path: `/signin`) to which the IdP redirects after login. This must match the allowed redirect URIs configured in your IdP. **Required**. + +### ClaimName + +`ClaimName` specifies the JWT claim containing group or role information (default: `groups`). Change if your provider uses a different claim name. + +### AdminClaim + +`AdminClaim` is the claim value (within `ClaimName`) that maps to the Chainlink **Admin** role (default: `NodeAdmins`). + +### EditClaim + +`EditClaim` is the claim value that maps to the **Edit** role (default: `NodeEditors`). + +### RunClaim + +`RunClaim` is the claim value that maps to the **Run** role (default: `NodeRunners`). + +### ReadClaim + +`ReadClaim` is the claim value that maps to the **Read-Only** role (default: `NodeReadOnly`). + +### SessionTimeout + +`SessionTimeout` defines how long an OIDC session can remain idle before timing out (default: `15m0s`). + +### UserApiTokenEnabled + +`UserApiTokenEnabled` enables OIDC users to generate API tokens with the same permissions as their role (default: `false`). + +### UserAPITokenDuration + +`UserAPITokenDuration` sets the lifespan of API tokens issued by OIDC users (default: `240h0m0s`). + +> **Note:** Configure the OIDC client’s secret (`WebServer.OIDC.ClientSecret`) via the node’s secret management (e.g., environment variable `CL_WEB_SERVER_OIDC_CLIENT_SECRET`). Keep the client secret secure and do not expose it in plaintext configuration. + ## WebServer.MFA ```toml @@ -5360,6 +5511,7 @@ AllowNoBootstrappers = false # Default DefaultTransactionQueueDepth = 1 # Default SimulateTransactions = false # Default TraceLogging = false # Default +SampleTelemetry = false # Default KeyValueStoreRootDir = '~/.chainlink-data' # Default ``` @@ -5509,6 +5661,14 @@ TraceLogging = false # Default TraceLogging enables trace level logging. +### SampleTelemetry + +```toml +SampleTelemetry = false # Default +``` + +SampleTelemetry enables telemetry sampling. + ### KeyValueStoreRootDir ```toml @@ -5652,6 +5812,7 @@ IncomingMessageBufferSize = 10 # Default OutgoingMessageBufferSize = 10 # Default PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example TraceLogging = false # Default +EnableExperimentalRageP2P = false # Default ``` P2P has a versioned networking stack. Currently only `[P2P.V2]` is supported. @@ -5696,6 +5857,14 @@ TraceLogging = false # Default TraceLogging enables trace level logging. +### EnableExperimentalRageP2P + +```toml +EnableExperimentalRageP2P = false # Default +``` + +EnableExperimentalRageP2P needs to be enabled for ocr3.1 components + ## P2P.V2 ```toml @@ -6076,6 +6245,7 @@ IncomingMessageBufferSize = 10 # Default OutgoingMessageBufferSize = 10 # Default PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example TraceLogging = false # Default +EnableExperimentalRageP2P = false # Default ``` ### IncomingMessageBufferSize @@ -6117,6 +6287,14 @@ TraceLogging = false # Default TraceLogging enables trace level logging. +### EnableExperimentalRageP2P + +```toml +EnableExperimentalRageP2P = false # Default +``` + +EnableExperimentalRageP2P needs to be enabled for ocr3.1 components + ## Capabilities.Peering.V2 ```toml @@ -6974,11 +7152,17 @@ InsecureConnection = false # Default TraceSampleRatio = 0.01 # Default EmitterBatchProcessor = true # Default EmitterExportTimeout = '1s' # Default +AuthHeadersTTL = '0s' # Default ChipIngressEndpoint = '' # Default ChipIngressInsecureConnection = false # Default HeartbeatInterval = '1s' # Default LogLevel = "info" # Default LogStreamingEnabled = false # Default +LogBatchProcessor = true # Default +LogExportTimeout = '1s' # Default +LogExportMaxBatchSize = 512 # Default +LogExportInterval = '1s' # Default +LogMaxQueueSize = 2048 # Default ``` Telemetry holds OTEL settings. @@ -7043,6 +7227,15 @@ EmitterExportTimeout = '1s' # Default EmitterExportTimeout sets timeout for exporting telemetry events +### AuthHeadersTTL + +```toml +AuthHeadersTTL = '0s' # Default +``` + +AuthHeadersTTL is the time-to-live for rotating authentication headers used with telemetry endpoints. +Set to 0 to use static authentication headers. + ### ChipIngressEndpoint ```toml @@ -7083,6 +7276,46 @@ LogStreamingEnabled = false # Default LogStreamingEnabled enables log streaming to the OTel log exporter +### LogBatchProcessor + +```toml +LogBatchProcessor = true # Default +``` + +LogBatchProcessor enables batching for telemetry logs + +### LogExportTimeout + +```toml +LogExportTimeout = '1s' # Default +``` + +LogExportTimeout sets timeout for exporting telemetry logs + +### LogExportMaxBatchSize + +```toml +LogExportMaxBatchSize = 512 # Default +``` + +LogExportMaxBatchSize sets the maximum batch size of every batch export + +### LogExportInterval + +```toml +LogExportInterval = '1s' # Default +``` + +LogExportInterval sets the maximum duration between batched exports + +### LogMaxQueueSize + +```toml +LogMaxQueueSize = 2048 # Default +``` + +LogMaxQueueSize sets the maximum queue size used by the batcher + ## Telemetry.ResourceAttributes ```toml @@ -7365,7 +7598,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -7480,7 +7713,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -7595,7 +7828,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -7710,7 +7943,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -7830,7 +8063,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -7946,7 +8179,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8061,7 +8294,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8175,7 +8408,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8289,7 +8522,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8404,7 +8637,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8519,7 +8752,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8635,7 +8868,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8750,7 +8983,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8865,7 +9098,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8985,7 +9218,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9100,7 +9333,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9215,7 +9448,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9330,7 +9563,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9450,7 +9683,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9567,7 +9800,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -9684,7 +9917,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -9804,7 +10037,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9922,7 +10155,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10041,7 +10274,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10156,7 +10389,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10270,7 +10503,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10390,7 +10623,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -10509,7 +10742,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10625,7 +10858,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10741,7 +10974,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10860,7 +11093,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10979,7 +11212,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -11099,7 +11332,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -11219,7 +11452,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -11334,7 +11567,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -11450,7 +11683,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -11570,7 +11803,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -11684,7 +11917,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -11804,7 +12037,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -11921,7 +12154,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -12037,7 +12270,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -12153,7 +12386,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -12268,7 +12501,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -12382,7 +12615,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -12502,7 +12735,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -12622,7 +12855,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -12736,7 +12969,7 @@ EnforceRepeatableRead = false DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -12856,7 +13089,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -12976,7 +13209,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -13091,7 +13324,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13206,7 +13439,121 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 + +[OCR] +ContractConfirmations = 4 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5400000 + +[Workflow] +GasLimitDefault = 400000 +TxAcceptanceState = 2 +PollPeriod = '2s' +AcceptanceTimeout = '30s' +``` + +### Private Testnet Andesite (2024) + +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +FinalityDepth = 1 +SafeDepth = 0 +FinalityTagEnabled = false +SafeTagSupported = true +LogBackfillBatchSize = 1000 +LogPollInterval = '15s' +LogKeepBlocksDepth = 100000 +LogPrunePageSize = 0 +BackupLogPollerBlockDelay = 100 +MinIncomingConfirmations = 3 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '3m0s' +LogBroadcasterEnabled = false +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 +NoNewFinalizedHeadsThreshold = '0s' + +[Transactions] +Enabled = true +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '1m0s' +ConfirmationTimeout = '1m0s' + +[Transactions.AutoPurge] +Enabled = false + +[Transactions.TransactionManagerV2] +Enabled = false + +[BalanceMonitor] +Enabled = false + +[GasEstimator] +Mode = 'SuggestedPrice' +PriceDefault = '0' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '0' +LimitDefault = 250000000 +LimitMax = 250000000 +LimitMultiplier = '4' +LimitTransfer = 21000 +EstimateLimit = false +BumpMin = '5 gwei' +BumpPercent = 20 +BumpThreshold = 3 +EIP1559DynamicFees = false +FeeCapDefault = '0' +TipCapDefault = '0' +TipCapMin = '0' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[GasEstimator.FeeHistory] +CacheTimeout = '10s' + +[HeadTracker] +HistoryDepth = 100 +MaxBufferSize = 3 +SamplingInterval = '1s' +MaxAllowedFinalityDepth = 10000 +FinalityTagBypass = false +PersistenceEnabled = false +PersistenceBatchSize = 100 + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 5 +LeaseDuration = '0s' +NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = true +DeathDeclarationDelay = '1m0s' +NewHeadsPollInterval = '0s' +VerifyChainID = true +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13326,7 +13673,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -13443,7 +13790,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -13557,7 +13904,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13672,7 +14019,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13787,7 +14134,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13902,7 +14249,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14018,7 +14365,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -14138,7 +14485,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14259,7 +14606,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14380,7 +14727,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14494,7 +14841,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -14614,7 +14961,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -14728,7 +15075,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '4s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14844,7 +15191,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14963,7 +15310,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15082,7 +15429,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15197,7 +15544,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -15317,7 +15664,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -15436,7 +15783,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [NodePool.Errors] TerminallyUnderpriced = '(?:: |^)(max fee per gas less than block base fee|virtual machine entered unexpected state. (?:P|p)lease contact developers and provide transaction details that caused this error. Error description: (?:The operator included transaction with an unacceptable gas price|Assertion error: Fair pubdata price too high)) @@ -15540,7 +15887,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15656,7 +16003,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15775,7 +16122,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '4s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -15890,7 +16237,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -16005,7 +16352,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -16121,7 +16468,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -16243,7 +16590,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -16365,7 +16712,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -16480,7 +16827,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16600,7 +16947,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16714,7 +17061,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16831,7 +17178,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16948,7 +17295,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -17068,7 +17415,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -17188,7 +17535,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -17306,7 +17653,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -17421,7 +17768,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -17536,7 +17883,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -17651,7 +17998,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -17766,7 +18113,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -17886,7 +18233,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -18005,7 +18352,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -18125,7 +18472,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -18239,7 +18586,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -18353,7 +18700,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -18472,7 +18819,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -18586,7 +18933,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -18700,7 +19047,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -18819,7 +19166,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -18934,7 +19281,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -19049,7 +19396,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -19168,7 +19515,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -19287,7 +19634,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -19406,7 +19753,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -19527,7 +19874,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -19648,7 +19995,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -19764,7 +20111,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -19883,7 +20230,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '4s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -20002,7 +20349,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -20122,7 +20469,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -20242,7 +20589,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -20360,7 +20707,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -20475,7 +20822,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -20595,7 +20942,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -20714,7 +21061,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -20833,7 +21180,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -20953,7 +21300,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -21068,7 +21415,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -21183,7 +21530,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -21401,7 +21748,7 @@ BackupLogPollerDelay=0 will disable Backup LogPoller (*not recommended for produ MinContractPayment = '10000000000000 juels' # Default ``` -MinContractPayment is the minimum payment in LINK required to execute a direct request job. This can be overridden on a per-job basis. +MinContractPayment is the minimum payment in LINK required to execute a direct request job. This can be overriden on a per-job basis. ### MinIncomingConfirmations @@ -22272,7 +22619,7 @@ EnforceRepeatableRead = true # Default DeathDeclarationDelay = '1m' # Default NewHeadsPollInterval = '0s' # Default VerifyChainID = true # Default -ExternalRequestMaxResponseSize = 50000 # Default +ExternalRequestMaxResponseSize = 1000000 # Default ``` The node pool manages multiple RPC endpoints. @@ -22407,7 +22754,7 @@ VerifyChainID enforces RPC Client ChainIDs to match configured ChainID ### ExternalRequestMaxResponseSize ```toml -ExternalRequestMaxResponseSize = 50000 # Default +ExternalRequestMaxResponseSize = 1000000 # Default ``` ExternalRequestMaxResponseSize sets the maximum allowed size (in bytes) for responses to external requests. @@ -23158,7 +23505,7 @@ Ensure the value is greater than the number of blocks that would be produced bet ComputeUnitLimitDefault = 200_000 # Default ``` -ComputeUnitLimitDefault is the compute units limit applied to transactions unless overridden during the txm enqueue +ComputeUnitLimitDefault is the compute units limit applied to transactions unless overriden during the txm enqueue ### EstimateComputeUnitLimit @@ -24355,10 +24702,81 @@ This section is similar to the [Fulfilling Requests](/chainlink-nodes/v1/fulfill - `YOUR_OPERATOR_CONTRACT_ADDRESS` with the address of your deployed operator contract address. - `EOA_ADDRESS` with the **first** Chainlink node EOA. + ```toml + # THIS IS EXAMPLE CODE THAT USES HARDCODED VALUES FOR CLARITY. + # THIS IS EXAMPLE CODE THAT USES UN-AUDITED CODE. + # DO NOT USE THIS CODE IN PRODUCTION. + + # evmChainID for Sepolia Testnet + evmChainID = "11155111" + contractAddress = "YOUR_OPERATOR_CONTRACT_ADDRESS" + forwardingAllowed = true + maxTaskDuration = "0s" + minIncomingConfirmations = 0 + name = "Get > Uint256" + observationSource = """ + decode_log [type="ethabidecodelog" + abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" + data="$(jobRun.logData)" + topics="$(jobRun.logTopics)"] + + decode_cbor [type="cborparse" data="$(decode_log.data)"] + fetch [type="http" method=GET url="$(decode_cbor.get)" allowUnrestrictedNetworkAccess="true"] + parse [type="jsonparse" path="$(decode_cbor.path)" data="$(fetch)"] + + multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"] + + encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"] + encode_tx [type="ethabiencode" + abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" + data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" + ] + submit_tx [type="ethtx" to="YOUR_OPERATOR_CONTRACT_ADDRESS" data="$(encode_tx)" from="[\\"EOA_ADDRESS\\"]"] + + decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx + """ + schemaVersion = 1 + type = "directrequest" + ``` + 4. Create the `string` job. Replace: - `YOUR_OPERATOR_CONTRACT_ADDRESS` with the address of your deployed operator contract address. - `EOA_ADDRESS` with the **second** Chainlink node EOA. + ```toml + # THIS IS EXAMPLE CODE THAT USES HARDCODED VALUES FOR CLARITY. + # THIS IS EXAMPLE CODE THAT USES UN-AUDITED CODE. + # DO NOT USE THIS CODE IN PRODUCTION. + + # evmChainID for Sepolia Testnet + evmChainID = "11155111" + contractAddress = "YOUR_OPERATOR_CONTRACT_ADDRESS" + forwardingAllowed = true + maxTaskDuration = "0s" + minIncomingConfirmations = 0 + name = "Get > String" + observationSource = """ + decode_log [type="ethabidecodelog" + abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" + data="$(jobRun.logData)" + topics="$(jobRun.logTopics)"] + + decode_cbor [type="cborparse" data="$(decode_log.data)"] + fetch [type="http" method=GET url="$(decode_cbor.get)" allowUnrestrictedNetworkAccess="true"] + parse [type="jsonparse" path="$(decode_cbor.path)" data="$(fetch)"] + encode_data [type="ethabiencode" abi="(bytes32 requestId, string value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(parse) }"] + encode_tx [type="ethabiencode" + abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" + data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" + ] + submit_tx [type="ethtx" to="YOUR_OPERATOR_CONTRACT_ADDRESS" data="$(encode_tx)" from="[\\"EOA_ADDRESS\\"]"] + + decode_log -> decode_cbor -> fetch -> parse -> encode_data -> encode_tx -> submit_tx + """ + schemaVersion = 1 + type = "directrequest" + ``` + 5. After you create the jobs, record the two job IDs. <Aside type="note"> diff --git a/src/content/chainlink-nodes/v1/node-config.mdx b/src/content/chainlink-nodes/v1/node-config.mdx index f18aa574631..43c1329401e 100644 --- a/src/content/chainlink-nodes/v1/node-config.mdx +++ b/src/content/chainlink-nodes/v1/node-config.mdx @@ -342,6 +342,7 @@ MaxBatchSize = 50 # Default SendInterval = '500ms' # Default SendTimeout = '10s' # Default UseBatchSend = true # Default +ChipIngressEnabled = false # Default ``` ### UniConn @@ -400,6 +401,14 @@ UseBatchSend = true # Default UseBatchSend toggles sending telemetry to the ingress server using the batch client. +### ChipIngressEnabled + +```toml +ChipIngressEnabled = false # Default +``` + +ChipIngressEnabled enables sending telemetry to CHIP Ingress. + ## TelemetryIngress.Endpoints ```toml @@ -1012,6 +1021,76 @@ UnauthenticatedPeriod = '20s' # Default UnauthenticatedPeriod defines the period to which unauthenticated requests get limited. +## WebServer.OIDC + +```toml +[WebServer.OIDC] +ClientID = "abc123" # Example +ProviderURL = "https://id.example.com/oauth2/default" # Example +RedirectURL = "https://your-node.example.com/signin" # Default +ClaimName = 'groups' # Default +AdminClaim = 'NodeAdmins' # Default +EditClaim = 'NodeEditors' # Default +RunClaim = 'NodeRunners' # Default +ReadClaim = 'NodeReadOnly' # Default +SessionTimeout = '15m0s' # Default +UserApiTokenEnabled = false # Default +UserAPITokenDuration = '240h0m0s' # Default +``` + +Optional OIDC configuration (when `WebServer.AuthenticationMethod` is set to `oidc`) enables SSO via OpenID Connect. Register a new OIDC application with your identity provider to get a Client ID and Secret for the TOML fields. When OIDC is enabled, the chainlink node will redirect users to the provider and use the returned ID token for authentication and role assignment. The Client Secret should be populated in the your `secrets.toml` as follows: + +```toml +[WebServer.OIDC] +clientSecret = "secret" # Example +``` + +### ClientID + +`ClientID` is the identifier issued by your OIDC provider when registering the Chainlink node application. It represents the expected audience of the ID token. **Required**. + +### ProviderURL + +`ProviderURL` is the base issuer or discovery URL for your OIDC provider (e.g., the `.well-known/openid-configuration` endpoint). **Required**. + +### RedirectURL + +`RedirectURL` is the callback URL on the Chainlink node (this should be path: `/signin`) to which the IdP redirects after login. This must match the allowed redirect URIs configured in your IdP. **Required**. + +### ClaimName + +`ClaimName` specifies the JWT claim containing group or role information (default: `groups`). Change if your provider uses a different claim name. + +### AdminClaim + +`AdminClaim` is the claim value (within `ClaimName`) that maps to the Chainlink **Admin** role (default: `NodeAdmins`). + +### EditClaim + +`EditClaim` is the claim value that maps to the **Edit** role (default: `NodeEditors`). + +### RunClaim + +`RunClaim` is the claim value that maps to the **Run** role (default: `NodeRunners`). + +### ReadClaim + +`ReadClaim` is the claim value that maps to the **Read-Only** role (default: `NodeReadOnly`). + +### SessionTimeout + +`SessionTimeout` defines how long an OIDC session can remain idle before timing out (default: `15m0s`). + +### UserApiTokenEnabled + +`UserApiTokenEnabled` enables OIDC users to generate API tokens with the same permissions as their role (default: `false`). + +### UserAPITokenDuration + +`UserAPITokenDuration` sets the lifespan of API tokens issued by OIDC users (default: `240h0m0s`). + +> **Note:** Configure the OIDC client’s secret (`WebServer.OIDC.ClientSecret`) via the node’s secret management (e.g., environment variable `CL_WEB_SERVER_OIDC_CLIENT_SECRET`). Keep the client secret secure and do not expose it in plaintext configuration. + ## WebServer.MFA ```toml @@ -1268,6 +1347,7 @@ AllowNoBootstrappers = false # Default DefaultTransactionQueueDepth = 1 # Default SimulateTransactions = false # Default TraceLogging = false # Default +SampleTelemetry = false # Default KeyValueStoreRootDir = '~/.chainlink-data' # Default ``` @@ -1417,6 +1497,14 @@ TraceLogging = false # Default TraceLogging enables trace level logging. +### SampleTelemetry + +```toml +SampleTelemetry = false # Default +``` + +SampleTelemetry enables telemetry sampling. + ### KeyValueStoreRootDir ```toml @@ -1560,6 +1648,7 @@ IncomingMessageBufferSize = 10 # Default OutgoingMessageBufferSize = 10 # Default PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example TraceLogging = false # Default +EnableExperimentalRageP2P = false # Default ``` P2P has a versioned networking stack. Currently only `[P2P.V2]` is supported. @@ -1604,6 +1693,14 @@ TraceLogging = false # Default TraceLogging enables trace level logging. +### EnableExperimentalRageP2P + +```toml +EnableExperimentalRageP2P = false # Default +``` + +EnableExperimentalRageP2P needs to be enabled for ocr3.1 components + ## P2P.V2 ```toml @@ -1984,6 +2081,7 @@ IncomingMessageBufferSize = 10 # Default OutgoingMessageBufferSize = 10 # Default PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example TraceLogging = false # Default +EnableExperimentalRageP2P = false # Default ``` ### IncomingMessageBufferSize @@ -2025,6 +2123,14 @@ TraceLogging = false # Default TraceLogging enables trace level logging. +### EnableExperimentalRageP2P + +```toml +EnableExperimentalRageP2P = false # Default +``` + +EnableExperimentalRageP2P needs to be enabled for ocr3.1 components + ## Capabilities.Peering.V2 ```toml @@ -2882,11 +2988,17 @@ InsecureConnection = false # Default TraceSampleRatio = 0.01 # Default EmitterBatchProcessor = true # Default EmitterExportTimeout = '1s' # Default +AuthHeadersTTL = '0s' # Default ChipIngressEndpoint = '' # Default ChipIngressInsecureConnection = false # Default HeartbeatInterval = '1s' # Default LogLevel = "info" # Default LogStreamingEnabled = false # Default +LogBatchProcessor = true # Default +LogExportTimeout = '1s' # Default +LogExportMaxBatchSize = 512 # Default +LogExportInterval = '1s' # Default +LogMaxQueueSize = 2048 # Default ``` Telemetry holds OTEL settings. @@ -2951,6 +3063,15 @@ EmitterExportTimeout = '1s' # Default EmitterExportTimeout sets timeout for exporting telemetry events +### AuthHeadersTTL + +```toml +AuthHeadersTTL = '0s' # Default +``` + +AuthHeadersTTL is the time-to-live for rotating authentication headers used with telemetry endpoints. +Set to 0 to use static authentication headers. + ### ChipIngressEndpoint ```toml @@ -2991,6 +3112,46 @@ LogStreamingEnabled = false # Default LogStreamingEnabled enables log streaming to the OTel log exporter +### LogBatchProcessor + +```toml +LogBatchProcessor = true # Default +``` + +LogBatchProcessor enables batching for telemetry logs + +### LogExportTimeout + +```toml +LogExportTimeout = '1s' # Default +``` + +LogExportTimeout sets timeout for exporting telemetry logs + +### LogExportMaxBatchSize + +```toml +LogExportMaxBatchSize = 512 # Default +``` + +LogExportMaxBatchSize sets the maximum batch size of every batch export + +### LogExportInterval + +```toml +LogExportInterval = '1s' # Default +``` + +LogExportInterval sets the maximum duration between batched exports + +### LogMaxQueueSize + +```toml +LogMaxQueueSize = 2048 # Default +``` + +LogMaxQueueSize sets the maximum queue size used by the batcher + ## Telemetry.ResourceAttributes ```toml @@ -3273,7 +3434,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -3388,7 +3549,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -3503,7 +3664,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -3618,7 +3779,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -3738,7 +3899,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -3854,7 +4015,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -3969,7 +4130,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -4083,7 +4244,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -4197,7 +4358,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -4312,7 +4473,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -4427,7 +4588,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -4543,7 +4704,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -4658,7 +4819,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -4773,7 +4934,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -4893,7 +5054,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -5008,7 +5169,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -5123,7 +5284,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -5238,7 +5399,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -5358,7 +5519,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -5475,7 +5636,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -5592,7 +5753,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -5712,7 +5873,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -5830,7 +5991,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -5949,7 +6110,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -6064,7 +6225,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -6178,7 +6339,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -6298,7 +6459,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -6417,7 +6578,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -6533,7 +6694,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -6649,7 +6810,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -6768,7 +6929,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -6887,7 +7048,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -7007,7 +7168,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -7127,7 +7288,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -7242,7 +7403,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -7358,7 +7519,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -7478,7 +7639,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -7592,7 +7753,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -7712,7 +7873,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -7829,7 +7990,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -7945,7 +8106,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -8061,7 +8222,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -8176,7 +8337,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8290,7 +8451,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8410,7 +8571,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8530,7 +8691,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -8644,7 +8805,7 @@ EnforceRepeatableRead = false DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -8764,7 +8925,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -8884,7 +9045,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -8999,7 +9160,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9114,7 +9275,121 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 + +[OCR] +ContractConfirmations = 4 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +DeltaCOverride = '168h0m0s' +DeltaCJitterOverride = '1h0m0s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5400000 + +[Workflow] +GasLimitDefault = 400000 +TxAcceptanceState = 2 +PollPeriod = '2s' +AcceptanceTimeout = '30s' +``` + +### Private Testnet Andesite (2024) + +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +FinalityDepth = 1 +SafeDepth = 0 +FinalityTagEnabled = false +SafeTagSupported = true +LogBackfillBatchSize = 1000 +LogPollInterval = '15s' +LogKeepBlocksDepth = 100000 +LogPrunePageSize = 0 +BackupLogPollerBlockDelay = 100 +MinIncomingConfirmations = 3 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '3m0s' +LogBroadcasterEnabled = false +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 +NoNewFinalizedHeadsThreshold = '0s' + +[Transactions] +Enabled = true +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '1m0s' +ConfirmationTimeout = '1m0s' + +[Transactions.AutoPurge] +Enabled = false + +[Transactions.TransactionManagerV2] +Enabled = false + +[BalanceMonitor] +Enabled = false + +[GasEstimator] +Mode = 'SuggestedPrice' +PriceDefault = '0' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '0' +LimitDefault = 250000000 +LimitMax = 250000000 +LimitMultiplier = '4' +LimitTransfer = 21000 +EstimateLimit = false +BumpMin = '5 gwei' +BumpPercent = 20 +BumpThreshold = 3 +EIP1559DynamicFees = false +FeeCapDefault = '0' +TipCapDefault = '0' +TipCapMin = '0' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[GasEstimator.FeeHistory] +CacheTimeout = '10s' + +[HeadTracker] +HistoryDepth = 100 +MaxBufferSize = 3 +SamplingInterval = '1s' +MaxAllowedFinalityDepth = 10000 +FinalityTagBypass = false +PersistenceEnabled = false +PersistenceBatchSize = 100 + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 5 +LeaseDuration = '0s' +NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = true +DeathDeclarationDelay = '1m0s' +NewHeadsPollInterval = '0s' +VerifyChainID = true +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9234,7 +9509,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -9351,7 +9626,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -9465,7 +9740,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9580,7 +9855,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9695,7 +9970,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9810,7 +10085,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -9926,7 +10201,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -10046,7 +10321,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10167,7 +10442,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10288,7 +10563,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10402,7 +10677,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -10522,7 +10797,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -10636,7 +10911,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '4s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10752,7 +11027,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -10871,7 +11146,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -10990,7 +11265,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -11105,7 +11380,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -11225,7 +11500,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -11344,7 +11619,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [NodePool.Errors] TerminallyUnderpriced = '(?:: |^)(max fee per gas less than block base fee|virtual machine entered unexpected state. (?:P|p)lease contact developers and provide transaction details that caused this error. Error description: (?:The operator included transaction with an unacceptable gas price|Assertion error: Fair pubdata price too high)) @@ -11448,7 +11723,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -11564,7 +11839,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -11683,7 +11958,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '4s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -11798,7 +12073,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -11913,7 +12188,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -12029,7 +12304,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -12151,7 +12426,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -12273,7 +12548,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -12388,7 +12663,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -12508,7 +12783,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -12622,7 +12897,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -12739,7 +13014,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -12856,7 +13131,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -12976,7 +13251,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -13096,7 +13371,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13214,7 +13489,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13329,7 +13604,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13444,7 +13719,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13559,7 +13834,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13674,7 +13949,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13794,7 +14069,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -13913,7 +14188,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -14033,7 +14308,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -14147,7 +14422,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14261,7 +14536,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14380,7 +14655,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14494,7 +14769,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -14608,7 +14883,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -14727,7 +15002,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14842,7 +15117,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -14957,7 +15232,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -15076,7 +15351,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15195,7 +15470,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15314,7 +15589,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15435,7 +15710,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15556,7 +15831,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15672,7 +15947,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15791,7 +16066,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '4s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -15910,7 +16185,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16030,7 +16305,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16150,7 +16425,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16268,7 +16543,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16383,7 +16658,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16503,7 +16778,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 1 @@ -16622,7 +16897,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16741,7 +17016,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16861,7 +17136,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -16976,7 +17251,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -17091,7 +17366,7 @@ EnforceRepeatableRead = true DeathDeclarationDelay = '1m0s' NewHeadsPollInterval = '0s' VerifyChainID = true -ExternalRequestMaxResponseSize = 50000 +ExternalRequestMaxResponseSize = 1000000 [OCR] ContractConfirmations = 4 @@ -17309,7 +17584,7 @@ BackupLogPollerDelay=0 will disable Backup LogPoller (_not recommended for produ MinContractPayment = '10000000000000 juels' # Default ``` -MinContractPayment is the minimum payment in LINK required to execute a direct request job. This can be overridden on a per-job basis. +MinContractPayment is the minimum payment in LINK required to execute a direct request job. This can be overriden on a per-job basis. ### MinIncomingConfirmations @@ -18180,7 +18455,7 @@ EnforceRepeatableRead = true # Default DeathDeclarationDelay = '1m' # Default NewHeadsPollInterval = '0s' # Default VerifyChainID = true # Default -ExternalRequestMaxResponseSize = 50000 # Default +ExternalRequestMaxResponseSize = 1000000 # Default ``` The node pool manages multiple RPC endpoints. @@ -18315,7 +18590,7 @@ VerifyChainID enforces RPC Client ChainIDs to match configured ChainID ### ExternalRequestMaxResponseSize ```toml -ExternalRequestMaxResponseSize = 50000 # Default +ExternalRequestMaxResponseSize = 1000000 # Default ``` ExternalRequestMaxResponseSize sets the maximum allowed size (in bytes) for responses to external requests. @@ -19066,7 +19341,7 @@ Ensure the value is greater than the number of blocks that would be produced bet ComputeUnitLimitDefault = 200_000 # Default ``` -ComputeUnitLimitDefault is the compute units limit applied to transactions unless overridden during the txm enqueue +ComputeUnitLimitDefault is the compute units limit applied to transactions unless overriden during the txm enqueue ### EstimateComputeUnitLimit diff --git a/src/content/cre/capabilities/confidential-http-go.mdx b/src/content/cre/capabilities/confidential-http-go.mdx new file mode 100644 index 00000000000..8980d625c47 --- /dev/null +++ b/src/content/cre/capabilities/confidential-http-go.mdx @@ -0,0 +1,117 @@ +--- +section: cre +title: "The Confidential HTTP Capability (Experimental)" +date: Last Modified +sdkLang: "go" +pageId: "confidential-http" +metadata: + description: "CRE Confidential HTTP capability: make privacy-preserving API calls with enclave execution, secret injection, and optional response encryption." + datePublished: "2026-02-06" + lastModified: "2026-02-06" +--- + +import { Aside } from "@components" + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The **Confidential HTTP** capability is a privacy-preserving HTTP service powered by the Chainlink Privacy Standard. It enables your workflow to interact with external APIs while keeping sensitive data—such as API credentials, request body fields, and response data—confidential. + +## The problem it solves + +Traditional consensus mechanisms require all nodes to see and agree on the same data. While this provides strong reliability and tamper resistance, it creates challenges for use cases with strict privacy requirements: + +- **Regulatory compliance:** Some industries require that sensitive data never be exposed to multiple parties. +- **Credential security:** High-risk API credentials could cause damage if compromised or exposed in node memory. +- **Response privacy:** API responses may contain sensitive fields that should not be visible to the decentralized network. + +Confidential HTTP addresses these challenges by executing requests inside a **secure enclave** and offering optional **response encryption**. + +## How it works + +Confidential HTTP operates differently from the [regular HTTP capability](/cre/capabilities/http): + +1. **Request consensus:** Nodes in the Confidential HTTP DON reach quorum on the request parameters (forwarded by each Workflow DON node). +1. **Secret retrieval:** The Confidential HTTP DON fetches encrypted secrets from the [Vault DON](/cre/guides/workflow/secrets/using-secrets-deployed). +1. **Enclave execution:** Secrets are decrypted and injected into the request inside a secure enclave. The HTTP request executes from the enclave—credentials never exist in accessible memory. +1. **Response:** The response is returned to your workflow. If `EncryptOutput` is enabled, the response body is encrypted before leaving the enclave. + +This approach ensures: + +- **Credential isolation:** Secrets are encrypted at rest and in transit, and are decrypted only inside the enclave—never in node memory. +- **Response privacy:** You can optionally encrypt the full response body so that it leaves the enclave encrypted and can be decrypted only in your own backend service. +- **Single execution:** Exactly one API call is made, not one per node. + +## What's kept confidential + +| Component | How it's protected | +| :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Secrets** (API keys, tokens) | Fully confidential. Stored in the Vault DON, decrypted only inside the enclave. | +| **Request body** | Template-based injection: secrets referenced in the request body (e.g., `{{.myApiKey}}`) are resolved inside the enclave, so sensitive values never appear in workflow memory. | +| **Response body** | Optionally encrypted. When `EncryptOutput` is enabled, the full response is [AES-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode) encrypted before leaving the enclave. | + +## Use cases + +### Credential isolation + +A SaaS service fetches user data from an e-commerce provider API. The same credential could also modify user data if misused. Confidential HTTP ensures the credential is decrypted only inside the enclave, never accessible in node memory. + +### Response encryption + +A workflow calls a payment processor API to execute a transaction. The API response includes the transaction ID and success status, but also returns sensitive data like the user's account balance and an internal risk score. With Confidential HTTP and `EncryptOutput` enabled, the full response is encrypted before leaving the enclave—it can only be decrypted using the encryption key, for example in your own backend service. + +### Processing sensitive request data + +A workflow processes card transactions where the request contains card details and the API key provides processor access. Confidential HTTP keeps both the credentials and card details private through template-based injection, returning only the encrypted response to the workflow. + +### Guaranteed single execution + +An API endpoint cannot tolerate duplicate requests (e.g., initiating a payment or creating a unique transaction). + +With the [regular HTTP capability](/cre/capabilities/http), each node in the DON executes the request independently to reach consensus on the response. For non-idempotent operations, [`cacheSettings` mitigates](/cre/guides/workflow/using-http-client/post-request-go#1-understanding-single-execution-with-cachesettings) this by enabling nodes to share cached responses, reducing duplicate calls in most cases. + +Confidential HTTP takes a different approach: by design, only one request is ever made from the enclave after quorum is reached on the request parameters. This provides an **architectural guarantee** of single execution. + +## When to use Confidential HTTP vs. regular HTTP + +### Use Confidential HTTP when: + +- The API response contains sensitive data that should not be visible to the network +- API credentials must never be accessible in node memory (enclave-only access) +- You need exactly one API call with zero tolerance for duplicates +- Regulatory or compliance requirements mandate data confidentiality + +### Use regular HTTP when: + +- **Querying multiple APIs and combining results**: For example, fetching prices from 3 different sources and computing a median. Each node calls all APIs, aggregates locally, then nodes reach consensus on the final value. + +- **Transforming data before consensus**: For example, parsing a complex API response, filtering fields, or performing calculations on the data before nodes agree on the result. + +- **Computing with a secret before the request**: For example, generating an HMAC signature for API authentication — use the [`runInNodeMode` pattern](/cre/guides/workflow/using-http-client/post-request-go#2-the-creruninnodemode-pattern-alternative) to access secrets and perform computations before making the request. + +- **No confidentiality requirements**: The API response doesn't contain sensitive data, and you don't need enclave-level protection for credentials. + +## Key differences from regular HTTP + +| Aspect | Regular HTTP | Confidential HTTP | +| :------------------------ | :------------------------------------ | :----------------------------- | +| **API calls** | One per node (multiple)\* | Exactly one (single) | +| **Consensus target** | Response data | Request parameters | +| **Execution environment** | Each node individually | Secure enclave | +| **Secrets exposure** | Decrypted in Workflow DON node memory | Decrypted only in the enclave | +| **Response handling** | Full response to all nodes | Optionally encrypted (AES-GCM) | +| **Data transformation** | Supported in workflow code | Not yet supported in enclave | + +\*For non-idempotent operations (POST, PUT, PATCH, DELETE), [`cacheSettings`](/cre/guides/workflow/using-http-client/post-request#1-understanding-single-execution-with-cachesettings) enables nodes to share cached responses, reducing multiple calls to a single execution in most cases. + +<Aside type="note" title="Confidential Compute"> + Confidential HTTP currently does not support complex data transformations within the enclave. A future **Confidential + Compute** capability will enable processing logic inside the enclave. +</Aside> + +## Learn more + +- **[Confidential API Interactions Guide](/cre/guides/workflow/using-confidential-http-client)**: Learn how to use the SDK to invoke the Confidential HTTP capability. +- **[Confidential HTTP Client SDK Reference](/cre/reference/sdk/confidential-http-client)**: See the detailed API reference for the `confidentialhttp.Client`. diff --git a/src/content/cre/capabilities/confidential-http-ts.mdx b/src/content/cre/capabilities/confidential-http-ts.mdx new file mode 100644 index 00000000000..5a58ad9b1f8 --- /dev/null +++ b/src/content/cre/capabilities/confidential-http-ts.mdx @@ -0,0 +1,117 @@ +--- +section: cre +title: "The Confidential HTTP Capability (Experimental)" +date: Last Modified +sdkLang: "ts" +pageId: "confidential-http" +metadata: + description: "CRE Confidential HTTP capability: make privacy-preserving API calls with enclave execution, secret injection, and optional response encryption." + datePublished: "2026-02-06" + lastModified: "2026-02-06" +--- + +import { Aside } from "@components" + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The **Confidential HTTP** capability is a privacy-preserving HTTP service powered by the Chainlink Privacy Standard. It enables your workflow to interact with external APIs while keeping sensitive data—such as API credentials, request body fields, and response data—confidential. + +## The problem it solves + +Traditional consensus mechanisms require all nodes to see and agree on the same data. While this provides strong reliability and tamper resistance, it creates challenges for use cases with strict privacy requirements: + +- **Regulatory compliance:** Some industries require that sensitive data never be exposed to multiple parties. +- **Credential security:** High-risk API credentials could cause damage if compromised or exposed in node memory. +- **Response privacy:** API responses may contain sensitive fields that should not be visible to the decentralized network. + +Confidential HTTP addresses these challenges by executing requests inside a **secure enclave** and offering optional **response encryption**. + +## How it works + +Confidential HTTP operates differently from the [regular HTTP capability](/cre/capabilities/http): + +1. **Request consensus:** Nodes in the Confidential HTTP DON reach quorum on the request parameters (forwarded by each Workflow DON node). +1. **Secret retrieval:** The Confidential HTTP DON fetches encrypted secrets from the [Vault DON](/cre/guides/workflow/secrets/using-secrets-deployed). +1. **Enclave execution:** Secrets are decrypted and injected into the request inside a secure enclave. The HTTP request executes from the enclave—credentials never exist in accessible memory. +1. **Response:** The response is returned to your workflow. If `EncryptOutput` is enabled, the response body is encrypted before leaving the enclave. + +This approach ensures: + +- **Credential isolation:** Secrets are encrypted at rest and in transit, and are decrypted only inside the enclave—never in node memory. +- **Response privacy:** You can optionally encrypt the full response body so that it leaves the enclave encrypted and can be decrypted only in your own backend service. +- **Single execution:** Exactly one API call is made, not one per node. + +## What's kept confidential + +| Component | How it's protected | +| :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Secrets** (API keys, tokens) | Fully confidential. Stored in the Vault DON, decrypted only inside the enclave. | +| **Request body** | Template-based injection: secrets referenced in the request body (e.g., `{{.myApiKey}}`) are resolved inside the enclave, so sensitive values never appear in workflow memory. | +| **Response body** | Optionally encrypted. When `EncryptOutput` is enabled, the full response is [AES-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode) encrypted before leaving the enclave. | + +## Use cases + +### Credential isolation + +A SaaS service fetches user data from an e-commerce provider API. The same credential could also modify user data if misused. Confidential HTTP ensures the credential is decrypted only inside the enclave, never accessible in node memory. + +### Response encryption + +A workflow calls a payment processor API to execute a transaction. The API response includes the transaction ID and success status, but also returns sensitive data like the user's account balance and an internal risk score. With Confidential HTTP and `EncryptOutput` enabled, the full response is encrypted before leaving the enclave—it can only be decrypted using the encryption key, for example in your own backend service. + +### Processing sensitive request data + +A workflow processes card transactions where the request contains card details and the API key provides processor access. Confidential HTTP keeps both the credentials and card details private through template-based injection, returning only the encrypted response to the workflow. + +### Guaranteed single execution + +An API endpoint cannot tolerate duplicate requests (e.g., initiating a payment or creating a unique transaction). + +With the [regular HTTP capability](/cre/capabilities/http), each node in the DON executes the request independently to reach consensus on the response. For non-idempotent operations, [`cacheSettings` mitigates](/cre/guides/workflow/using-http-client/post-request-ts#1-understanding-single-execution-with-cachesettings) this by enabling nodes to share cached responses, reducing duplicate calls in most cases. + +Confidential HTTP takes a different approach: by design, only one request is ever made from the enclave after quorum is reached on the request parameters. This provides an **architectural guarantee** of single execution. + +## When to use Confidential HTTP vs. regular HTTP + +### Use Confidential HTTP when: + +- The API response contains sensitive data that should not be visible to the network +- API credentials must never be accessible in node memory (enclave-only access) +- You need exactly one API call with zero tolerance for duplicates +- Regulatory or compliance requirements mandate data confidentiality + +### Use regular HTTP when: + +- **Querying multiple APIs and combining results**: For example, fetching prices from 3 different sources and computing a median. Each node calls all APIs, aggregates locally, then nodes reach consensus on the final value. + +- **Transforming data before consensus**: For example, parsing a complex API response, filtering fields, or performing calculations on the data before nodes agree on the result. + +- **Computing with a secret before the request**: For example, generating an HMAC signature for API authentication — use the [`runInNodeMode` pattern](/cre/guides/workflow/using-http-client/post-request-ts#2-the-low-level-runinnodemode-pattern) to access secrets and perform computations before making the request. + +- **No confidentiality requirements**: The API response doesn't contain sensitive data, and you don't need enclave-level protection for credentials. + +## Key differences from regular HTTP + +| Aspect | Regular HTTP | Confidential HTTP | +| :------------------------ | :------------------------------------ | :----------------------------- | +| **API calls** | One per node (multiple)\* | Exactly one (single) | +| **Consensus target** | Response data | Request parameters | +| **Execution environment** | Each node individually | Secure enclave | +| **Secrets exposure** | Decrypted in Workflow DON node memory | Decrypted only in the enclave | +| **Response handling** | Full response to all nodes | Optionally encrypted (AES-GCM) | +| **Data transformation** | Supported in workflow code | Not yet supported in enclave | + +\*For non-idempotent operations (POST, PUT, PATCH, DELETE), [`cacheSettings`](/cre/guides/workflow/using-http-client/post-request#1-understanding-single-execution-with-cachesettings) enables nodes to share cached responses, reducing multiple calls to a single execution in most cases. + +<Aside type="note" title="Confidential Compute"> + Confidential HTTP currently does not support complex data transformations within the enclave. A future **Confidential + Compute** capability will enable processing logic inside the enclave. +</Aside> + +## Learn more + +- **[Confidential API Interactions Guide](/cre/guides/workflow/using-confidential-http-client)**: Learn how to use the SDK to invoke the Confidential HTTP capability. +- **[Confidential HTTP Client SDK Reference](/cre/reference/sdk/confidential-http-client)**: See the detailed API reference for the `confidentialhttp.Client`. diff --git a/src/content/cre/capabilities/index.mdx b/src/content/cre/capabilities/index.mdx index 9af7b805f2d..d613ee4e3e7 100644 --- a/src/content/cre/capabilities/index.mdx +++ b/src/content/cre/capabilities/index.mdx @@ -30,6 +30,7 @@ This section provides a high-level, conceptual overview of the capabilities curr - **[Triggers](/cre/capabilities/triggers)**: Event sources that start your workflow executions. - **[HTTP](/cre/capabilities/http)**: Fetch and post data from external APIs with decentralized consensus. +- **[Confidential HTTP](/cre/capabilities/confidential-http)** _(Experimental)_: Make privacy-preserving API calls with enclave execution, secret injection, and optional response encryption. - **[EVM Read & Write](/cre/capabilities/evm-read-write)**: Interact with smart contracts on EVM-compatible blockchains with decentralized consensus. -All execution capabilities (HTTP, EVM) automatically use [built-in consensus](/cre/concepts/consensus-computing) to validate results across multiple nodes, ensuring security and reliability. +All execution capabilities (HTTP, Confidential HTTP, EVM) automatically use [built-in consensus](/cre/concepts/consensus-computing) to validate results across multiple nodes, ensuring security and reliability. diff --git a/src/content/cre/code-snippets/index-trigger-callback-example.ts b/src/content/cre/code-snippets/index-trigger-callback-example.ts index 2b87bd4d0d6..4d69dd7f999 100644 --- a/src/content/cre/code-snippets/index-trigger-callback-example.ts +++ b/src/content/cre/code-snippets/index-trigger-callback-example.ts @@ -1,4 +1,4 @@ -cre.handler( +handler( cronTrigger.trigger({ schedule: "0 */10 * * * *" }), // trigger fires every 10 minutes onCronTrigger // your callback function ) diff --git a/src/content/cre/concepts/finality-go.mdx b/src/content/cre/concepts/finality-go.mdx new file mode 100644 index 00000000000..662e0ce9b17 --- /dev/null +++ b/src/content/cre/concepts/finality-go.mdx @@ -0,0 +1,117 @@ +--- +section: cre +title: "Finality and Confidence Levels" +date: Last Modified +sdkLang: "go" +pageId: "concepts-finality" +metadata: + description: "Understand how CRE handles blockchain finality across different chains, including confidence levels, finality tags, and block depth configurations." + datePublished: "2025-12-10" + lastModified: "2025-12-10" +--- + +import { Aside, CopyText } from "@components" + +Finality determines when a blockchain transaction is considered irreversible. Until a block is finalized, it could be reorganized (replaced by a different block if the chain temporarily forks), which means any data you read from it might change. + +Different blockchains achieve finality in different ways and at different speeds. CRE abstracts these differences through **confidence levels**, allowing you to specify your finality requirements without needing to know the underlying chain-specific implementation. + +## Understanding CRE's finality model + +CRE provides three confidence levels for reading blockchain data and monitoring events. These levels work consistently across all supported chains. + +### The three confidence levels + +| Confidence Level | Description | Use Case | +| ---------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| **`LATEST`** | The most recent block. No finality guarantees—the block could still be reorganized. | Non-critical, time-sensitive operations where speed matters more than certainty. | +| **`SAFE`** | A block that is unlikely to be reorganized, but not yet fully finalized. | A balance between speed and security for most operations. | +| **`FINALIZED`** | A block that is considered irreversible. This is the safest option. | Critical operations where you need absolute certainty the data won't change. | + +**Choosing the right level:** + +- **`FINALIZED`** — Use for financial transactions, critical state updates, or when incorrect data could cause significant issues +- **`SAFE`** — Use when you need reasonable confidence without waiting for full finality (good for most monitoring/alerting) +- **`LATEST`** — Use for real-time dashboards or displays where speed matters more than guaranteed accuracy + +### How confidence levels map to chains + +**SAFE and LATEST:** + +CRE uses the chain's native `safe` and `latest` block tags respectively for all supported chains. + +**FINALIZED:** + +When you specify `FINALIZED` in your workflow, CRE automatically maps this to a native finality tag or a block depth threshold depending on the chain. + +| Chain | Finality Method | Block Depth | +| ------------------------------- | ---------------------------- | ----------- | +| Arbitrum One / Arbitrum Sepolia | Native `finalized` tag | — | +| Avalanche / Avalanche Fuji | Native `finalized` tag | — | +| Base / Base Sepolia | Native `finalized` tag | — | +| BNB Chain / BNB Testnet | Native `finalized` tag | — | +| Ethereum / Ethereum Sepolia | Native `finalized` tag | — | +| OP Mainnet / OP Sepolia | Native `finalized` tag | — | +| Polygon / Polygon Amoy | Block depth (500 blocks ago) | 500 | + +## Finality for chain reads + +Chain read operations ([`CallContract`](/cre/reference/sdk/evm-client-go#callcontract), [`BalanceAt`](/cre/reference/sdk/evm-client-go#balanceat), [`FilterLogs`](/cre/reference/sdk/evm-client-go#filterlogs), etc.) support confidence levels and custom block depths. + +### Using confidence levels + +For most read operations, use the standard confidence levels by passing `-2` (latest) or `-3` (finalized) as the `BlockNumber` parameter. If you don't specify a block number, CRE defaults to `LATEST`. + +**Note:** The `SAFE` confidence level is not available for chain reads—only `LATEST` and `FINALIZED` are supported. + +### Custom block depths + +For use cases requiring fixed confirmation thresholds or historical state verification, you can specify **any explicit block number** instead of using the predefined confidence levels. This enables you to: + +- Implement custom finality rules tailored to your risk profile (e.g., "always wait 1,000 blocks") +- Meet regulatory requirements that mandate fixed, auditable confirmation thresholds +- Query historical state at specific past block heights for analysis or verification + +**When to use custom block depths:** + +- **Regulatory compliance** — Your interactions require provable, fixed confirmation thresholds for auditors +- **Changing chain parameters** — The chain's finality definition may change, but your security model must remain constant +- **Historical verification** — You need to verify state at a specific moment + +**Implementation:** + +You can pass any `*big.Int` directly as the `BlockNumber` parameter. The SDK accepts both special values (like `-2` for latest, `-3` for finalized) and positive integers for explicit block heights. See [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read-go#custom-block-depths) for examples. + +## Finality for chain writes + +Chain write operations return a [`WriteReportReply`](/cre/reference/sdk/evm-client-go#evmwritereportreply) when the transaction is included in a block, not when it reaches finality. + +### What a successful response means + +When [`WriteReportReply`](/cre/reference/sdk/evm-client-go#evmwritereportreply) returns with `TxStatus` equal to `SUCCESS`: + +- Your transaction was **included in a block** +- The transaction is **not necessarily finalized** yet + +The reply is returned as soon as the transaction appears in a block, not when the block reaches finality. This is important for time-sensitive workflows, but it means the transaction could still be reorganized. + +### Reorg handling + +If a block containing your transaction is reorganized: + +- CRE's Transaction Manager (TXM) automatically resubmits your transaction +- Gas bumping is applied as needed to ensure the transaction is included +- **Important:** The transaction hash may change during resubmission +- You are not automatically notified if the hash changes + +<Aside type="caution" title="For mission-critical applications"> + If you need absolute certainty that your write transaction reached finality, implement post-write verification by + reading the blockchain state after a custom number of confirmations. Do not rely solely on `WriteReportReply` for + finality confirmation. +</Aside> + +## Finality for event triggers + +EVM Log Triggers must use the three confidence levels (`LATEST`, `SAFE`, or `FINALIZED`). Custom block depths are not supported for triggers. + +By default, triggers use `SAFE` if no confidence level is specified. For details on configuring trigger confidence levels, see [EVM Log Trigger](/cre/reference/sdk/triggers/evm-log-trigger-go#evmfilterlogtriggerrequest). diff --git a/src/content/cre/concepts/finality-ts.mdx b/src/content/cre/concepts/finality-ts.mdx new file mode 100644 index 00000000000..b1f71c0ea63 --- /dev/null +++ b/src/content/cre/concepts/finality-ts.mdx @@ -0,0 +1,117 @@ +--- +section: cre +title: "Finality and Confidence Levels" +date: Last Modified +sdkLang: "ts" +pageId: "concepts-finality" +metadata: + description: "Understand how CRE handles blockchain finality across different chains, including confidence levels, finality tags, and block depth configurations." + datePublished: "2025-12-10" + lastModified: "2025-12-10" +--- + +import { Aside, CopyText } from "@components" + +Finality determines when a blockchain transaction is considered irreversible. Until a block is finalized, it could be reorganized (replaced by a different block if the chain temporarily forks), which means any data you read from it might change. + +Different blockchains achieve finality in different ways and at different speeds. CRE abstracts these differences through **confidence levels**, allowing you to specify your finality requirements without needing to know the underlying chain-specific implementation. + +## Understanding CRE's finality model + +CRE provides three confidence levels for reading blockchain data and monitoring events. These levels work consistently across all supported chains. + +### The three confidence levels + +| Confidence Level | Description | Use Case | +| ---------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| **`LATEST`** | The most recent block. No finality guarantees—the block could still be reorganized. | Non-critical, time-sensitive operations where speed matters more than certainty. | +| **`SAFE`** | A block that is unlikely to be reorganized, but not yet fully finalized. | A balance between speed and security for most operations. | +| **`FINALIZED`** | A block that is considered irreversible. This is the safest option. | Critical operations where you need absolute certainty the data won't change. | + +**Choosing the right level:** + +- **`FINALIZED`** — Use for financial transactions, critical state updates, or when incorrect data could cause significant issues +- **`SAFE`** — Use when you need reasonable confidence without waiting for full finality (good for most monitoring/alerting) +- **`LATEST`** — Use for real-time dashboards or displays where speed matters more than guaranteed accuracy + +### How confidence levels map to chains + +**SAFE and LATEST:** + +CRE uses the chain's native `safe` and `latest` block tags respectively for all supported chains. + +**FINALIZED:** + +When you specify `FINALIZED` in your workflow, CRE automatically maps this to its finality method—whether it uses the native finality tag or block depth (with the number of blocks specified for block depth). + +| Chain | Finality Method | +| ------------------------------- | ------------------------ | +| Arbitrum One / Arbitrum Sepolia | Native `finalized` tag | +| Avalanche / Avalanche Fuji | Native `finalized` tag | +| Base / Base Sepolia | Native `finalized` tag | +| BNB Chain / BNB Testnet | Native `finalized` tag | +| Ethereum / Ethereum Sepolia | Native `finalized` tag | +| OP Mainnet / OP Sepolia | Native `finalized` tag | +| Polygon / Polygon Amoy | Block depth (500 blocks) | + +## Finality for chain reads + +Chain read operations ([`CallContract`](/cre/reference/sdk/evm-client-ts#callcontract), [`BalanceAt`](/cre/reference/sdk/evm-client-ts#balanceat), [`FilterLogs`](/cre/reference/sdk/evm-client-ts#filterlogs), etc.) support confidence levels and custom block depths. + +### Using confidence levels + +For most read operations, use the standard confidence levels by passing [`LATEST_BLOCK_NUMBER`](/cre/reference/sdk/evm-client-ts#latest_block_number) or [`LAST_FINALIZED_BLOCK_NUMBER`](/cre/reference/sdk/evm-client-ts#last_finalized_block_number) as the `blockNumber` parameter. If you don't specify a block number, CRE defaults to `LATEST`. + +**Note:** The `SAFE` confidence level is not available for chain reads—only `LATEST` and `FINALIZED` are supported. + +### Custom block depths + +For use cases requiring fixed confirmation thresholds or historical state verification, you can specify **any explicit block number** instead of using the predefined confidence levels. This enables you to: + +- Implement custom finality rules tailored to your risk profile (e.g., "always wait 1,000 blocks") +- Meet regulatory requirements that mandate fixed, auditable confirmation thresholds +- Query historical state at specific past block heights for analysis or verification + +**When to use custom block depths:** + +- **Regulatory compliance** — Your interactions require provable, fixed confirmation thresholds for auditors +- **Changing chain parameters** — The chain's finality definition may change, but your security model must remain constant +- **Historical verification** — You need to verify state at a specific moment + +**Implementation:** + +Block numbers must be provided as `BigIntJson` objects. See [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths) for the conversion pattern and examples. + +## Finality for chain writes + +Chain write operations return a [`WriteReportReply`](/cre/reference/sdk/evm-client-ts#writereportreply) when the transaction is included in a block, not when it reaches finality. + +### What a successful response means + +When [`WriteReportReply`](/cre/reference/sdk/evm-client-ts#writereportreply) returns with `txStatus` equal to `TX_STATUS_SUCCESS`: + +- Your transaction was **included in a block** +- The transaction is **not necessarily finalized** yet + +The reply is returned as soon as the transaction appears in a block, not when the block reaches finality. This is important for time-sensitive workflows, but it means the transaction could still be reorganized. + +### Reorg handling + +If a block containing your transaction is reorganized: + +- CRE's Transaction Manager (TXM) automatically resubmits your transaction +- Gas bumping is applied as needed to ensure the transaction is included +- **Important:** The transaction hash may change during resubmission +- You are not automatically notified if the hash changes + +<Aside type="caution" title="For mission-critical applications"> + If you need absolute certainty that your write transaction reached finality, implement post-write verification by + reading the blockchain state after a custom number of confirmations. Do not rely solely on `WriteReportReply` for + finality confirmation. +</Aside> + +## Finality for event triggers + +EVM Log Triggers must use the three confidence levels (`LATEST`, `SAFE`, or `FINALIZED`). Custom block depths are not supported for triggers. + +By default, triggers use `SAFE` if no confidence level is specified. For details on configuring trigger confidence levels, see [EVM Log Trigger](/cre/reference/sdk/triggers/evm-log-trigger-ts#configuration). diff --git a/src/content/cre/concepts/non-determinism-go.mdx b/src/content/cre/concepts/non-determinism-go.mdx index 2460cb376b9..76834e2dabb 100644 --- a/src/content/cre/concepts/non-determinism-go.mdx +++ b/src/content/cre/concepts/non-determinism-go.mdx @@ -7,7 +7,7 @@ date: Last Modified metadata: description: "Learn how to avoid non-deterministic behaviors in CRE Go workflows that prevent nodes from reaching consensus." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside } from "@components" @@ -71,7 +71,7 @@ Never use Go's `time` package functions in DON mode. Nodes have different system **The problem:** Using `time.Now()` returns different values on each node. -**The solution:** Use `runtime.Now()` from the CRE SDK, which provides DON Time—a consensus-derived timestamp that all nodes agree on. See [Time in CRE](/cre/concepts/time-in-cre) for details. +**The solution:** Use `runtime.Now()` from the CRE SDK, which provides DON Time—a consensus-derived timestamp that all nodes agree on. See [Time in CRE](/cre/guides/workflow/time-in-workflows-go) for details. ## 5. Random number generation @@ -79,7 +79,7 @@ Go's built-in `rand` package generates different random sequences on each node, **The problem:** Each node generates different random values, breaking consensus. -**The solution:** Use `runtime.Rand()` from the CRE SDK, which provides consensus-safe random number generation. All nodes generate the same sequence of random values, enabling consensus. See [Random in CRE](/cre/concepts/random-in-cre) for details. +**The solution:** Use `runtime.Rand()` from the CRE SDK, which provides consensus-safe random number generation. All nodes generate the same sequence of random values, enabling consensus. See [Using Randomness in Workflows](/cre/guides/workflow/using-randomness) for details. ## 6. Working with LLMs @@ -113,6 +113,6 @@ Large Language Models (LLMs) generate different responses for the same prompt, e ## Related concepts -- **[Time in CRE](/cre/concepts/time-in-cre)**: Learn about DON Time and why `runtime.Now()` is required -- **[Random in CRE](/cre/concepts/random-in-cre)**: Understand consensus-safe random number generation +- **[Time in CRE](/cre/guides/workflow/time-in-workflows-go)**: Learn about DON Time and why `runtime.Now()` is required +- **[Using Randomness in Workflows](/cre/guides/workflow/using-randomness)**: Understand consensus-safe random number generation - **[Consensus Computing](/cre/concepts/consensus-computing)**: Deep dive into how nodes reach agreement diff --git a/src/content/cre/concepts/non-determinism-ts.mdx b/src/content/cre/concepts/non-determinism-ts.mdx index f07046e911a..ce1b70975b9 100644 --- a/src/content/cre/concepts/non-determinism-ts.mdx +++ b/src/content/cre/concepts/non-determinism-ts.mdx @@ -7,7 +7,7 @@ date: Last Modified metadata: description: "Learn how to avoid non-deterministic behaviors in CRE TypeScript workflows that prevent nodes from reaching consensus." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside } from "@components" @@ -45,7 +45,7 @@ const obj = { b: 2, a: 1 } // Order may vary across runtimes or serialization for (const key in obj) { - console.log(key) // Could be "b", "a" or "a", "b" + // key could be "b", "a" or "a", "b" — non-deterministic! } ``` @@ -56,7 +56,7 @@ const obj = { b: 2, a: 1 } // Preserves insertion order for (const key of Object.keys(obj)) { - console.log(key, obj[key]) // "b", "a" (insertion order) + // key order: "b", "a" (insertion order) } ``` @@ -67,7 +67,7 @@ const obj = { b: 2, a: 1 } // Guaranteed alphabetical order for (const key of Object.keys(obj).sort()) { - console.log(key, obj[key]) // "a", "b" (alphabetically sorted) + // key order: "a", "b" (alphabetically sorted) } ``` @@ -83,7 +83,7 @@ map.set("b", 2) map.set("a", 1) for (const [key, value] of map) { - console.log(key, value) // Always "b", then "a" + // Order: ["b", 2], then ["a", 1] — guaranteed } ``` @@ -93,7 +93,7 @@ for (const [key, value] of map) { const set = new Set(["b", "a"]) for (const value of set) { - console.log(value) // Always "b", then "a" + // Order: "b", then "a" — guaranteed } ``` @@ -125,11 +125,11 @@ const firstSuccess = await Promise.any([fetchFromAPI1(), fetchFromAPI2()]) **Good: Deterministic order with `.result()`** ```typescript -import { cre, type Runtime, type NodeRuntime, consensusMedianAggregation } from "@chainlink/cre-sdk" +import { HTTPClient, type Runtime, type NodeRuntime, consensusMedianAggregation } from "@chainlink/cre-sdk" // Fetch from API 1, then API 2, in a fixed order const fetchPrice = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // Try first API const response1 = httpClient @@ -188,7 +188,7 @@ const now = runtime.now() // Same timestamp across all nodes runtime.log(`Current time: ${now.toISOString()}`) ``` -The `runtime.now()` method returns a `Date` object representing DON Time—a consensus-derived timestamp that all nodes agree on. See [Time in CRE](/cre/concepts/time-in-cre) for more details. +The `runtime.now()` method returns a `Date` object representing DON Time—a consensus-derived timestamp that all nodes agree on. See [Time in CRE](/cre/guides/workflow/time-in-workflows-ts) for more details. ## 4. Working with LLMs @@ -217,6 +217,6 @@ Large Language Models (LLMs) generate different responses for the same prompt, e ## Related concepts -- **[Time in CRE](/cre/concepts/time-in-cre)**: Learn about DON Time and why `runtime.now()` is required +- **[Time in CRE](/cre/guides/workflow/time-in-workflows-ts)**: Learn about DON Time and why `runtime.now()` is required - **[Consensus Computing](/cre/concepts/consensus-computing)**: Deep dive into how nodes reach agreement - **[Core SDK Reference](/cre/reference/sdk/core-ts)**: Details on `Runtime`, `NodeRuntime`, and the `.result()` pattern diff --git a/src/content/cre/concepts/typescript-wasm-runtime.mdx b/src/content/cre/concepts/typescript-wasm-runtime.mdx index 61be85dfe05..26a4c671eb0 100644 --- a/src/content/cre/concepts/typescript-wasm-runtime.mdx +++ b/src/content/cre/concepts/typescript-wasm-runtime.mdx @@ -34,6 +34,11 @@ Javy uses [QuickJS](https://bellard.org/quickjs), a lightweight JavaScript engin Not all Node.js built-in modules are available. For example, `node:crypto` is not supported. Before using third-party NPM packages, verify they don't rely on unsupported Node.js APIs. +{/* prettier-ignore */} +<Aside type="tip" title="Cryptography libraries"> + If you need cryptographic functions, <a href="https://paulmillr.com/noble/" target="_blank" rel="noopener noreferrer">Noble</a> is a popular JavaScript cryptography library with minimal dependencies that works well with QuickJS. Always verify any third-party library in simulation before deploying. +</Aside> + <Aside type="note" title="Note on async/await with SDK capabilities"> While JavaScript `Promise` and `async/await` are supported by QuickJS, **SDK capabilities do not use them**. The CRE TypeScript SDK uses a custom `.result()` pattern instead. See the [Core SDK diff --git a/src/content/cre/getting-started/before-you-build-go.mdx b/src/content/cre/getting-started/before-you-build-go.mdx new file mode 100644 index 00000000000..861d35457d9 --- /dev/null +++ b/src/content/cre/getting-started/before-you-build-go.mdx @@ -0,0 +1,92 @@ +--- +section: cre +title: "Before You Build" +date: Last Modified +pageId: "getting-started-before-you-build" +sdkLang: "go" +metadata: + description: "Essential tips before building your own CRE workflows: working with time, randomness, and next steps for production deployment." + datePublished: "2026-02-04" + lastModified: "2026-02-04" +--- + +import { Aside } from "@components" + +You've completed the Getting Started guide and built a workflow that fetches offchain data, reads from a smart contract, performs calculations, and writes results onchain. You're ready to build your own workflows. + +Before you do, take two minutes to understand how CRE differs from typical development. These tips will save you debugging time. + +## Working with time + +If your workflow uses timestamps (e.g., for API authentication or time-based queries), use `runtime.Now()` instead of `time.Now()`. This ensures all nodes in the DON use the same timestamp and can reach consensus. + +{/* prettier-ignore */} +<Aside type="tip" title="Learn more"> + See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details on DON time and best practices. +</Aside> + +## Working with randomness + +If your workflow needs random values (e.g., selecting a winner or generating nonces), use `runtime.Rand()` instead of Go's `rand` package. This ensures all nodes generate the same random sequence and can reach consensus. + +{/* prettier-ignore */} +<Aside type="tip" title="Learn more"> + See [Using Randomness in Workflows](/cre/guides/workflow/using-randomness) for usage examples and best practices. +</Aside> + +{/* prettier-ignore */} +<Aside type="note" title="Going deeper"> + Time and randomness are the most common cases. For a complete guide to non-determinism (map iteration, JSON serialization, channel selection, and more), see [Avoiding Non-Determinism in Workflows](/cre/concepts/non-determinism). +</Aside> + +## What's next? + +Here are resources to help you go from simulation to production. + +### Learn from examples + +- **[Run the Custom Data Feed Demo](/cre/templates/running-demo-workflow)** — A starter template you can run locally and customize +- **[Browse all Templates](/cre/templates)** — Building blocks for specific patterns (secrets, HTTP auth, streams) and starter templates +- **[AI-Powered Prediction Market](/cre/demos/prediction-market)** — Full end-to-end demo integrating CRE with Gemini AI and Firebase + +### Deploy to production + +{/* prettier-ignore */} +<Aside type="note" title="Deployment access required"> + Deploying requires Early Access approval. <a href="https://cre.chain.link/request-access" target="_blank" rel="noopener noreferrer">Request access here</a>. While you wait, continue building and simulating workflows. +</Aside> + +1. **[Link a Wallet Key](/cre/organization/linking-keys)** — Connect your wallet to your organization +1. **[Deploy Your Workflow](/cre/guides/operations/deploying-workflows)** — Push your workflow live +1. **[Monitor Your Workflow](/cre/guides/operations/monitoring-workflows)** — Watch it execute and debug issues + +### Explore different triggers + +You used a Cron trigger. Most production workflows react to events: + +- **[HTTP Trigger](/cre/guides/workflow/using-triggers/http-trigger/overview)** — Trigger via API calls +- **[EVM Log Trigger](/cre/guides/workflow/using-triggers/evm-log-trigger)** — React to onchain events + +### Add secrets + +Real workflows need API keys and sensitive data: + +- **[Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation)** — Local development +- **[Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed)** — Store secrets in the Vault DON for production +- **[Managing Secrets with 1Password](/cre/guides/workflow/secrets/managing-secrets-1password)** — Best practice: inject secrets at runtime + +### Build your own consumer contract + +- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)** — Create contracts that receive CRE data + +## Reference + +Dive deeper into concepts from this guide: + +| Topic | Resources | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Workflow structure** | [Core SDK](/cre/reference/sdk/core), [Triggers Overview](/cre/guides/workflow/using-triggers/overview) | +| **HTTP & offchain data** | [API Interactions](/cre/guides/workflow/using-http-client), [Consensus & Aggregation](/cre/reference/sdk/consensus) | +| **EVM interactions** | [EVM Client Overview](/cre/guides/workflow/using-evm-client/overview), [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read), [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview) | +| **Configuration** | [Project Configuration](/cre/reference/project-configuration), [Secrets Guide](/cre/guides/workflow/secrets) | +| **All capabilities** | [Capabilities Overview](/cre/capabilities) | diff --git a/src/content/cre/getting-started/before-you-build-ts.mdx b/src/content/cre/getting-started/before-you-build-ts.mdx new file mode 100644 index 00000000000..aab337683b2 --- /dev/null +++ b/src/content/cre/getting-started/before-you-build-ts.mdx @@ -0,0 +1,120 @@ +--- +section: cre +title: "Before You Build" +date: Last Modified +pageId: "getting-started-before-you-build" +sdkLang: "ts" +metadata: + description: "Essential tips before building your own CRE workflows: library compatibility, Solidity integers, working with time, and next steps for production deployment." + datePublished: "2026-02-04" + lastModified: "2026-02-04" +--- + +import { Aside } from "@components" + +You've completed the Getting Started guide and built a workflow that fetches offchain data, reads from a smart contract, performs calculations, and writes results onchain. You're ready to build your own workflows. + +Before you do, take two minutes to understand how CRE differs from typical development. These tips will save you debugging time. + +## Library compatibility + +Your TypeScript code compiles to WebAssembly and runs in a QuickJS environment, **not Node.js**. Some NPM packages won't work if they rely on Node.js-specific APIs like `node:crypto` or `node:fs`. + +**Before using a third-party package:** + +1. Check if it relies on Node.js built-in modules +1. Test with `cre workflow simulate` — simulation uses the same WASM environment as production, so compatibility issues surface immediately + +{/* prettier-ignore */} +<Aside type="tip" title="Cryptography libraries"> + If you need cryptographic functions, <a href="https://paulmillr.com/noble/" target="_blank" rel="noopener noreferrer">Noble</a> is a popular JavaScript cryptography library that works well with QuickJS. Always verify any third-party library in simulation before deploying. +</Aside> + +{/* prettier-ignore */} +<Aside type="tip" title="Learn more"> + See [TypeScript Runtime Environment](/cre/concepts/typescript-wasm-runtime) for details on QuickJS compatibility and how to [verify library support](/cre/concepts/typescript-wasm-runtime#checking-library-compatibility). +</Aside> + +## Working with Solidity integers + +When sending values to smart contracts, always use `bigint` (with the `n` suffix) in your workflow code. JavaScript `number` loses precision for large values, causing **silent precision loss**. + +```typescript +// WRONG - silent precision loss +const amount = 10000000000000001 // 10 quadrillion + 1 +// Silently becomes 10000000000000000 (the +1 vanishes) + +// CORRECT - use bigint +const amount = 10000000000000001n // Stays exactly 10000000000000001 +``` + +{/* prettier-ignore */} +<Aside type="tip" title="Learn more"> + See [Writing Data Onchain](/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain#step-2-abi-encode-your-value) for the complete Solidity-to-TypeScript type mapping. +</Aside> + +## Working with time + +If your workflow uses timestamps (e.g., for API authentication or time-based queries), use `runtime.now()` instead of `Date.now()`. This ensures all nodes in the DON use the same timestamp and can reach consensus. + +{/* prettier-ignore */} +<Aside type="tip" title="Learn more"> + See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details on DON time and best practices. +</Aside> + +{/* prettier-ignore */} +<Aside type="note" title="Going deeper"> + These are the most common cases. For a complete guide to non-determinism (object iteration, Promise handling, and more), see [Avoiding Non-Determinism in Workflows](/cre/concepts/non-determinism). +</Aside> + +## What's next? + +Here are resources to help you go from simulation to production. + +### Learn from examples + +- **[Run the Custom Data Feed Demo](/cre/templates/running-demo-workflow)** — A starter template you can run locally and customize +- **[Browse all Templates](/cre/templates)** — Building blocks for specific patterns (secrets, HTTP auth, streams) and starter templates +- **[AI-Powered Prediction Market](/cre/demos/prediction-market)** — Full end-to-end demo integrating CRE with Gemini AI and Firebase + +### Deploy to production + +{/* prettier-ignore */} +<Aside type="note" title="Deployment access required"> + Deploying requires Early Access approval. <a href="https://cre.chain.link/request-access" target="_blank" rel="noopener noreferrer">Request access here</a>. While you wait, continue building and simulating workflows. +</Aside> + +1. **[Link a Wallet Key](/cre/organization/linking-keys)** — Connect your wallet to your organization +1. **[Deploy Your Workflow](/cre/guides/operations/deploying-workflows)** — Push your workflow live +1. **[Monitor Your Workflow](/cre/guides/operations/monitoring-workflows)** — Watch it execute and debug issues + +### Explore different triggers + +You used a Cron trigger. Most production workflows react to events: + +- **[HTTP Trigger](/cre/guides/workflow/using-triggers/http-trigger/overview)** — Trigger via API calls +- **[EVM Log Trigger](/cre/guides/workflow/using-triggers/evm-log-trigger)** — React to onchain events + +### Add secrets + +Real workflows need API keys and sensitive data: + +- **[Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation)** — Local development +- **[Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed)** — Store secrets in the Vault DON for production +- **[Managing Secrets with 1Password](/cre/guides/workflow/secrets/managing-secrets-1password)** — Best practice: inject secrets at runtime + +### Build your own consumer contract + +- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)** — Create contracts that receive CRE data + +## Reference + +Dive deeper into concepts from this guide: + +| Topic | Resources | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Workflow structure** | [Core SDK](/cre/reference/sdk/core), [Triggers Overview](/cre/guides/workflow/using-triggers/overview) | +| **HTTP & offchain data** | [API Interactions](/cre/guides/workflow/using-http-client), [Consensus & Aggregation](/cre/reference/sdk/consensus) | +| **EVM interactions** | [EVM Client Overview](/cre/guides/workflow/using-evm-client/overview), [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read), [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview) | +| **Configuration** | [Project Configuration](/cre/reference/project-configuration), [Secrets Guide](/cre/guides/workflow/secrets) | +| **All capabilities** | [Capabilities Overview](/cre/capabilities) | diff --git a/src/content/cre/getting-started/cli-installation/macos-linux.mdx b/src/content/cre/getting-started/cli-installation/macos-linux.mdx index 2c618ed3736..0818e7fca63 100644 --- a/src/content/cre/getting-started/cli-installation/macos-linux.mdx +++ b/src/content/cre/getting-started/cli-installation/macos-linux.mdx @@ -5,13 +5,13 @@ title: "Installing the CRE CLI on macOS and Linux" metadata: description: "Install the CRE CLI on macOS or Linux: choose automatic script or manual setup, verify integrity, and get ready to build workflows." datePublished: "2025-11-04" - lastModified: "2025-11-20" + lastModified: "2026-02-10" --- import { Aside, CopyText, PageTabs } from "@components" import { DownloadButton } from "~/components/DownloadButton.tsx" -This page explains how to install the CRE CLI on macOS or Linux. The recommended version at the time of writing is **v1.0.2**. +This page explains how to install the CRE CLI on macOS or Linux. The recommended version at the time of writing is **v1.0.10**. <PageTabs pages={[ @@ -49,7 +49,7 @@ Choose your installation method: The easiest way to install the CRE CLI is using the installation script: ```bash -curl -sSL https://cre.chain.link/install.sh | sh +curl -sSL https://cre.chain.link/install.sh | bash ``` This script will: @@ -57,7 +57,7 @@ This script will: - Detect your operating system and architecture automatically - Download the correct binary for your system - Verify the binary's integrity -- Install it to `/usr/local/bin` (or prompt you for a custom location) +- Install it to `$HOME/.cre` - Make the binary executable After the script completes, verify the installation: @@ -66,11 +66,11 @@ After the script completes, verify the installation: cre version ``` -**Expected output:** `cre version v1.0.2` +**Expected output:** `cre version v1.0.10` <Aside type="note" title="macOS Gatekeeper"> If you see warnings about "unrecognized developer/source" on macOS, run:{" "} - <CopyText text="xattr -c /usr/local/bin/cre" code /> + <CopyText text="xattr -c $HOME/.cre/cre" code /> </Aside> ### Manual installation @@ -89,9 +89,15 @@ The file you need depends on your operating system and CPU architecture: - On **macOS** (darwin), run <CopyText text="uname -m" code />: - `arm64` (Apple Silicon) → Download `cre_darwin_arm64.zip` - `x86_64` (Intel) → Download `cre_darwin_amd64.zip` -- On **Linux**, run <CopyText text="uname -m" code />: - - `aarch64` (ARM) → Download `cre_linux_arm64.tar.gz` - - `x86_64` (AMD/Intel) → Download `cre_linux_amd64.tar.gz` +- On **Linux**, the binary depends on both your architecture and OS version. First, run <CopyText text="uname -m" code /> to check your architecture, then <CopyText text="lsb_release -rs" code /> to check your Ubuntu version: + - **Ubuntu 22.04 or older**: + - `x86_64` (AMD/Intel) → Download `cre_linux_amd64_ldd2-35.tar.gz` + - `aarch64` (ARM) → Download `cre_linux_arm64_ldd2-35.tar.gz` + - **Ubuntu 24.04 or newer**: + - `x86_64` (AMD/Intel) → Download `cre_linux_amd64.tar.gz` + - `aarch64` (ARM) → Download `cre_linux_arm64.tar.gz` + +**Note:** The `ldd2-35` binaries are compiled for older glibc versions (2.35 and below). If you're using a non-Ubuntu Linux distribution, check your glibc version with <CopyText text="ldd --version" code /> and use the `ldd2-35` binary if your version is 2.35 or lower. </Aside> @@ -111,16 +117,21 @@ shasum -a 256 cre_darwin_arm64.zip **Verify against official checksums** -Compare the output with the official checksum below: +Compare the output with the official checksum from the [CRE CLI releases page](https://github.com/smartcontractkit/cre-cli/releases): + +1. Go to https://github.com/smartcontractkit/cre-cli/releases +1. Find the release version you downloaded (e.g., v1.0.10) +1. Under the **Assets** section, locate your downloaded file +1. Compare the SHA-256 checksum shown next to the file with your command output + +**Example:** For `cre_darwin_arm64.zip` in release v1.0.10, you'll see something like: -| <div style="width: 200px;">File</div> | SHA-256 Checksum | -| ------------------------------------- | ----------------------------------------------------------------------------------------- | -| `cre_darwin_amd64.zip` | <CopyText text="482e53d3a5f8471034d30c935196d2dca2ab09a5fe1ab2083ad336172565291b" code /> | -| `cre_darwin_arm64.zip` | <CopyText text="92b0409801dd4e44f90a85331615f3e4b8cf1fe9f90a8eab3ad8bb3458b4b6cf" code /> | -| `cre_linux_amd64.tar.gz` | <CopyText text="d3a8b9b999b4b8bf73b2235d27386acf4efbc8f05d86d9e6066abda23ee9ce9b" code /> | -| `cre_linux_arm64.tar.gz` | <CopyText text="f52d618727ccc8fb6ab4b1f9418b09424c8505428131a49c01bb33ca2bc86fe3" code /> | +``` +cre_darwin_arm64.zip +sha256:1359415a1f1baee7643107b82b3a0589a3627aef71018644e5c488960a97e955 +``` -If the checksum doesn't match, do not proceed with installation. Contact your Chainlink point of contact for assistance. +If the checksums match, the file is authentic and safe to install. If they don't match, do not proceed with installation and contact the Chainlink team for assistance. #### 2. Extract and install @@ -143,7 +154,7 @@ If the checksum doesn't match, do not proceed with installation. Contact your Ch 1. **Rename the extracted binary to `cre`** ```bash - mv cre_v1.0.2_darwin_arm64 cre + mv cre_v1.0.10_darwin_arm64 cre ``` 1. **Make it executable**: @@ -216,13 +227,13 @@ cre version **Expected output:** -You should see version information: `cre version v1.0.2`. +You should see version information: `cre version v1.0.10`. **If it doesn't work:** - Make sure you opened a **new terminal window** after making PATH changes -- Check the binary location: `which cre` should return `/usr/local/bin/cre` (or your custom path) -- Check that the binary has execute permissions: `ls -la /usr/local/bin/cre` +- Check the binary location: `which cre` should return the path to your installation +- Check that the binary has execute permissions: `ls -la $(which cre)` - Verify your PATH includes the correct directory: `echo $PATH` #### 5. Confirm your PATH (troubleshooting) diff --git a/src/content/cre/getting-started/cli-installation/windows.mdx b/src/content/cre/getting-started/cli-installation/windows.mdx index 69b24a01b66..26230ee64ef 100644 --- a/src/content/cre/getting-started/cli-installation/windows.mdx +++ b/src/content/cre/getting-started/cli-installation/windows.mdx @@ -5,13 +5,13 @@ title: "Installing the CRE CLI on Windows" metadata: description: "Install the CRE CLI on Windows: use PowerShell for quick setup or manual installation, verify integrity, and start building workflows." datePublished: "2025-11-04" - lastModified: "2025-11-20" + lastModified: "2026-02-10" --- import { Aside, CopyText, PageTabs } from "@components" import { DownloadButton } from "~/components/DownloadButton.tsx" -This page explains how to install the Chainlink Developer Platform CLI (also referred to as the CRE CLI) on Windows. The recommended version at the time of writing is **v1.0.2**. +This page explains how to install the Chainlink Developer Platform CLI (also referred to as the CRE CLI) on Windows. The recommended version at the time of writing is **v1.0.10**. <PageTabs pages={[ @@ -56,7 +56,7 @@ This script will: - Download the correct binary for Windows - Verify the binary's integrity -- Install it to a location in your PATH +- Install it to `$env:LOCALAPPDATA\Programs\cre` - Make the binary executable After the script completes, **open a new PowerShell window** and verify the installation: @@ -65,7 +65,7 @@ After the script completes, **open a new PowerShell window** and verify the inst cre version ``` -**Expected output:** `cre version v1.0.2` +**Expected output:** `cre version v1.0.10` ### Manual installation @@ -93,20 +93,28 @@ Get-FileHash cre_windows_amd64.zip -Algorithm SHA256 **Verify against the official checksum** -Compare the `Hash` value in the output with the official checksum below: +Compare the `Hash` value in the output with the official checksum from the [CRE CLI releases page](https://github.com/smartcontractkit/cre-cli/releases): -| <div style="width: 200px;">File</div> | SHA-256 Checksum | -| ------------------------------------- | ----------------------------------------------------------------------------------------- | -| `cre_windows_amd64.zip` | <CopyText text="60fe65b74619c4164c0a9d6442611bf8537a04a6daf1ed3ecefc608cbbffdb01" code /> | +1. Go to https://github.com/smartcontractkit/cre-cli/releases +2. Find the release version you downloaded (e.g., v1.0.10) +3. Under the **Assets** section, locate `cre_windows_amd64.zip` +4. Compare the SHA-256 checksum shown next to the file with the `Hash` value from your PowerShell output -If the checksum doesn't match, do not proceed with installation. Contact your Chainlink point of contact for assistance. +**Example:** For `cre_windows_amd64.zip` in release v1.0.10, you'll see something like: + +``` +cre_windows_amd64.zip +sha256:372d16566479ff6bbfe9eb1d5cebe0e1e2a3c67062c6f0439fc96c735ddeaa18 +``` + +If the checksums match, the file is authentic and safe to install. If they don't match, do not proceed with installation and contact the Chainlink team for assistance. #### 2. Extract and install 1. Navigate to the directory where you downloaded the archive. 1. Right-click the `.zip` file and select **Extract All...**. 1. Choose a permanent location for the extracted folder (e.g., `C:\Program Files\cre-cli`). -1. Inside the extracted folder, rename the file `cre_v1.0.2_windows_amd64.exe` to `cre.exe`. +1. Inside the extracted folder, rename the file `cre_v1.0.10_windows_amd64.exe` to `cre.exe`. #### 3. Add the CLI to your PATH @@ -131,7 +139,7 @@ Open a new **PowerShell** or **Command Prompt** window and run: cre version ``` -You should see version information: `cre version v1.0.2`. +You should see version information: `cre version v1.0.10`. ## Next steps diff --git a/src/content/cre/getting-started/conclusion.mdx b/src/content/cre/getting-started/conclusion.mdx deleted file mode 100644 index 63eeccd9441..00000000000 --- a/src/content/cre/getting-started/conclusion.mdx +++ /dev/null @@ -1,115 +0,0 @@ ---- -section: cre -title: "Conclusion & Next Steps" -date: Last Modified -metadata: - description: "Getting started conclusion: next steps after completing the tutorial - deploy to production, explore triggers, and build custom contracts." - datePublished: "2025-11-04" - lastModified: "2025-11-04" ---- - -import { Aside } from "@components" - -You've built a complete, end-to-end CRE workflow from scratch. - -You started with an empty project and progressively built a workflow that: - -- Fetches data from an offchain API with consensus -- Reads values from a smart contract -- Performs calculations combining onchain and offchain data -- Writes results back to the blockchain - -**This is no small achievement.** You've mastered the core pattern that powers most CRE workflows: the trigger-and-callback model with capabilities for HTTP, EVM, and consensus. - -## What's next? - -Now that you have a working workflow, here's your natural progression from simulation to production and beyond. - -### 1. See a complete example - -Ready to see all these concepts in a more complex, real-world scenario? - -- **[Run the Custom Data Feed Demo](/cre/templates/running-demo-workflow)** - Explore an advanced template that combines multiple capabilities - -**Why this matters:** Templates show production-ready patterns. - -### 2. Deploy your Calculator workflow to Production - -You've simulated your workflow locally. **The logical next step is to deploy it to the CRE production environment** so it runs across a Decentralized Oracle Network (DON). - -{/* prettier-ignore */} -<Aside type="note" title="Deployment access required"> - - Deploying workflows requires Early Access approval. If you don't have deployment access yet, <a href="https://cre.chain.link/request-access" target="_blank" rel="noopener noreferrer">request it here</a>. - - **While you wait:** Continue building and simulating workflows using [`cre workflow simulate`](/cre/guides/operations/simulating-workflows). -</Aside> - -**Follow this deployment sequence:** - -1. **[Link a Wallet Key](/cre/organization/linking-keys)** - Connect your wallet address to your organization (required before deployment) -1. **[Deploy Your Workflow](/cre/guides/operations/deploying-workflows)** - Push your calculator workflow live -1. **[Monitor Your Workflow](/cre/guides/operations/monitoring-workflows)** - Watch it execute in production and debug any issues - -**Why this matters:** Deploying moves your workflow from local simulation to production execution across a DON. - -### 3. Explore different triggers - -You used a **Cron trigger** (time-based). **Most production workflows react to real-world events.** - -**Try these next:** - -- **[HTTP Trigger](/cre/guides/workflow/using-triggers/http-trigger/overview)** - Let external systems trigger your workflow via API calls -- **[EVM Log Trigger](/cre/guides/workflow/using-triggers/evm-log-trigger)** - React to onchain events (e.g., token transfers, contract events) - -**Why this matters:** Event-driven workflows are more powerful than scheduled ones. They respond instantly to real-world changes. - -### 4. Add secrets - -Your calculator used a public API. **Real workflows often need API keys and other sensitive data.** - -**Learn how to secure your secrets:** - -- **[Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation)** - Store secrets in your local environment for development -- **[Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed)** - Store secrets in the Vault DON for production -- **[Managing Secrets with 1Password](/cre/guides/workflow/secrets/managing-secrets-1password)** - Best practice: inject secrets at runtime - -**Why this matters:** Hardcoded credentials are a security risk. CRE's secrets management lets you safely use authenticated APIs and private keys. - -### 5. Build your own consumer contract - -You used a **pre-deployed consumer contract**. **For production workflows, you'll create custom contracts tailored to your use case.** - -**Learn the secure pattern:** - -- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)** - Create contracts that safely receive CRE data - -**Why this matters:** Consumer contracts enforce business logic and validation onchain, enabling trustless and verifiable execution. - -## Reference: Deepen Your Understanding - -Want to dive deeper into specific concepts from the Getting Started guide? Use this section as a quick reference. - -**Workflow Structure & Triggers** - -- **[Core SDK Reference](/cre/reference/sdk/core/)** - Fundamental building blocks (`InitWorkflow`, `Handler`, `Runtime`) -- **[Triggers Overview](/cre/guides/workflow/using-triggers/overview)** - Compare all available event sources - -**HTTP & Offchain Data** - -- **[API Interactions Guide](/cre/guides/workflow/using-http-client/)** - Complete patterns for HTTP requests -- **[Consensus & Aggregation](/cre/reference/sdk/consensus)** - All aggregation methods (median, mode, custom) -- **[Consensus Computing Concept](/cre/concepts/consensus-computing)** - How CRE's consensus-based execution works - -**EVM & Onchain Interactions** - -- **[EVM Client Overview](/cre/guides/workflow/using-evm-client/overview)** - Introduction to smart contract interactions -- **[Onchain Read Guide](/cre/guides/workflow/using-evm-client/onchain-read)** - Reading from a smart contract -- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write)** - Complete write patterns and report generation - -**Configuration & Secrets** - -- **[Project Configuration](/cre/reference/project-configuration/)** - Complete guide to `project.yaml`, `workflow.yaml`, and targets -- **[Secrets Guide](/cre/guides/workflow/secrets)** - All secrets management patterns - -**All Capabilities** - -- **[Capabilities Overview](/cre/capabilities/)** - See the full list of CRE capabilities and how they work together diff --git a/src/content/cre/getting-started/part-1-project-setup-go.mdx b/src/content/cre/getting-started/part-1-project-setup-go.mdx index f4bb0a924e6..9f8bb8b0794 100644 --- a/src/content/cre/getting-started/part-1-project-setup-go.mdx +++ b/src/content/cre/getting-started/part-1-project-setup-go.mdx @@ -7,14 +7,14 @@ pageId: "getting-started-part-1" metadata: description: "Getting started Part 1 (Go): set up your first CRE project, explore the structure, and run a successful workflow simulation." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-14" --- import { Aside, CopyText, CodeHighlightBlock } from "@components" import part1Code from "./snippets/part-1-main.go?raw" <Aside type="note" title="SDK Language: Go"> - You're viewing the **Go** version of this guide. If you prefer TypeScript, use the language selector in the right + You're viewing the **Go** version of this guide. If you prefer TypeScript, use the language selector in the left sidebar to switch to the TypeScript version. </Aside> diff --git a/src/content/cre/getting-started/part-1-project-setup-ts.mdx b/src/content/cre/getting-started/part-1-project-setup-ts.mdx index d571e0f7895..7c96dc090d4 100644 --- a/src/content/cre/getting-started/part-1-project-setup-ts.mdx +++ b/src/content/cre/getting-started/part-1-project-setup-ts.mdx @@ -7,14 +7,14 @@ pageId: "getting-started-part-1" metadata: description: "Getting started Part 1 (TypeScript): set up your first CRE project, explore the structure, and run a successful workflow simulation." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside, CopyText, CodeHighlightBlock } from "@components" import part1Code from "./snippets/part-1-main.ts?raw" <Aside type="note" title="SDK Language: TypeScript"> - You're viewing the **TypeScript** version of this guide. If you prefer Go, use the language selector in the right + You're viewing the **TypeScript** version of this guide. If you prefer Go, use the language selector in the left sidebar to switch to the Go version. </Aside> @@ -33,7 +33,7 @@ Before you begin, ensure you have the following: - **CRE CLI**: See the [Installation Guide](/cre/getting-started/cli-installation/macos-linux) for details. - **CRE account & authentication**: You must have a CRE account and be logged in with the CLI. See [Create your account](/cre/account/creating-account) and [Log in with the CLI](/cre/account/cli-login) for instructions. -- **Bun**: You must have <a href="https://bun.com/docs" target="blank">Bun</a> version 1.2.21 or higher installed. Check your version with <CopyText text="bun --version" code />. See [Install Bun](https://bun.sh/) for instructions. +- **Bun**: You must have <a href="https://bun.com/docs" target="blank">Bun</a> version 1.2.21 or higher installed. Check your version with <CopyText text="bun --version" code />. See [Install Bun](https://bun.com) for instructions. - **Funded Sepolia Account**: An account with Sepolia ETH to pay for transaction gas fees. Go to <a href="https://faucets.chain.link" target="blank">faucets.chain.link</a> to get some Sepolia ETH. ## Step 1: Verify your authentication @@ -160,6 +160,12 @@ Open `onchain-calculator/my-calculator-workflow/main.ts` to see its contents: - **`initWorkflow`**: Creates the workflow by registering handlers (trigger-callback pairs). This is where you define what events your workflow responds to. - **`main`**: The entry point that creates a `Runner`, passes your config type, and runs the workflow. +<Aside type="note" title="Automatic execution"> + You don't need to call `main()` at the end of your file—the SDK automatically executes it during compilation. The SDK + also handles error reporting automatically, so you don't need to add `.catch()` unless you need custom error handling. + See the [Core SDK Reference](/cre/reference/sdk/core-ts#main) for details. +</Aside> + ## Step 4: Configure your workflow Now that you've explored the generated files, let's configure your workflow for simulation. You'll need to adjust a few configuration files. diff --git a/src/content/cre/getting-started/part-4-writing-onchain-go.mdx b/src/content/cre/getting-started/part-4-writing-onchain-go.mdx index 530d5a03092..145ef82f504 100644 --- a/src/content/cre/getting-started/part-4-writing-onchain-go.mdx +++ b/src/content/cre/getting-started/part-4-writing-onchain-go.mdx @@ -7,11 +7,11 @@ pageId: "getting-started-part-4" metadata: description: "Getting started Part 4 (Go): write verified workflow results onchain to smart contracts and complete your first end-to-end workflow." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2025-12-09" --- import { Aside } from "@components" -import { CodeHighlightBlock } from "@components" +import { CodeHighlightBlock, CodeSample } from "@components" import part4Code from "./snippets/part-4-main.go?raw" In the previous parts, you successfully fetched offchain data and read from a smart contract. Now, you'll complete the "Onchain Calculator" by writing your computed result back to the blockchain. @@ -35,75 +35,9 @@ Here is the source code for the contract so you can see how it works: of how this works in a later guide. </Aside> -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import { IReceiverTemplate } from "./keystone/IReceiverTemplate.sol"; - -/** - * @title CalculatorConsumer (Testing Version) - * @notice This contract receives reports from a CRE workflow and stores the results of a calculation onchain. - * @dev This version uses IReceiverTemplate without configuring any security checks, making it compatible - * with the mock Forwarder used during simulation. All permission fields remain at their default zero - * values (disabled). - */ -contract CalculatorConsumer is IReceiverTemplate { - // Struct to hold the data sent in a report from the workflow - struct CalculatorResult { - uint256 offchainValue; - int256 onchainValue; - uint256 finalResult; - } - - // --- State Variables --- - CalculatorResult public latestResult; - uint256 public resultCount; - mapping(uint256 => CalculatorResult) public results; - - // --- Events --- - event ResultUpdated(uint256 indexed resultId, uint256 finalResult); - - /** - * @dev The constructor doesn't set any security checks. - * The IReceiverTemplate parent constructor will initialize all permission fields to zero (disabled). - */ - constructor() {} - - /** - * @notice Implements the core business logic for processing reports. - * @dev This is called automatically by IReceiverTemplate's onReport function after security checks. - */ - function _processReport(bytes calldata report) internal override { - // Decode the report bytes into our CalculatorResult struct - CalculatorResult memory calculatorResult = abi.decode(report, (CalculatorResult)); - - // --- Core Logic --- - // Update contract state with the new result - resultCount++; - results[resultCount] = calculatorResult; - latestResult = calculatorResult; - - emit ResultUpdated(resultCount, calculatorResult.finalResult); - } - - // This function is a "dry-run" utility. It allows an offchain system to check - // if a prospective result is an outlier before submitting it for a real onchain update. - // It is also used to guide the binding generator to create a method that accepts the CalculatorResult struct. - function isResultAnomalous(CalculatorResult memory _prospectiveResult) public view returns (bool) { - // A result is not considered anomalous if it's the first one. - if (resultCount == 0) { - return false; - } - - // Business logic: Define an anomaly as a new result that is more than double the previous result. - // This is just one example of a validation rule you could implement. - return _prospectiveResult.finalResult > (latestResult.finalResult * 2); - } -} -``` +<CodeSample src="samples/CRE/CalculatorConsumer.sol" /> -The contract is already deployed for you on Sepolia at the following address: <a href="https://sepolia.etherscan.io/address/0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54#code" target="_blank" rel="noopener noreferrer">`0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54`</a>. You will use this address in your configuration file. +The contract is already deployed for you on Sepolia at the following address: <a href="https://sepolia.etherscan.io/address/0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb#code" target="_blank" rel="noopener noreferrer">`0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb`</a>. You will use this address in your configuration file. ## Step 2: Generate the consumer contract binding @@ -119,7 +53,7 @@ You need to create a binding for the consumer contract so your workflow can inte {/* prettier-ignore */} ```json - [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"received","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"InvalidAuthor","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"InvalidSender","type":"error"},{"inputs":[{"internalType":"bytes32","name":"received","type":"bytes32"},{"internalType":"bytes32","name":"expected","type":"bytes32"}],"name":"InvalidWorkflowId","type":"error"},{"inputs":[{"internalType":"bytes10","name":"received","type":"bytes10"},{"internalType":"bytes10","name":"expected","type":"bytes10"}],"name":"InvalidWorkflowName","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"resultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalResult","type":"uint256"}],"name":"ResultUpdated","type":"event"},{"inputs":[],"name":"expectedAuthor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expectedWorkflowId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expectedWorkflowName","outputs":[{"internalType":"bytes10","name":"","type":"bytes10"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forwarderAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"internalType":"struct CalculatorConsumer.CalculatorResult","name":"_prospectiveResult","type":"tuple"}],"name":"isResultAnomalous","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestResult","outputs":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"bytes","name":"report","type":"bytes"}],"name":"onReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resultCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"results","outputs":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_author","type":"address"}],"name":"setExpectedAuthor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"setExpectedWorkflowId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes10","name":"_name","type":"bytes10"}],"name":"setExpectedWorkflowName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_forwarder","type":"address"}],"name":"setForwarderAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}] + [{"inputs":[{"internalType":"address","name":"_forwarderAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"received","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"InvalidAuthor","type":"error"},{"inputs":[],"name":"InvalidForwarderAddress","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"InvalidSender","type":"error"},{"inputs":[{"internalType":"bytes32","name":"received","type":"bytes32"},{"internalType":"bytes32","name":"expected","type":"bytes32"}],"name":"InvalidWorkflowId","type":"error"},{"inputs":[{"internalType":"bytes10","name":"received","type":"bytes10"},{"internalType":"bytes10","name":"expected","type":"bytes10"}],"name":"InvalidWorkflowName","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"WorkflowNameRequiresAuthorValidation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousAuthor","type":"address"},{"indexed":true,"internalType":"address","name":"newAuthor","type":"address"}],"name":"ExpectedAuthorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"previousId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newId","type":"bytes32"}],"name":"ExpectedWorkflowIdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes10","name":"previousName","type":"bytes10"},{"indexed":true,"internalType":"bytes10","name":"newName","type":"bytes10"}],"name":"ExpectedWorkflowNameUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousForwarder","type":"address"},{"indexed":true,"internalType":"address","name":"newForwarder","type":"address"}],"name":"ForwarderAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"resultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalResult","type":"uint256"}],"name":"ResultUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"SecurityWarning","type":"event"},{"inputs":[],"name":"getExpectedAuthor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExpectedWorkflowId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExpectedWorkflowName","outputs":[{"internalType":"bytes10","name":"","type":"bytes10"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getForwarderAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"internalType":"struct CalculatorConsumer.CalculatorResult","name":"_prospectiveResult","type":"tuple"}],"name":"isResultAnomalous","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestResult","outputs":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"bytes","name":"report","type":"bytes"}],"name":"onReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resultCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"results","outputs":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_author","type":"address"}],"name":"setExpectedAuthor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"setExpectedWorkflowId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"setExpectedWorkflowName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_forwarder","type":"address"}],"name":"setForwarderAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}] ``` 1. **Generate the bindings**: Run the binding generator to create Go bindings for all ABI files in your project. From your project root (`onchain-calculator/`), run: @@ -143,7 +77,7 @@ Add the `CalculatorConsumer` contract address to your `config.staging.json`: "evms": [ { "storageAddress": "0xa17CF997C28FF154eDBae1422e6a50BeF23927F4", - "calculatorConsumerAddress": "0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54", + "calculatorConsumerAddress": "0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb", "chainName": "ethereum-testnet-sepolia", "gasLimit": 500000 } @@ -183,7 +117,7 @@ go mod tidy <Aside type="note" title="Funding Your Account"> This step submits an onchain transaction, which requires gas. Before running the simulation, verify that the account associated with the private key from [Part - 1](/cre/getting-started/part-1-project-setup#step-3-configure-the-environment) is funded with sufficient Sepolia ETH. + 1](/cre/getting-started/part-1-project-setup-go#set-up-your-private-key) is funded with sufficient Sepolia ETH. An unfunded account will cause the transaction to fail, often with an error message like `gas required exceeds allowance`. <br/> @@ -207,34 +141,34 @@ Your workflow will now show the complete end-to-end execution, including the fin ```bash Workflow compiled -2025-11-03T22:48:41Z [SIMULATION] Simulator Initialized - -2025-11-03T22:48:41Z [SIMULATION] Running trigger trigger=cron-trigger@1.0.0 -2025-11-03T22:48:41Z [USER LOG] msg="Successfully fetched offchain value" result=56 -2025-11-03T22:48:41Z [USER LOG] msg="Successfully read onchain value" result=22 -2025-11-03T22:48:41Z [USER LOG] msg="Final calculated result" result=78 -2025-11-03T22:48:41Z [USER LOG] msg="Updating calculator result" consumerAddress=0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54 -2025-11-03T22:48:41Z [USER LOG] msg="Writing report to consumer contract" offchainValue=56 onchainValue=22 finalResult=78 -2025-11-03T22:48:41Z [USER LOG] msg="Waiting for write report response" -2025-11-03T22:48:48Z [USER LOG] msg="Write report transaction succeeded" txHash=0x86a26f848c83f37b8eace8123ec275a0af9d21b23b1fbba9cc7664b7e474314f -2025-11-03T22:48:48Z [USER LOG] msg="View transaction at" url=https://sepolia.etherscan.io/tx/0x86a26f848c83f37b8eace8123ec275a0af9d21b23b1fbba9cc7664b7e474314f -2025-11-03T22:48:48Z [USER LOG] msg="Workflow finished successfully!" result="&{OffchainValue:+56 OnchainValue:+22 FinalResult:+78 TxHash:0x86a26f848c83f37b8eace8123ec275a0af9d21b23b1fbba9cc7664b7e474314f}" +2026-01-09T17:56:29Z [SIMULATION] Simulator Initialized + +2026-01-09T17:56:29Z [SIMULATION] Running trigger trigger=cron-trigger@1.0.0 +2026-01-09T17:56:29Z [USER LOG] msg="Successfully fetched offchain value" result=29 +2026-01-09T17:56:30Z [USER LOG] msg="Successfully read onchain value" result=22 +2026-01-09T17:56:30Z [USER LOG] msg="Final calculated result" result=51 +2026-01-09T17:56:30Z [USER LOG] msg="Updating calculator result" consumerAddress=0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb +2026-01-09T17:56:30Z [USER LOG] msg="Writing report to consumer contract" offchainValue=29 onchainValue=22 finalResult=51 +2026-01-09T17:56:30Z [USER LOG] msg="Waiting for write report response" +2026-01-09T17:56:36Z [USER LOG] msg="Write report transaction succeeded" txHash=0xa9f69bdf80329d16e175e19bb007fdbbd4d8f028aacb67d43a2832d6618d8a24 +2026-01-09T17:56:36Z [USER LOG] msg="View transaction at" url=https://sepolia.etherscan.io/tx/0xa9f69bdf80329d16e175e19bb007fdbbd4d8f028aacb67d43a2832d6618d8a24 +2026-01-09T17:56:36Z [USER LOG] msg="Workflow finished successfully!" result="&{OffchainValue:+29 OnchainValue:+22 FinalResult:+51 TxHash:0xa9f69bdf80329d16e175e19bb007fdbbd4d8f028aacb67d43a2832d6618d8a24}" Workflow Simulation Result: { - "FinalResult": 78, - "OffchainValue": 56, + "FinalResult": 51, + "OffchainValue": 29, "OnchainValue": 22, - "TxHash": "0x86a26f848c83f37b8eace8123ec275a0af9d21b23b1fbba9cc7664b7e474314f" + "TxHash": "0xa9f69bdf80329d16e175e19bb007fdbbd4d8f028aacb67d43a2832d6618d8a24" } -2025-11-03T22:48:48Z [SIMULATION] Execution finished signal received -2025-11-03T22:48:48Z [SIMULATION] Skipping WorkflowEngineV2 +2026-01-09T17:56:36Z [SIMULATION] Execution finished signal received +2026-01-09T17:56:36Z [SIMULATION] Skipping WorkflowEngineV2 ``` -- **`[USER LOG]`**: You can see all of your `logger.Info()` calls showing the complete workflow execution, including the offchain value (`result=56`), onchain value (`result=22`), final calculation (`result=78`), and the transaction hash. +- **`[USER LOG]`**: You can see all of your `logger.Info()` calls showing the complete workflow execution, including the offchain value (`result=29`), onchain value (`result=22`), final calculation (`result=51`), and the transaction hash. - **`[SIMULATION]`**: These are system-level messages from the simulator showing its internal state. -- **`Workflow Simulation Result`**: This is the final return value of your workflow. The `MyResult` struct contains all the values (56 + 22 = 78) and the transaction hash confirming the write operation succeeded. +- **`Workflow Simulation Result`**: This is the final return value of your workflow. The `MyResult` struct contains all the values (29 + 22 = 51) and the transaction hash confirming the write operation succeeded. ## Step 7: Verify the result onchain @@ -250,13 +184,13 @@ Click the URL (or copy and paste it into your browser) to see the full details o **What are you seeing on a blockchain explorer?** -You'll notice the transaction's `to` address is not the `CalculatorConsumer` contract you intended to call. Instead, it's to a **Forwarder** contract. Your workflow sends a secure report to the Forwarder, which then verifies the request and makes the final call to the `CalculatorConsumer` on your workflow's behalf. To learn more, see the [Onchain Write guide](/cre/guides/workflow/using-evm-client/onchain-write). +You'll notice the transaction's `to` address is not the `CalculatorConsumer` contract you intended to call. Instead, it's to a **Forwarder** contract. Your workflow sends a secure report to the Forwarder, which then verifies the request and makes the final call to the `CalculatorConsumer` on your workflow's behalf. To learn more, see the [Onchain Write guide](/cre/guides/workflow/using-evm-client/onchain-write/overview). ### **2. Check the contract state** While your wallet interacted with the Forwarder, the `CalculatorConsumer` contract's state was still updated. You can verify this change directly on Etherscan: -- Navigate to the `CalculatorConsumer` contract address: <a href="https://sepolia.etherscan.io/address/0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54#readContract" target="_blank" rel="noopener noreferrer">`0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54`</a>. +- Navigate to the `CalculatorConsumer` contract address: <a href="https://sepolia.etherscan.io/address/0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb#readContract" target="_blank" rel="noopener noreferrer">`0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb`</a>. - Expand the `latestResult` function and click **Query**. The values should match the `finalResult`, `offchainValue`, and `onchainValue` from your workflow logs. This completes the end-to-end loop: triggering a workflow, fetching data, reading onchain state, and verifiably writing the result back to a public blockchain. @@ -264,10 +198,10 @@ This completes the end-to-end loop: triggering a workflow, fetching data, readin To learn more about implementing consumer contracts and the secure write process, see these guides: - **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Learn how to create your own secure consumer contracts with proper validation. -- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write)**: Dive deeper into the write patterns. +- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write/overview-go)**: Dive deeper into the write patterns. ## Next steps You've now mastered the complete CRE development workflow! -- **[Conclusion & Next Steps](/cre/getting-started/conclusion)**: Review what you've learned and find resources for advanced topics. +- **[Before You Build](/cre/getting-started/before-you-build-go)**: Don't skip this — critical tips before building your own workflows. diff --git a/src/content/cre/getting-started/part-4-writing-onchain-ts.mdx b/src/content/cre/getting-started/part-4-writing-onchain-ts.mdx index 5fbfb1fc583..8f890d953cf 100644 --- a/src/content/cre/getting-started/part-4-writing-onchain-ts.mdx +++ b/src/content/cre/getting-started/part-4-writing-onchain-ts.mdx @@ -7,11 +7,11 @@ pageId: "getting-started-part-4" metadata: description: "Getting started Part 4 (TypeScript): write verified workflow results onchain to smart contracts and complete your first end-to-end workflow." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2025-12-09" --- import { Aside } from "@components" -import { CodeHighlightBlock } from "@components" +import { CodeHighlightBlock, CodeSample } from "@components" import part4Code from "./snippets/part-4-main.ts?raw" In the previous parts, you successfully fetched offchain data and read from a smart contract. Now, you'll complete the "Onchain Calculator" by writing your computed result back to the blockchain. @@ -35,75 +35,9 @@ Here is the source code for the contract so you can see how it works: of how this works in a later guide. </Aside> -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import { IReceiverTemplate } from "./keystone/IReceiverTemplate.sol"; - -/** - * @title CalculatorConsumer (Testing Version) - * @notice This contract receives reports from a CRE workflow and stores the results of a calculation onchain. - * @dev This version uses IReceiverTemplate without configuring any security checks, making it compatible - * with the mock Forwarder used during simulation. All permission fields remain at their default zero - * values (disabled). - */ -contract CalculatorConsumer is IReceiverTemplate { - // Struct to hold the data sent in a report from the workflow - struct CalculatorResult { - uint256 offchainValue; - int256 onchainValue; - uint256 finalResult; - } - - // --- State Variables --- - CalculatorResult public latestResult; - uint256 public resultCount; - mapping(uint256 => CalculatorResult) public results; - - // --- Events --- - event ResultUpdated(uint256 indexed resultId, uint256 finalResult); - - /** - * @dev The constructor doesn't set any security checks. - * The IReceiverTemplate parent constructor will initialize all permission fields to zero (disabled). - */ - constructor() {} - - /** - * @notice Implements the core business logic for processing reports. - * @dev This is called automatically by IReceiverTemplate's onReport function after security checks. - */ - function _processReport(bytes calldata report) internal override { - // Decode the report bytes into our CalculatorResult struct - CalculatorResult memory calculatorResult = abi.decode(report, (CalculatorResult)); - - // --- Core Logic --- - // Update contract state with the new result - resultCount++; - results[resultCount] = calculatorResult; - latestResult = calculatorResult; - - emit ResultUpdated(resultCount, calculatorResult.finalResult); - } - - // This function is a "dry-run" utility. It allows an offchain system to check - // if a prospective result is an outlier before submitting it for a real onchain update. - // It is also used to guide the binding generator to create a method that accepts the CalculatorResult struct. - function isResultAnomalous(CalculatorResult memory _prospectiveResult) public view returns (bool) { - // A result is not considered anomalous if it's the first one. - if (resultCount == 0) { - return false; - } +<CodeSample src="samples/CRE/CalculatorConsumer.sol" /> - // Business logic: Define an anomaly as a new result that is more than double the previous result. - // This is just one example of a validation rule you could implement. - return _prospectiveResult.finalResult > (latestResult.finalResult * 2); - } -} -``` - -The contract is already deployed for you on Sepolia at the following address: <a href="https://sepolia.etherscan.io/address/0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54#code" target="_blank" rel="noopener noreferrer">`0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54`</a>. You will use this address in your configuration file. +The contract is already deployed for you on Sepolia at the following address: <a href="https://sepolia.etherscan.io/address/0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb#code" target="_blank" rel="noopener noreferrer">`0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb`</a>. You will use this address in your configuration file. ## Step 2: Update your workflow configuration @@ -116,7 +50,7 @@ Add the `CalculatorConsumer` contract address to your `config.staging.json`: "evms": [ { "storageAddress": "0xa17CF997C28FF154eDBae1422e6a50BeF23927F4", - "calculatorConsumerAddress": "0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54", + "calculatorConsumerAddress": "0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb", "chainName": "ethereum-testnet-sepolia", "gasLimit": "500000" } @@ -184,7 +118,7 @@ These helpers are great for production code, but we use the explicit approach he <Aside type="note" title="Funding Your Account"> This step submits an onchain transaction, which requires gas. Before running the simulation, verify that the account associated with the private key from [Part - 1](/cre/getting-started/part-1-project-setup#step-3-configure-your-workflow) is funded with sufficient Sepolia ETH. + 1](/cre/getting-started/part-1-project-setup-ts#set-up-your-private-key) is funded with sufficient Sepolia ETH. An unfunded account will cause the transaction to fail, often with an error message like `gas required exceeds allowance`. <br/> @@ -208,31 +142,35 @@ Your workflow will now show the complete end-to-end execution, including the fin ```bash Workflow compiled -2025-11-03T19:09:22Z [SIMULATION] Simulator Initialized - -2025-11-03T19:09:22Z [SIMULATION] Running trigger trigger=cron-trigger@1.0.0 -2025-11-03T19:09:22Z [USER LOG] Successfully fetched offchain value: 39 -2025-11-03T19:09:22Z [USER LOG] Successfully read onchain value: 22 -2025-11-03T19:09:22Z [USER LOG] Final calculated result: 61 -2025-11-03T19:09:22Z [USER LOG] Updating calculator result for consumer: 0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54 -2025-11-03T19:09:22Z [USER LOG] Writing report to consumer contract - offchainValue: 39, onchainValue: 22, finalResult: 61 -2025-11-03T19:09:25Z [USER LOG] Waiting for write report response -2025-11-03T19:09:25Z [USER LOG] Write report transaction succeeded: 0xcc99cf4fcdc1262162762f747eeb660b52cc117754c953fdb72842414fcecdc4 -2025-11-03T19:09:25Z [USER LOG] View transaction at https://sepolia.etherscan.io/tx/0xcc99cf4fcdc1262162762f747eeb660b52cc117754c953fdb72842414fcecdc4 -2025-11-03T19:09:25Z [USER LOG] Workflow finished successfully! offchainValue: 39, onchainValue: 22, finalResult: 61, txHash: 0xcc99cf4fcdc1262162762f747eeb660b52cc117754c953fdb72842414fcecdc4 +2026-01-09T17:52:05Z [SIMULATION] Simulator Initialized + +2026-01-09T17:52:05Z [SIMULATION] Running trigger trigger=cron-trigger@1.0.0 +2026-01-09T17:52:06Z [USER LOG] Successfully fetched offchain value: 68 +2026-01-09T17:52:06Z [USER LOG] Successfully read onchain value: 22 +2026-01-09T17:52:06Z [USER LOG] Final calculated result: 90 +2026-01-09T17:52:06Z [USER LOG] Updating calculator result for consumer: 0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb +2026-01-09T17:52:06Z [USER LOG] Writing report to consumer contract - offchainValue: 68, onchainValue: 22, finalResult: 90 +2026-01-09T17:52:12Z [USER LOG] Waiting for write report response +2026-01-09T17:52:12Z [USER LOG] Write report transaction succeeded: 0x6346d9eeca2f2875131d38aa9903a216f16e3cc7188f0ac6a1d5cd1fcbfbf9e6 +2026-01-09T17:52:12Z [USER LOG] View transaction at https://sepolia.etherscan.io/tx/0x6346d9eeca2f2875131d38aa9903a216f16e3cc7188f0ac6a1d5cd1fcbfbf9e6 +2026-01-09T17:52:12Z [USER LOG] Workflow finished successfully! offchainValue: 68, onchainValue: 22, finalResult: 90, txHash: 0x6346d9eeca2f2875131d38aa9903a216f16e3cc7188f0ac6a1d5cd1fcbfbf9e6 Workflow Simulation Result: { - "finalResult": 61, - "offchainValue": 39, + "finalResult": 90, + "offchainValue": 68, "onchainValue": 22, - "txHash": "0xcc99cf4fcdc1262162762f747eeb660b52cc117754c953fdb72842414fcecdc4" + "txHash": "0x6346d9eeca2f2875131d38aa9903a216f16e3cc7188f0ac6a1d5cd1fcbfbf9e6" } -2025-11-03T19:09:25Z [SIMULATION] Execution finished signal received -2025-11-03T19:09:25Z [SIMULATION] Skipping WorkflowEngineV2 +2026-01-09T17:52:12Z [SIMULATION] Execution finished signal received +2026-01-09T17:52:12Z [SIMULATION] Skipping WorkflowEngineV2 ``` +- **`[USER LOG]`**: You can see all of your `logger.info()` calls showing the complete workflow execution, including the offchain value (`68`), onchain value (`22`), final calculation (`90`), and the transaction hash. +- **`[SIMULATION]`**: These are system-level messages from the simulator showing its internal state. +- **`Workflow Simulation Result`**: This is the final return value of your workflow. The `MyResult` object contains all the values (68 + 22 = 90) and the transaction hash confirming the write operation succeeded. + ## Step 5: Verify the result onchain ### **1. Check the Transaction** @@ -247,13 +185,13 @@ Click the URL (or copy and paste it into your browser) to see the full details o **What are you seeing on a blockchain explorer?** -You'll notice the transaction's `to` address is not the `CalculatorConsumer` contract you intended to call. Instead, it's to a **Forwarder** contract. Your workflow sends a secure report to the Forwarder, which then verifies the request and makes the final call to the `CalculatorConsumer` on your workflow's behalf. To learn more, see the [Onchain Write guide](/cre/guides/workflow/using-evm-client/onchain-write). +You'll notice the transaction's `to` address is not the `CalculatorConsumer` contract you intended to call. Instead, it's to a **Forwarder** contract. Your workflow sends a secure report to the Forwarder, which then verifies the request and makes the final call to the `CalculatorConsumer` on your workflow's behalf. To learn more, see the [Onchain Write guide](/cre/guides/workflow/using-evm-client/onchain-write/overview). ### **2. Check the contract state** While your wallet interacted with the Forwarder, the `CalculatorConsumer` contract's state was still updated. You can verify this change directly on Etherscan: -- Navigate to the `CalculatorConsumer` contract address: <a href="https://sepolia.etherscan.io/address/0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54#readContract" target="_blank" rel="noopener noreferrer">`0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54`</a>. +- Navigate to the `CalculatorConsumer` contract address: <a href="https://sepolia.etherscan.io/address/0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb#readContract" target="_blank" rel="noopener noreferrer">`0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb`</a>. - Expand the `latestResult` function and click **Query**. The values should match the `finalResult`, `offchainValue`, and `onchainValue` from your workflow logs. This completes the end-to-end loop: triggering a workflow, fetching data, reading onchain state, and verifiably writing the result back to a public blockchain. @@ -261,10 +199,10 @@ This completes the end-to-end loop: triggering a workflow, fetching data, readin To learn more about implementing consumer contracts and the secure write process, see these guides: - **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Learn how to create your own secure consumer contracts with proper validation. -- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write)**: Dive deeper into the write patterns. +- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write/overview-ts)**: Dive deeper into the write patterns. ## Next steps You've now mastered the complete CRE development workflow! -- **[Conclusion & Next Steps](/cre/getting-started/conclusion)**: Review what you've learned and find resources for advanced topics. +- **[Before You Build](/cre/getting-started/before-you-build-ts)**: Don't skip this — critical tips before building your own workflows. diff --git a/src/content/cre/getting-started/snippets/part-1-main.ts b/src/content/cre/getting-started/snippets/part-1-main.ts index 7abfa193544..b8eab23b5f8 100644 --- a/src/content/cre/getting-started/snippets/part-1-main.ts +++ b/src/content/cre/getting-started/snippets/part-1-main.ts @@ -1,4 +1,4 @@ -import { cre, Runner, type Runtime } from "@chainlink/cre-sdk" +import { CronCapability, handler, Runner, type Runtime } from "@chainlink/cre-sdk" type Config = { schedule: string @@ -10,14 +10,12 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() diff --git a/src/content/cre/getting-started/snippets/part-2-main.ts b/src/content/cre/getting-started/snippets/part-2-main.ts index 1adb068c8ad..b0e68ab7f79 100644 --- a/src/content/cre/getting-started/snippets/part-2-main.ts +++ b/src/content/cre/getting-started/snippets/part-2-main.ts @@ -1,4 +1,12 @@ -import { cre, consensusMedianAggregation, Runner, type NodeRuntime, type Runtime } from "@chainlink/cre-sdk" +import { + CronCapability, + HTTPClient, + handler, + consensusMedianAggregation, + Runner, + type NodeRuntime, + type Runtime, +} from "@chainlink/cre-sdk" type Config = { schedule: string @@ -10,15 +18,15 @@ type MyResult = { } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } // fetchMathResult is the function passed to the runInNodeMode helper. // It contains the logic for making the request and parsing the response. const fetchMathResult = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const req = { url: nodeRuntime.config.apiUrl, @@ -54,5 +62,3 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() diff --git a/src/content/cre/getting-started/snippets/part-3-main.ts b/src/content/cre/getting-started/snippets/part-3-main.ts index eb85ea08827..593db2241ba 100644 --- a/src/content/cre/getting-started/snippets/part-3-main.ts +++ b/src/content/cre/getting-started/snippets/part-3-main.ts @@ -1,5 +1,8 @@ import { - cre, + CronCapability, + HTTPClient, + EVMClient, + handler, consensusMedianAggregation, Runner, type NodeRuntime, @@ -31,14 +34,14 @@ type MyResult = { } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } // fetchMathResult is the function passed to the runInNodeMode helper. const fetchMathResult = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const req = { url: nodeRuntime.config.apiUrl, @@ -73,7 +76,7 @@ const onCronTrigger = (runtime: Runtime<Config>): MyResult => { throw new Error(`Unknown chain name: ${evmConfig.chainName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) // Encode the function call using the Storage ABI const callData = encodeFunctionData({ @@ -116,5 +119,3 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() diff --git a/src/content/cre/getting-started/snippets/part-4-main.ts b/src/content/cre/getting-started/snippets/part-4-main.ts index 0770441c52f..b16f70ff4ec 100644 --- a/src/content/cre/getting-started/snippets/part-4-main.ts +++ b/src/content/cre/getting-started/snippets/part-4-main.ts @@ -1,5 +1,8 @@ import { - cre, + CronCapability, + HTTPClient, + EVMClient, + handler, consensusMedianAggregation, Runner, type NodeRuntime, @@ -37,9 +40,9 @@ type MyResult = { // highlight-end const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } const onCronTrigger = (runtime: Runtime<Config>): MyResult => { @@ -61,7 +64,7 @@ const onCronTrigger = (runtime: Runtime<Config>): MyResult => { runtime.log(`Successfully fetched offchain value: ${offchainValue}`) // Step 2: Read onchain data using the EVM client - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) const callData = encodeFunctionData({ abi: Storage, @@ -120,7 +123,7 @@ const onCronTrigger = (runtime: Runtime<Config>): MyResult => { // highlight-end const fetchMathResult = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const req = { url: nodeRuntime.config.apiUrl, @@ -146,7 +149,7 @@ function updateCalculatorResult( ): string { runtime.log(`Updating calculator result for consumer: ${evmConfig.calculatorConsumerAddress}`) - const evmClient = new cre.capabilities.EVMClient(chainSelector) + const evmClient = new EVMClient(chainSelector) // Encode the CalculatorResult struct according to the contract's ABI const reportData = encodeAbiParameters( @@ -192,5 +195,3 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() diff --git a/src/content/cre/guides/operations/simulating-workflows.mdx b/src/content/cre/guides/operations/simulating-workflows.mdx index cee0d5e5901..f3d5101c4e5 100644 --- a/src/content/cre/guides/operations/simulating-workflows.mdx +++ b/src/content/cre/guides/operations/simulating-workflows.mdx @@ -95,7 +95,7 @@ Non-interactive mode allows you to run simulations without prompts, making it id **Requirements:** - Use the `--non-interactive` flag -- Specify `--trigger-index` (0-based index of the trigger to run) +- Specify `--trigger-index` to select which handler to run (0-based position: `0` = first handler, `1` = second, etc.) - Provide trigger-specific flags as needed (see [Trigger-specific configuration](#trigger-specific-configuration)) **Example:** @@ -104,6 +104,14 @@ Non-interactive mode allows you to run simulations without prompts, making it id cre workflow simulate my-workflow --non-interactive --trigger-index 0 --target staging-settings ``` +<Aside type="tip" title="Understanding trigger-index"> + The `--trigger-index` flag selects **which handler** in your workflow to execute. Handlers are created in your + `InitWorkflow` function using `cre.Handler()`, where [each handler connects a trigger to a callback + function](/cre/key-terms#handler). If your workflow has only one handler, use `--trigger-index 0`. If you have + multiple handlers (e.g., one for an HTTP trigger and one for an EVM log trigger), use `0` for the first, `1` for the + second, etc., based on their order in your code. +</Aside> + ## The `--broadcast` flag By default, the simulator performs a **dry run** for onchain write operations. It prepares the transaction but does not broadcast it to the blockchain. @@ -211,6 +219,19 @@ cre workflow simulate my-workflow \ --target staging-settings ``` +{/* prettier-ignore */} +<Aside type="tip" title="Understanding the two different indexes"> + **Two separate concepts:** + - **`--trigger-index`** selects **which handler** in your workflow to run (e.g., if the + handler with an EVM log trigger is the third handler defined, use `--trigger-index 2`) + - **`--evm-event-index`** + specifies **which log/event within the transaction** to use for testing (e.g., if the transaction emitted 3 events and + you want the first one, use `--evm-event-index 0`) + <br /> + These are completely independent: one selects your workflow's + handler to execute, the other selects which event data from the blockchain to test with. +</Aside> + ## Additional flags ### `--engine-logs` (`-g`) diff --git a/src/content/cre/guides/operations/updating-deployed-workflows.mdx b/src/content/cre/guides/operations/updating-deployed-workflows.mdx index 4ccb0177715..d3ce1a4b47c 100644 --- a/src/content/cre/guides/operations/updating-deployed-workflows.mdx +++ b/src/content/cre/guides/operations/updating-deployed-workflows.mdx @@ -5,13 +5,18 @@ title: "Updating Deployed Workflows" metadata: description: "Update your live workflows: learn how to safely deploy new versions and replace your running workflows without downtime." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-23" --- import { Aside } from "@components" When you update a deployed workflow, you redeploy it with the same workflow name. The new deployment replaces the previous version in the Workflow Registry contract. Currently, CRE does not maintain version history—each deployment overwrites the previous one. +{/* prettier-ignore */} +<Aside type="caution" title="Workflow ID changes on update"> + The workflow ID changes each time you update a workflow. This is because the workflow ID is a hash derived from the workflow binary and configuration. If your consumer contract uses the workflow ID for validation, make sure to update the expected workflow ID after each update. See [Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#34-configuring-permissions) for details. +</Aside> + ## Prerequisites Before updating a deployed workflow, ensure you have: @@ -36,6 +41,12 @@ cre workflow deploy my-workflow --target production-settings 1. **Upload**: The new binary and configuration files are uploaded to the CRE Storage Service 1. **Registration**: A new registration transaction is sent to the Workflow Registry contract 1. **Replacement**: The previous version is replaced with the new deployment +1. **Status preserved**: The workflow's status (active or paused) is preserved from the previous deployment + +{/* prettier-ignore */} +<Aside type="note" title="Workflow status is preserved"> + When you update a workflow, the CLI matches the status of the previously deployed version. If your workflow was paused, the updated version will remain paused. If it was active, the updated version will be active and immediately start responding to triggers. To change the workflow status, see [Activating & Pausing Workflows](/cre/guides/operations/activating-pausing-workflows). +</Aside> {/* prettier-ignore */} <Aside type="caution" title="No version history"> diff --git a/src/content/cre/guides/workflow/secrets/using-secrets-deployed.mdx b/src/content/cre/guides/workflow/secrets/using-secrets-deployed.mdx index d64d82d93c7..7aba4836364 100644 --- a/src/content/cre/guides/workflow/secrets/using-secrets-deployed.mdx +++ b/src/content/cre/guides/workflow/secrets/using-secrets-deployed.mdx @@ -5,7 +5,7 @@ date: Last Modified metadata: description: "Secure your deployed workflows: learn to store and manage secrets in the Vault DON for deployed workflows running on DONs." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside, CodeHighlightBlockMulti } from "@components" @@ -139,7 +139,7 @@ Your workflow code uses the same API to access secrets, whether running in local <CodeHighlightBlockMulti languages={{ ts: { - code: `import { cre, type Runtime } from "@chainlink/cre-sdk" + code: `import { type Runtime } from "@chainlink/cre-sdk" const onCronTrigger = (runtime: Runtime<Config>): string => { // Fetch the secret from the Vault DON (uses default "main" namespace) diff --git a/src/content/cre/guides/workflow/snippets/using-secrets-multiple-ts.ts b/src/content/cre/guides/workflow/snippets/using-secrets-multiple-ts.ts index 212560e14d8..62d46195a8f 100644 --- a/src/content/cre/guides/workflow/snippets/using-secrets-multiple-ts.ts +++ b/src/content/cre/guides/workflow/snippets/using-secrets-multiple-ts.ts @@ -1,4 +1,4 @@ -import { cre, Runner, type Runtime } from "@chainlink/cre-sdk" +import { CronCapability, handler, Runner, type Runtime } from "@chainlink/cre-sdk" // Config can be an empty object if you don't need any parameters from config.json type Config = Record<string, never> @@ -21,9 +21,9 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { // initWorkflow is the entry point for the workflow const initWorkflow = () => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] + return [handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] } // main is the entry point for the WASM binary @@ -31,5 +31,3 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() diff --git a/src/content/cre/guides/workflow/snippets/using-secrets-single-ts.ts b/src/content/cre/guides/workflow/snippets/using-secrets-single-ts.ts index b7c81913051..8f32e23c02f 100644 --- a/src/content/cre/guides/workflow/snippets/using-secrets-single-ts.ts +++ b/src/content/cre/guides/workflow/snippets/using-secrets-single-ts.ts @@ -1,4 +1,4 @@ -import { cre, Runner, type Runtime } from "@chainlink/cre-sdk" +import { CronCapability, handler, Runner, type Runtime } from "@chainlink/cre-sdk" // Config can be an empty object if you don't need any parameters from config.json type Config = Record<string, never> @@ -22,9 +22,9 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { // initWorkflow is the entry point for the workflow const initWorkflow = () => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] + return [handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] } // main is the entry point for the WASM binary @@ -32,5 +32,3 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() diff --git a/src/content/cre/concepts/time-in-cre.mdx b/src/content/cre/guides/workflow/time-in-workflows-go.mdx similarity index 97% rename from src/content/cre/concepts/time-in-cre.mdx rename to src/content/cre/guides/workflow/time-in-workflows-go.mdx index 1c2ca0ea5b1..1645b5876ce 100644 --- a/src/content/cre/concepts/time-in-cre.mdx +++ b/src/content/cre/guides/workflow/time-in-workflows-go.mdx @@ -1,12 +1,13 @@ --- section: cre -title: "Time in CRE" +title: "Using Time in Workflows" sdkLang: "go" +pageId: "time-in-workflows" date: Last Modified metadata: description: "Understand DON Time in CRE: learn why all nodes need the same timestamp and how to use runtime.Now() for deterministic workflows." - datePublished: "2025-11-04" - lastModified: "2025-11-04" + datePublished: "2026-02-03" + lastModified: "2026-02-03" --- import { Aside } from "@components" diff --git a/src/content/cre/guides/workflow/time-in-workflows-ts.mdx b/src/content/cre/guides/workflow/time-in-workflows-ts.mdx new file mode 100644 index 00000000000..d22bf5bc21c --- /dev/null +++ b/src/content/cre/guides/workflow/time-in-workflows-ts.mdx @@ -0,0 +1,118 @@ +--- +section: cre +title: "Using Time in Workflows" +sdkLang: "ts" +pageId: "time-in-workflows" +date: Last Modified +metadata: + description: "Understand DON Time in CRE: learn why all nodes need the same timestamp and how to use runtime.now() for deterministic workflows." + datePublished: "2026-02-03" + lastModified: "2026-02-03" +--- + +import { Aside } from "@components" + +<Aside type="note" title="TL;DR"> + CRE provides **DON Time**: a consensus-derived timestamp so different nodes see the _same time_. Use the SDK's runtime + call, `runtime.now()`, whenever your workflow logic depends on time. Do **not** use `Date.now()` or other local time + sources in DON Mode — they introduce non-determinism. +</Aside> + +## The problem: Why time needs consensus + +Workflows often rely on time for decisions (market-hours checks), scheduling (retries/backoffs), and observability (log timestamps). In a decentralized network, nodes do not share an identical clock—clock drift, resource contention, and OS scheduling can skew each node's local time. If each node consults its own clock: + +- Different nodes may take **different branches** of your logic (e.g., one thinks the market is open, another does not). +- Logs across nodes become **hard to correlate**. +- Data fetched using time (e.g., "fetch price at timestamp N") can be **inconsistent**. + +**DON Time** removes these divergences by making time **deterministic in the DON**. + +## The solution: DON time + +**DON Time** is a timestamp computed by an <a href="https://docs.chain.link/architecture-overview/off-chain-reporting" target="_blank" rel="noopener noreferrer">OCR (Off-Chain Reporting)</a> plugin and agreed upon by the nodes participating in CRE. You access it through the SDK's runtime call, `runtime.now()`, not via JavaScript's `Date.now()`. The `runtime.now()` method returns a standard JavaScript `Date` object. + +**Key properties:** + +- **Deterministic across nodes**: nodes see the same timestamp. +- **Sequenced per workflow**: time responses are associated with a **time-call sequence number** inside each workflow execution (1st call, 2nd call, …). Node execution timing might be slightly off, but a given call will resolve to the **same DON timestamp**. +- **Low latency**: the plugin runs continuously with **delta round = 0**, and each node **transmits** results back to outstanding requests at the end of every round. +- **Tamper-resistant**: workflows don't expose host machine time, reducing timing-attack surface. + +<Aside type="note" title="A Note on Accuracy"> + DON Time is computed as the **median of nodes' local observations** in each round. It is designed for **consistency** + across the DON rather than exact alignment to an external UTC source. Think of it as a highly reliable clock for your + workflows. Do not treat it as a high-precision clock. +</Aside> + +## How it works: A high-level view + +1. Your workflow calls **`runtime.now()`**. +1. **The Chainlink network takes this request**: The Workflow Engine's **TimeProvider** assigns that call a **sequence number** and enqueues it in the **DON Time Store**. +1. **All the nodes agree on a single time (the DON Time)**: The **OCR Time Plugin** on each node reaches consensus on a new DON timestamp (the median of observed times). +1. Each node **returns** the newest DON timestamp to every pending request and updates its **last observed DON time** cache. +1. The result is written back into the WebAssembly execution, and your workflow continues. + +Because requests are sequenced, _Call 1_ for a workflow instance will always return the same DON timestamp on every node. If Node A hits _Call 2_ before Node B, A will block until the DON timestamp for _Call 2_ is produced; when B reaches _Call 2_, it immediately reuses that value. + +## Execution modes: DON mode vs. Node mode + +### DON mode (default for workflows) + +- Time is **consensus-based** and **deterministic**. +- Use for **any** logic where different outcomes across nodes would be a bug. Examples: + - Market-hours gates + - Time-windowed queries ("last 15 minutes") + - Retry/backoff logic that must align across nodes + - Timestamps used for cross-node correlation (logging, audit trails) + +### Node mode (advanced / special cases) + +- Workflow authors handle consensus themselves. +- `runtime.now()` in Node Mode is a non-blocking call that returns the **last generated DON timestamp** from the local node's cache. +- Useful in situations where you already expect non-determinism (e.g., inherently variable HTTP responses). + +<Aside type="caution" title="Use DON Mode"> + Unless you have a specific reason and understand the trade-offs, **always use DON Mode** for time-dependent logic. +</Aside> + +## Best practices: Avoiding non-determinism in DON mode + +When running in DON Mode, you get determinism **if and only if** you base time-dependent logic on DON Time. + +**Avoid** these patterns: + +- **Reading local time** (`Date.now()`, `new Date()`, etc.). Always use `runtime.now()` from the CRE SDK. +- **Mixing time sources** in the same control path. +- **Per-node "sleeps" based on local time** that gate deterministic decisions. + +**Deterministic patterns:** + +- ✅ Gate behavior with: + ```typescript + const now = runtime.now() + if (isMarketOpen(now)) { + // proceed + } + ``` +- ✅ Compute windows from DON Time: + ```typescript + const now = runtime.now() + const fifteenMinutesMs = 15 * 60 * 1000 + const windowStart = new Date(now.getTime() - fifteenMinutesMs) + fetchData(windowStart, now) + ``` + +## FAQ + +**Is DON Time "real UTC time"?** + +It's the **median of node observations** per round. It closely tracks real time but prioritizes **consistency** over absolute accuracy. + +**What is the resolution?** + +New DON timestamps are produced continuously (multiple per second). Treat it as coarse-grained real time suitable for gating and logging, not sub-millisecond measurement. + +**Why can't I use `Date.now()`?** + +`Date.now()` reads the local system clock, which differs slightly on each node. This breaks consensus—nodes may execute different code paths and fail to agree on the workflow result. diff --git a/src/content/cre/guides/workflow/using-confidential-http-client/index.mdx b/src/content/cre/guides/workflow/using-confidential-http-client/index.mdx new file mode 100644 index 00000000000..9bae44c569c --- /dev/null +++ b/src/content/cre/guides/workflow/using-confidential-http-client/index.mdx @@ -0,0 +1,25 @@ +--- +section: cre +title: "Confidential API Interactions (Experimental)" +date: Last Modified +isIndex: true +metadata: + description: "Make privacy-preserving API calls: learn to use Confidential HTTP for enclave execution, secret injection, and response encryption." + datePublished: "2026-02-06" + lastModified: "2026-02-06" +--- + +import { Aside } from "@components" + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The CRE SDK provides a Confidential HTTP client that allows your workflows to interact with external APIs while keeping sensitive data private. Requests execute inside a secure enclave, secrets are injected via templates, and responses can optionally be encrypted. + +For a conceptual overview of what Confidential HTTP is and how it differs from the regular HTTP capability, see [The Confidential HTTP Capability](/cre/capabilities/confidential-http). + +## Guides + +- **[Making Confidential Requests](/cre/guides/workflow/using-confidential-http-client/making-requests)**: Learn how to make a confidential HTTP request with secret injection and optional response encryption. diff --git a/src/content/cre/guides/workflow/using-confidential-http-client/making-requests-go.mdx b/src/content/cre/guides/workflow/using-confidential-http-client/making-requests-go.mdx new file mode 100644 index 00000000000..5b862910c94 --- /dev/null +++ b/src/content/cre/guides/workflow/using-confidential-http-client/making-requests-go.mdx @@ -0,0 +1,400 @@ +--- +section: cre +title: "Making Confidential Requests" +date: Last Modified +sdkLang: "go" +pageId: "guides-workflow-confidential-http-making-requests" +metadata: + description: "Make confidential HTTP requests in Go: learn to use enclave execution, secret injection, and optional response encryption in your workflows." + datePublished: "2026-02-10" + lastModified: "2026-02-10" +--- + +import { Aside } from "@components" + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The `confidentialhttp.Client` is the SDK's interface for the underlying [Confidential HTTP Capability](/cre/capabilities/confidential-http). It allows your workflow to make privacy-preserving API calls where secrets are injected inside a secure enclave and responses can be optionally encrypted. + +Unlike the regular [`http.Client`](/cre/reference/sdk/http-client), the Confidential HTTP client: + +- Executes the request in a secure **enclave** (not on each node individually) +- Injects secrets from the **Vault DON** using template syntax +- Optionally **encrypts the response** before returning it to your workflow + +## Prerequisites + +This guide assumes you have: + +- A basic understanding of CRE. If you are new, complete the [Getting Started tutorial](/cre/getting-started/overview) first. +- Familiarity with [secrets management](/cre/guides/workflow/secrets) in CRE. + +## Step-by-step example + +This example shows a workflow that makes a confidential POST request to an API, injecting an API secret into both the request body and headers using template syntax. + +### Step 1: Configure your workflow + +Add the API URL to your `config.json` file. + +```json +{ + "schedule": "0 */5 * * * *", + "url": "https://api.example.com/data" +} +``` + +### Step 2: Set up secrets for simulation + +Confidential HTTP uses the `secrets.yaml` file. If you've already set up secrets for your project, you can reuse the same file. For a full walkthrough, see [Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation). + +Add the secrets your confidential request needs to your `secrets.yaml`: + +```yaml +# secrets.yaml +secretsNames: + myApiKey: + - MY_API_KEY_ALL +``` + +Provide the actual value via an environment variable or `.env` file: + +```bash +export MY_API_KEY_ALL="your-secret-api-key" +``` + +<Aside type="note" title="Verify secrets-path in workflow.yaml"> + Make sure the `secrets-path` field in your `workflow.yaml` points to your `secrets.yaml` file (for example, + `"../secrets.yaml"` if it is at the project root). New projects created with the CLI may have this field empty by + default. +</Aside> + +### Step 3: Build the confidential request + +The key difference from regular HTTP is how you construct the request. You provide: + +- An `HTTPRequest` with template placeholders (`{{.secretName}}`) in the body and/or headers +- A list of `VaultDonSecrets` identifying which secrets to fetch from the Vault DON +- An optional `EncryptOutput` flag to encrypt the response + +```go +import ( + "github.com/smartcontractkit/cre-sdk-go/capabilities/networking/confidentialhttp" + "github.com/smartcontractkit/cre-sdk-go/cre" +) + +type Config struct { + Schedule string `json:"schedule"` + URL string `json:"url"` +} + +type Result struct { + TransactionID string `json:"transactionId" consensus:"identical"` + Status string `json:"status" consensus:"identical"` +} +``` + +### Step 4: Implement the request logic + +Use `cre.RunInNodeMode` to make the confidential request. The `confidentialhttp.Client` requires a `NodeRuntime`: + +```go +func makeConfidentialRequest(config Config, nodeRuntime cre.NodeRuntime) (Result, error) { + // 1. Define the request body with secret template placeholders + payload := `{"auth": "{{.myApiKey}}", "action": "getTransaction", "id": "tx-123"}` + + // 2. Define headers with secret template placeholders + headers := map[string]*confidentialhttp.HeaderValues{ + "Content-Type": { + Values: []string{"application/json"}, + }, + "Authorization": { + Values: []string{"Basic {{.myApiKey}}"}, + }, + } + + // 3. Create the client and send the request + client := confidentialhttp.Client{} + resp, err := client.SendRequest(nodeRuntime, &confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: payload}, + MultiHeaders: headers, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "myApiKey"}, + }, + EncryptOutput: false, + }).Await() + if err != nil { + return Result{}, fmt.Errorf("confidential HTTP request failed: %w", err) + } + + // 4. Parse the response + var result Result + if err := json.Unmarshal(resp.Body, &result); err != nil { + return Result{}, fmt.Errorf("failed to parse response: %w", err) + } + + return result, nil +} +``` + +### Step 5: Wire it into your workflow + +Call the request function from your trigger handler using `cre.RunInNodeMode`: + +```go +func onCronTrigger(config *Config, runtime cre.Runtime, outputs *cron.Payload) (string, error) { + result, err := cre.RunInNodeMode(*config, runtime, + makeConfidentialRequest, + cre.ConsensusIdenticalAggregation[Result](), + ).Await() + if err != nil { + return "", fmt.Errorf("failed to get result: %w", err) + } + + runtime.Logger().Info("Transaction result", "id", result.TransactionID, "status", result.Status) + return result.TransactionID, nil +} +``` + +### Step 6: Simulate + +Run the simulation: + +```bash +cre workflow simulate +``` + +## Template syntax for secrets + +Secrets are injected into request bodies and headers using Go template syntax: `{{.secretName}}`. The placeholder name must match the `Key` in your `VaultDonSecrets` list. + +**In the request body:** + +```json +{ "auth": "{{.myApiKey}}", "data": "public-data" } +``` + +**In headers:** + +```go +headers := map[string]*confidentialhttp.HeaderValues{ + "Authorization": { + Values: []string{"Basic {{.myCredential}}"}, + }, +} +``` + +The template placeholders are resolved inside the enclave. The actual secret values never appear in your workflow code or in node memory. + +## Response encryption + +By default, the API response is returned unencrypted (`EncryptOutput: false`). To encrypt the response body before it leaves the enclave, set `EncryptOutput: true` and provide an AES-256 encryption key as a Vault DON secret. + +### Setting up response encryption + +1. **Store an AES-256 key** as a Vault DON secret with the identifier `san_marino_aes_gcm_encryption_key`: + + ```yaml + # secrets.yaml + secretsNames: + san_marino_aes_gcm_encryption_key: + - AES_KEY_ALL + ``` + + The key must be a 256-bit (32 bytes) hex-encoded string: + + ```bash + export AES_KEY_ALL="your-256-bit-hex-encoded-key" + ``` + +1. **Include the key in your `VaultDonSecrets`** and set `EncryptOutput: true`: + + ```go + resp, err := client.SendRequest(nodeRuntime, &confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: payload}, + MultiHeaders: headers, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "myApiKey"}, + {Key: "san_marino_aes_gcm_encryption_key"}, + }, + EncryptOutput: true, + }).Await() + ``` + +1. **Decrypt the response** in your own secure backend using AES-GCM. The encrypted response body is structured as `nonce || ciphertext || tag`: + + ```go + import ( + "crypto/aes" + "crypto/cipher" + "encoding/hex" + ) + + func AESGCMDecrypt(blob []byte, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonceSize := gcm.NonceSize() + if len(blob) < nonceSize { + return nil, fmt.Errorf("ciphertext too short") + } + + nonce, ciphertext := blob[:nonceSize], blob[nonceSize:] + return gcm.Open(nil, nonce, ciphertext, nil) + } + ``` + + {/* prettier-ignore */} + <Aside type="tip" title="Do not decrypt inside the workflow"> + The purpose of response encryption is to keep the response confidential even within the decentralized network. Decrypt the response in your own secure backend service, not inside the workflow itself. + </Aside> + +## Complete example + +Here's the full workflow code for a confidential HTTP request with response encryption: + +```go +package main + +import ( + "crypto/aes" + "crypto/cipher" + "encoding/hex" + "encoding/json" + "fmt" + "log/slog" + "os" + + "github.com/smartcontractkit/cre-sdk-go/capabilities/networking/confidentialhttp" + "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" + "github.com/smartcontractkit/cre-sdk-go/cre" +) + +type Config struct { + Schedule string `json:"schedule"` + URL string `json:"url"` +} + +type Result struct { + TransactionID string `json:"transactionId" consensus:"identical"` + Status string `json:"status" consensus:"identical"` +} + +func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { + cronTriggerCfg := &cron.Config{ + Schedule: config.Schedule, + } + + workflow := cre.Workflow[*Config]{ + cre.Handler( + cron.Trigger(cronTriggerCfg), + onCronTrigger, + ), + } + + return workflow, nil +} + +func onCronTrigger(config *Config, runtime cre.Runtime, outputs *cron.Payload) (string, error) { + result, err := cre.RunInNodeMode(*config, runtime, + makeConfidentialRequest, + cre.ConsensusIdenticalAggregation[Result](), + ).Await() + if err != nil { + return "", fmt.Errorf("failed to get result: %w", err) + } + + runtime.Logger().Info("Transaction result", "id", result.TransactionID, "status", result.Status) + return result.TransactionID, nil +} + +func makeConfidentialRequest(config Config, nodeRuntime cre.NodeRuntime) (Result, error) { + payload := `{"auth": "{{.myApiKey}}", "action": "getTransaction", "id": "tx-123"}` + + headers := map[string]*confidentialhttp.HeaderValues{ + "Content-Type": { + Values: []string{"application/json"}, + }, + "Authorization": { + Values: []string{"Basic {{.myApiKey}}"}, + }, + } + + client := confidentialhttp.Client{} + resp, err := client.SendRequest(nodeRuntime, &confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: payload}, + MultiHeaders: headers, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "myApiKey"}, + {Key: "san_marino_aes_gcm_encryption_key"}, + }, + EncryptOutput: true, + }).Await() + if err != nil { + return Result{}, fmt.Errorf("confidential HTTP request failed: %w", err) + } + + // In a real workflow, you would forward the encrypted body to your + // secure backend for decryption. This inline decryption is shown + // for demonstration purposes only. + keyHex := os.Getenv("AES_KEY_ALL") // your 256-bit hex-encoded key + keyBytes, _ := hex.DecodeString(keyHex) + decrypted, err := AESGCMDecrypt(resp.Body, keyBytes) + if err != nil { + return Result{}, fmt.Errorf("failed to decrypt response: %w", err) + } + + var result Result + if err := json.Unmarshal(decrypted, &result); err != nil { + return Result{}, fmt.Errorf("failed to parse response: %w", err) + } + + return result, nil +} + +func AESGCMDecrypt(blob []byte, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonceSize := gcm.NonceSize() + if len(blob) < nonceSize { + return nil, fmt.Errorf("ciphertext too short") + } + + nonce, ciphertext := blob[:nonceSize], blob[nonceSize:] + return gcm.Open(nil, nonce, ciphertext, nil) +} +``` + +## API reference + +For the full list of types and methods available on the Confidential HTTP client, see the [Confidential HTTP Client SDK Reference](/cre/reference/sdk/confidential-http-client-go). diff --git a/src/content/cre/guides/workflow/using-confidential-http-client/making-requests-ts.mdx b/src/content/cre/guides/workflow/using-confidential-http-client/making-requests-ts.mdx new file mode 100644 index 00000000000..6ac9f386e16 --- /dev/null +++ b/src/content/cre/guides/workflow/using-confidential-http-client/making-requests-ts.mdx @@ -0,0 +1,319 @@ +--- +section: cre +title: "Making Confidential Requests" +date: Last Modified +sdkLang: "ts" +pageId: "guides-workflow-confidential-http-making-requests" +metadata: + description: "Make confidential HTTP requests in TypeScript: learn to use enclave execution, secret injection, and optional response encryption in your workflows." + datePublished: "2026-02-10" + lastModified: "2026-02-10" +--- + +import { Aside } from "@components" + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The `ConfidentialHTTPClient` is the SDK's interface for the underlying [Confidential HTTP Capability](/cre/capabilities/confidential-http). It allows your workflow to make privacy-preserving API calls where secrets are injected inside a secure enclave and responses can be optionally encrypted. + +Unlike the regular [`HTTPClient`](/cre/reference/sdk/http-client), the Confidential HTTP client: + +- Executes the request in a secure **enclave** (not on each node individually) +- Injects secrets from the **Vault DON** using template syntax +- Optionally **encrypts the response** before returning it to your workflow + +## Prerequisites + +This guide assumes you have: + +- A basic understanding of CRE. If you are new, complete the [Getting Started tutorial](/cre/getting-started/overview) first. +- Familiarity with [secrets management](/cre/guides/workflow/secrets) in CRE. + +## Step-by-step example + +This example shows a workflow that makes a confidential GET request to an API, injecting a secret into the request headers using template syntax. + +### Step 1: Configure your workflow + +Add the API URL to your `config.json` file. + +```json +{ + "schedule": "0 */5 * * * *", + "url": "https://api.example.com/data", + "owner": "" +} +``` + +### Step 2: Set up secrets for simulation + +Confidential HTTP uses the `secrets.yaml` file. If you've already set up secrets for your project, you can reuse the same file. For a full walkthrough, see [Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation). + +Add the secrets your confidential request needs to your `secrets.yaml`: + +```yaml +# secrets.yaml +secretsNames: + myApiKey: + - MY_API_KEY_ALL +``` + +Provide the actual value via an environment variable or `.env` file: + +```bash +export MY_API_KEY_ALL="your-secret-api-key" +``` + +<Aside type="note" title="Verify secrets-path in workflow.yaml"> + Make sure the `secrets-path` field in your `workflow.yaml` points to your `secrets.yaml` file (for example, + `"../secrets.yaml"` if it is at the project root). New projects created with the CLI may have this field empty by + default. +</Aside> + +### Step 3: Define your types + +```typescript +import { z } from "zod" + +const configSchema = z.object({ + schedule: z.string(), + url: z.string(), + owner: z.string(), +}) + +type Config = z.infer<typeof configSchema> + +type TransactionResult = { + transactionId: string + status: string +} +``` + +### Step 4: Implement the fetch function + +Create the function that will be passed to `sendRequest()`. This function receives a `ConfidentialHTTPSendRequester` and your config as parameters: + +```typescript +import { type ConfidentialHTTPSendRequester, ok, json } from "@chainlink/cre-sdk" + +const fetchTransaction = (sendRequester: ConfidentialHTTPSendRequester, config: Config): TransactionResult => { + // 1. Send the confidential request + const response = sendRequester + .sendRequest({ + request: { + url: config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.myApiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "myApiKey", owner: config.owner }], + }) + .result() + + // 2. Check the response status + if (!ok(response)) { + throw new Error(`HTTP request failed with status: ${response.statusCode}`) + } + + // 3. Parse and return the result + return json(response) as TransactionResult +} +``` + +### Step 5: Wire it into your workflow + +In your trigger handler, call `confHTTPClient.sendRequest()` with your fetch function and a consensus method: + +```typescript +import { + CronCapability, + ConfidentialHTTPClient, + handler, + consensusIdenticalAggregation, + type Runtime, + Runner, +} from "@chainlink/cre-sdk" + +const onCronTrigger = (runtime: Runtime<Config>): string => { + const confHTTPClient = new ConfidentialHTTPClient() + + const result = confHTTPClient + .sendRequest(runtime, fetchTransaction, consensusIdenticalAggregation<TransactionResult>())(runtime.config) + .result() + + runtime.log(`Transaction result: ${result.transactionId} — ${result.status}`) + return result.transactionId +} +``` + +### Step 6: Simulate + +Run the simulation: + +```bash +cre workflow simulate +``` + +## Template syntax for secrets + +Secrets are injected into request bodies and headers using Go template syntax: `{{.secretName}}`. The placeholder name must match the `key` in your `vaultDonSecrets` list. + +**In the request body:** + +```json +{ "auth": "{{.myApiKey}}", "data": "public-data" } +``` + +**In headers:** + +```typescript +multiHeaders: { + "Authorization": { values: ["Basic {{.myCredential}}"] }, +} +``` + +The template placeholders are resolved inside the enclave. The actual secret values never appear in your workflow code or in node memory. + +## Response encryption + +By default, the API response is returned unencrypted (`encryptOutput: false`). To encrypt the response body before it leaves the enclave, set `encryptOutput: true` and provide an AES-256 encryption key as a Vault DON secret. + +### Setting up response encryption + +1. **Store an AES-256 key** as a Vault DON secret with the identifier `san_marino_aes_gcm_encryption_key`: + + ```yaml + # secrets.yaml + secretsNames: + san_marino_aes_gcm_encryption_key: + - AES_KEY_ALL + ``` + +The key must be a 256-bit (32 bytes) hex-encoded string: + +```bash +export AES_KEY_ALL="your-256-bit-hex-encoded-key" +``` + +1. **Include the key in your `vaultDonSecrets`** and set `encryptOutput: true`: + + ```typescript + const response = sendRequester + .sendRequest({ + request: { + url: config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.myApiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "myApiKey", owner: config.owner }, { key: "san_marino_aes_gcm_encryption_key" }], + encryptOutput: true, + }) + .result() + ``` + +1. **Decrypt the response** in your own backend service. The encrypted response body is structured as `nonce || ciphertext || tag` and uses AES-GCM encryption. + +{/* prettier-ignore */} +<Aside type="caution" title="Do not decrypt inside the workflow"> + The purpose of response encryption is to keep the response confidential even within the decentralized network. Decrypt + the response in your own backend service, not inside the workflow itself. +</Aside> + +## Response helper functions + +The SDK response helpers `ok()`, `text()`, and `json()` work with Confidential HTTP responses just as they do with regular HTTP responses. For full documentation, see the [HTTP Client SDK Reference](/cre/reference/sdk/http-client-ts#helper-functions). + +## Complete example + +Here's the full workflow code for a confidential HTTP request with secret injection: + +```typescript +import { + CronCapability, + ConfidentialHTTPClient, + handler, + consensusIdenticalAggregation, + ok, + json, + type ConfidentialHTTPSendRequester, + type Runtime, + Runner, +} from "@chainlink/cre-sdk" +import { z } from "zod" + +// Config schema +const configSchema = z.object({ + schedule: z.string(), + url: z.string(), + owner: z.string(), +}) + +type Config = z.infer<typeof configSchema> + +// Result type +type TransactionResult = { + transactionId: string + status: string +} + +// Fetch function — receives a ConfidentialHTTPSendRequester and config +const fetchTransaction = (sendRequester: ConfidentialHTTPSendRequester, config: Config): TransactionResult => { + const response = sendRequester + .sendRequest({ + request: { + url: config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.myApiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "myApiKey", owner: config.owner }], + }) + .result() + + if (!ok(response)) { + throw new Error(`HTTP request failed with status: ${response.statusCode}`) + } + + return json(response) as TransactionResult +} + +// Main workflow handler +const onCronTrigger = (runtime: Runtime<Config>): string => { + const confHTTPClient = new ConfidentialHTTPClient() + + const result = confHTTPClient + .sendRequest(runtime, fetchTransaction, consensusIdenticalAggregation<TransactionResult>())(runtime.config) + .result() + + runtime.log(`Transaction result: ${result.transactionId} — ${result.status}`) + return result.transactionId +} + +// Initialize workflow +const initWorkflow = (config: Config) => { + return [ + handler( + new CronCapability().trigger({ + schedule: config.schedule, + }), + onCronTrigger + ), + ] +} + +export async function main() { + const runner = await Runner.newRunner<Config>({ configSchema }) + await runner.run(initWorkflow) +} +``` + +## API reference + +For the full list of types and methods available on the Confidential HTTP client, see the [Confidential HTTP Client SDK Reference](/cre/reference/sdk/confidential-http-client-ts). diff --git a/src/content/cre/guides/workflow/using-evm-client/forwarder-directory-go.mdx b/src/content/cre/guides/workflow/using-evm-client/forwarder-directory-go.mdx new file mode 100644 index 00000000000..32ec87b8a48 --- /dev/null +++ b/src/content/cre/guides/workflow/using-evm-client/forwarder-directory-go.mdx @@ -0,0 +1,121 @@ +--- +section: cre +title: "Forwarder Directory" +date: Last Modified +sdkLang: "go" +pageId: "evm-forwarder-directory" +metadata: + description: "Find forwarder contract addresses for CRE workflows on supported EVM networks." + datePublished: "2025-11-04" + lastModified: "2026-02-03" +--- + +import { Aside, CopyText } from "@components" + +<Aside type="note" title="Looking for supported networks?"> + For a complete list of supported networks and version requirements, see [Supported Networks](/cre/supported-networks). +</Aside> + +This page lists forwarder contract addresses for CRE workflows, organized by network. + +## How to Use This Page + +This reference provides three key pieces of information for each network: + +1. **Network Name**: The human-readable network identifier +1. **Chain Name**: The value to use in your [`project.yaml`](/cre/reference/project-configuration-go#31-global-configuration-projectyaml) configuration and [EVM Client code](/cre/reference/sdk/evm-client-go#chain-selectors) +1. **Forwarder Address**: The contract address for optional consumer contract validation + +## Understanding Forwarder Addresses + +Forwarder addresses identify the trusted Chainlink Forwarder contract that delivers verified workflow reports to your consumer contract. Your workflow code does not interact with forwarders directly—the EVM capability handles report delivery automatically. Learn more: [Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview-go). + +**Using the [ReceiverTemplate](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#3-using-receivertemplate) (recommended)**: If you use the [`ReceiverTemplate`](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#receivertemplate), the forwarder address is **required** in the constructor. This ensures your contract only accepts reports from the trusted Chainlink Forwarder. + +**Custom implementations**: If you implement the `IReceiver` interface directly without using `ReceiverTemplate`, you control your own security checks. See [Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts) for details. + +### Simulation vs Production Addresses + +**Important**: Forwarder contracts differ between local simulation and production: + +| Environment | Contract Type | Section | +| ---------------- | ----------------------- | ----------------------------------------------- | +| Local simulation | `MockKeystoneForwarder` | [Simulation Forwarders](#simulation-forwarders) | +| Production | `KeystoneForwarder` | [Production Forwarders](#production-forwarders) | + +If you configure forwarder validation in your consumer contract, **remember to update the forwarder address** when deploying to production. Learn more: [Working with Simulation](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#4-working-with-simulation). + +## Simulation Forwarders + +These `MockKeystoneForwarder` addresses are used when running `cre workflow simulate` with the `--broadcast` flag. Use these addresses **only** during local development and testing. + +### Simulation Mainnets + +| Network | Chain Name | Mock Forwarder Address | +| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------ | +| <a href="https://arbiscan.io/address/0xd770499057619c9a76205fd4168161cf94abc532" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | <CopyText text="ethereum-mainnet-arbitrum-1" code/> | <CopyText text="0xd770499057619c9a76205fd4168161cf94abc532" code/> | +| <a href="https://snowscan.xyz/address/0xdc21e279934ff6721cadfdd112dafb3261f09a2c" target="_blank" rel="noopener noreferrer">Avalanche</a> | <CopyText text="avalanche-mainnet" code/> | <CopyText text="0xdc21e279934ff6721cadfdd112dafb3261f09a2c" code/> | +| <a href="https://basescan.org/address/0x5e342a8438b4f5d39e72875fcee6f76b39cce548" target="_blank" rel="noopener noreferrer">Base</a> | <CopyText text="ethereum-mainnet-base-1" code/> | <CopyText text="0x5e342a8438b4f5d39e72875fcee6f76b39cce548" code/> | +| <a href="https://bscscan.com/address/0x6f3239bbb26e98961e1115aba83f8a282e5508c8" target="_blank" rel="noopener noreferrer">BNB Chain</a> | <CopyText text="binance_smart_chain-mainnet" code/> | <CopyText text="0x6f3239bbb26e98961e1115aba83f8a282e5508c8" code/> | +| <a href="https://etherscan.io/address/0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | <CopyText text="ethereum-mainnet" code/> | <CopyText text="0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" code/> | +| <a href="https://optimistic.etherscan.io/address/0x9119a1501550ed94a3f2794038ed9258337afa18" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | <CopyText text="ethereum-mainnet-optimism-1" code/> | <CopyText text="0x9119a1501550ed94a3f2794038ed9258337afa18" code/> | +| <a href="https://polygonscan.com/address/0xf458d621885e29a5003ea9bbba5280d54e19b1ce" target="_blank" rel="noopener noreferrer">Polygon</a> | <CopyText text="polygon-mainnet" code/> | <CopyText text="0xf458d621885e29a5003ea9bbba5280d54e19b1ce" code/> | +| <a href="https://explorer.zksync.io/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">ZKSync Era</a> | <CopyText text="ethereum-mainnet-zksync-1" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | + +### Simulation Testnets + +| Network | Chain Name | Mock Forwarder Address | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------ | +| <a href="https://explorer.curtis.apechain.com/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Apechain Curtis</a> | <CopyText text="apechain-testnet-curtis" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://testnet.arcscan.app/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Arc Testnet</a> | <CopyText text="arc-testnet" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia.arbiscan.io/address/0xd41263567ddfead91504199b8c6c87371e83ca5d" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code/> | <CopyText text="0xd41263567ddfead91504199b8c6c87371e83ca5d" code/> | +| <a href="https://testnet.snowscan.xyz/address/0x2e7371a5d032489e4f60216d8d898a4c10805963" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | <CopyText text="avalanche-testnet-fuji" code/> | <CopyText text="0x2e7371a5d032489e4f60216d8d898a4c10805963" code/> | +| <a href="https://sepolia.basescan.org/address/0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-base-1" code/> | <CopyText text="0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" code/> | +| <a href="https://testnet.bscscan.com/address/0xa238e42cb8782808dbb2f37e19859244ec4779b0" target="_blank" rel="noopener noreferrer">BNB Chain Testnet</a> | <CopyText text="binance_smart_chain-testnet" code/> | <CopyText text="0xa238e42cb8782808dbb2f37e19859244ec4779b0" code/> | +| <a href="https://sepolia.etherscan.io/address/0x15fC6ae953E024d975e77382eEeC56A9101f9F88" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia" code/> | <CopyText text="0x15fC6ae953E024d975e77382eEeC56A9101f9F88" code/> | +| <a href="https://testnet.purrsec.com/address/0xB27fA1c28288c50542527F64BCda22C9FbAc24CB" target="_blank" rel="noopener noreferrer">Hyperliquid Testnet</a> | <CopyText text="hyperliquid-testnet" code/> | <CopyText text="0xB27fA1c28288c50542527F64BCda22C9FbAc24CB" code/> | +| <a href="https://explorer-sepolia.inkonchain.com/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Ink Sepolia</a> | <CopyText text="ink-testnet-sepolia" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia-explorer.jovay.io/l2/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Jovay Testnet</a> | <CopyText text="jovay-testnet" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia.lineascan.build/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Linea Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-linea-1" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia-optimism.etherscan.io/address/0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-optimism-1" code/> | <CopyText text="0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" code/> | +| <a href="https://testnet.plasmascan.to/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Plasma Testnet</a> | <CopyText text="plasma-testnet" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://amoy.polygonscan.com/address/0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | <CopyText text="polygon-testnet-amoy" code/> | <CopyText text="0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" code/> | +| <a href="https://sepolia.worldscan.org/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">World Chain Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-worldchain-1" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia.explorer.zksync.io/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">ZKSync Era Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-zksync-1" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | + +## Production Forwarders + +These `KeystoneForwarder` addresses are used by deployed workflows. Use these addresses when configuring your consumer contracts for production. + +### Mainnets + +| Network | Chain Name | Forwarder Address | +| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------ | +| <a href="https://arbiscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | <CopyText text="ethereum-mainnet-arbitrum-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche</a> | <CopyText text="avalanche-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base</a> | <CopyText text="ethereum-mainnet-base-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Chain</a> | <CopyText text="binance_smart_chain-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://etherscan.io/address/0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | <CopyText text="ethereum-mainnet" code/> | <CopyText text="0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" code/> | +| <a href="https://optimistic.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | <CopyText text="ethereum-mainnet-optimism-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon</a> | <CopyText text="polygon-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://explorer.zksync.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">ZKSync Era</a> | <CopyText text="ethereum-mainnet-zksync-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | + +### Testnets + +| Network | Chain Name | Forwarder Address | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------ | +| <a href="https://explorer.curtis.apechain.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Apechain Curtis</a> | <CopyText text="apechain-testnet-curtis" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.arbiscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://testnet.snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | <CopyText text="avalanche-testnet-fuji" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-base-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://testnet.bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Chain Testnet</a> | <CopyText text="binance_smart_chain-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://testnet.purrsec.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Hyperliquid Testnet</a> | <CopyText text="hyperliquid-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://explorer-sepolia.inkonchain.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Ink Sepolia</a> | <CopyText text="ink-testnet-sepolia" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia-explorer.jovay.io/l2/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Jovay Testnet</a> | <CopyText text="jovay-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.lineascan.build/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Linea Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-linea-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia-optimism.etherscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-optimism-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://testnet.plasmascan.to/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Plasma Testnet</a> | <CopyText text="plasma-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://amoy.polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | <CopyText text="polygon-testnet-amoy" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.worldscan.org/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">World Chain Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-worldchain-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.explorer.zksync.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">ZKSync Era Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-zksync-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | diff --git a/src/content/cre/guides/workflow/using-evm-client/forwarder-directory-ts.mdx b/src/content/cre/guides/workflow/using-evm-client/forwarder-directory-ts.mdx new file mode 100644 index 00000000000..4baf0ff9d4f --- /dev/null +++ b/src/content/cre/guides/workflow/using-evm-client/forwarder-directory-ts.mdx @@ -0,0 +1,121 @@ +--- +section: cre +title: "Forwarder Directory" +date: Last Modified +sdkLang: "ts" +pageId: "evm-forwarder-directory" +metadata: + description: "Find forwarder contract addresses for CRE workflows on supported EVM networks." + datePublished: "2025-11-04" + lastModified: "2026-02-03" +--- + +import { Aside, CopyText } from "@components" + +<Aside type="note" title="Looking for supported networks?"> + For a complete list of supported networks and version requirements, see [Supported Networks](/cre/supported-networks). +</Aside> + +This page lists forwarder contract addresses for CRE workflows, organized by network. + +## How to Use This Page + +This reference provides three key pieces of information for each network: + +1. **Network Name**: The human-readable network identifier (click to view the forwarder contract on the block explorer) +1. **Chain Name**: The value to use in your [`project.yaml`](/cre/reference/project-configuration-ts#31-global-configuration-projectyaml) configuration and [EVM Client code](/cre/reference/sdk/evm-client-ts#chain-selectors) +1. **Forwarder Address**: The contract address for optional consumer contract validation + +## Understanding Forwarder Addresses + +Forwarder addresses identify the trusted Chainlink Forwarder contract that delivers verified workflow reports to your consumer contract. Your workflow code does not interact with forwarders directly—the EVM capability handles report delivery automatically. Learn more: [Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview-ts). + +**Using the [ReceiverTemplate](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#3-using-receivertemplate) (recommended)**: If you use the [`ReceiverTemplate`](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#receivertemplate), the forwarder address is **required** in the constructor. This ensures your contract only accepts reports from the trusted Chainlink Forwarder. + +**Custom implementations**: If you implement the `IReceiver` interface directly without using `ReceiverTemplate`, you control your own security checks. See [Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts) for details. + +### Simulation vs Production Addresses + +**Important**: Forwarder contracts differ between local simulation and production: + +| Environment | Contract Type | Section | +| ---------------- | ----------------------- | ----------------------------------------------- | +| Local simulation | `MockKeystoneForwarder` | [Simulation Forwarders](#simulation-forwarders) | +| Production | `KeystoneForwarder` | [Production Forwarders](#production-forwarders) | + +If you configure forwarder validation in your consumer contract, **remember to update the forwarder address** when deploying to production. Learn more: [Working with Simulation](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#4-working-with-simulation). + +## Simulation Forwarders + +These `MockKeystoneForwarder` addresses are used when running `cre workflow simulate` with the `--broadcast` flag. Use these addresses **only** during local development and testing. + +### Simulation Mainnets + +| Network | Chain Name | Mock Forwarder Address | +| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------ | +| <a href="https://arbiscan.io/address/0xd770499057619c9a76205fd4168161cf94abc532" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | <CopyText text="ethereum-mainnet-arbitrum-1" code/> | <CopyText text="0xd770499057619c9a76205fd4168161cf94abc532" code/> | +| <a href="https://snowscan.xyz/address/0xdc21e279934ff6721cadfdd112dafb3261f09a2c" target="_blank" rel="noopener noreferrer">Avalanche</a> | <CopyText text="avalanche-mainnet" code/> | <CopyText text="0xdc21e279934ff6721cadfdd112dafb3261f09a2c" code/> | +| <a href="https://basescan.org/address/0x5e342a8438b4f5d39e72875fcee6f76b39cce548" target="_blank" rel="noopener noreferrer">Base</a> | <CopyText text="ethereum-mainnet-base-1" code/> | <CopyText text="0x5e342a8438b4f5d39e72875fcee6f76b39cce548" code/> | +| <a href="https://bscscan.com/address/0x6f3239bbb26e98961e1115aba83f8a282e5508c8" target="_blank" rel="noopener noreferrer">BNB Smart Chain</a> | <CopyText text="binance_smart_chain-mainnet" code/> | <CopyText text="0x6f3239bbb26e98961e1115aba83f8a282e5508c8" code/> | +| <a href="https://etherscan.io/address/0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | <CopyText text="ethereum-mainnet" code/> | <CopyText text="0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" code/> | +| <a href="https://optimistic.etherscan.io/address/0x9119a1501550ed94a3f2794038ed9258337afa18" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | <CopyText text="ethereum-mainnet-optimism-1" code/> | <CopyText text="0x9119a1501550ed94a3f2794038ed9258337afa18" code/> | +| <a href="https://polygonscan.com/address/0xf458d621885e29a5003ea9bbba5280d54e19b1ce" target="_blank" rel="noopener noreferrer">Polygon</a> | <CopyText text="polygon-mainnet" code/> | <CopyText text="0xf458d621885e29a5003ea9bbba5280d54e19b1ce" code/> | +| <a href="https://explorer.zksync.io/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">ZKSync Era</a> | <CopyText text="ethereum-mainnet-zksync-1" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | + +### Simulation Testnets + +| Network | Chain Name | Mock Forwarder Address | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------ | +| <a href="https://explorer.curtis.apechain.com/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Apechain Curtis</a> | <CopyText text="apechain-testnet-curtis" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://testnet.arcscan.app/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Arc Testnet</a> | <CopyText text="arc-testnet" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia.arbiscan.io/address/0xd41263567ddfead91504199b8c6c87371e83ca5d" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code/> | <CopyText text="0xd41263567ddfead91504199b8c6c87371e83ca5d" code/> | +| <a href="https://testnet.snowscan.xyz/address/0x2e7371a5d032489e4f60216d8d898a4c10805963" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | <CopyText text="avalanche-testnet-fuji" code/> | <CopyText text="0x2e7371a5d032489e4f60216d8d898a4c10805963" code/> | +| <a href="https://sepolia.basescan.org/address/0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-base-1" code/> | <CopyText text="0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" code/> | +| <a href="https://testnet.bscscan.com/address/0xa238e42cb8782808dbb2f37e19859244ec4779b0" target="_blank" rel="noopener noreferrer">BSC Testnet</a> | <CopyText text="binance_smart_chain-testnet" code/> | <CopyText text="0xa238e42cb8782808dbb2f37e19859244ec4779b0" code/> | +| <a href="https://sepolia.etherscan.io/address/0x15fC6ae953E024d975e77382eEeC56A9101f9F88" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia" code/> | <CopyText text="0x15fC6ae953E024d975e77382eEeC56A9101f9F88" code/> | +| <a href="https://testnet.purrsec.com/address/0xB27fA1c28288c50542527F64BCda22C9FbAc24CB" target="_blank" rel="noopener noreferrer">Hyperliquid Testnet</a> | <CopyText text="hyperliquid-testnet" code/> | <CopyText text="0xB27fA1c28288c50542527F64BCda22C9FbAc24CB" code/> | +| <a href="https://explorer-sepolia.inkonchain.com/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Ink Sepolia</a> | <CopyText text="ink-testnet-sepolia" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia-explorer.jovay.io/l2/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Jovay Testnet</a> | <CopyText text="jovay-testnet" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia.lineascan.build/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Linea Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-linea-1" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia-optimism.etherscan.io/address/0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-optimism-1" code/> | <CopyText text="0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" code/> | +| <a href="https://testnet.plasmascan.to/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Plasma Testnet</a> | <CopyText text="plasma-testnet" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://amoy.polygonscan.com/address/0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | <CopyText text="polygon-testnet-amoy" code/> | <CopyText text="0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" code/> | +| <a href="https://sepolia.worldscan.org/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">World Chain Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-worldchain-1" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | +| <a href="https://sepolia.explorer.zksync.io/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">ZKSync Era Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-zksync-1" code/> | <CopyText text="0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" code/> | + +## Production Forwarders + +These `KeystoneForwarder` addresses are used by deployed workflows. Use these addresses when configuring your consumer contracts for production. + +### Mainnets + +| Network | Chain Name | Forwarder Address | +| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------ | +| <a href="https://arbiscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | <CopyText text="ethereum-mainnet-arbitrum-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche</a> | <CopyText text="avalanche-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base</a> | <CopyText text="ethereum-mainnet-base-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Smart Chain</a> | <CopyText text="binance_smart_chain-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://etherscan.io/address/0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | <CopyText text="ethereum-mainnet" code/> | <CopyText text="0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" code/> | +| <a href="https://optimistic.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | <CopyText text="ethereum-mainnet-optimism-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon</a> | <CopyText text="polygon-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://explorer.zksync.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">ZKSync Era</a> | <CopyText text="ethereum-mainnet-zksync-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | + +### Testnets + +| Network | Chain Name | Forwarder Address | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------ | +| <a href="https://explorer.curtis.apechain.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Apechain Curtis</a> | <CopyText text="apechain-testnet-curtis" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.arbiscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://testnet.snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | <CopyText text="avalanche-testnet-fuji" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-base-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://testnet.bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BSC Testnet</a> | <CopyText text="binance_smart_chain-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | +| <a href="https://testnet.purrsec.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Hyperliquid Testnet</a> | <CopyText text="hyperliquid-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://explorer-sepolia.inkonchain.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Ink Sepolia</a> | <CopyText text="ink-testnet-sepolia" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia-explorer.jovay.io/l2/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Jovay Testnet</a> | <CopyText text="jovay-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.lineascan.build/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Linea Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-linea-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia-optimism.etherscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-optimism-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://testnet.plasmascan.to/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Plasma Testnet</a> | <CopyText text="plasma-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://amoy.polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | <CopyText text="polygon-testnet-amoy" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.worldscan.org/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">World Chain Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-worldchain-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | +| <a href="https://sepolia.explorer.zksync.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">ZKSync Era Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-zksync-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | diff --git a/src/content/cre/guides/workflow/using-evm-client/generating-bindings.mdx b/src/content/cre/guides/workflow/using-evm-client/generating-bindings.mdx index edd642d1531..6fa9d0c62d3 100644 --- a/src/content/cre/guides/workflow/using-evm-client/generating-bindings.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/generating-bindings.mdx @@ -403,4 +403,4 @@ This generated test file demonstrates real-world patterns for testing complex wo ## Where to go next -Now that you know how to generate bindings, you can use them to [read data from](/cre/guides/workflow/using-evm-client/onchain-read) or [write data to](/cre/guides/workflow/using-evm-client/onchain-write) your contracts, or [trigger workflows from events](/cre/guides/workflow/using-triggers/evm-log-trigger). +Now that you know how to generate bindings, you can use them to [read data from](/cre/guides/workflow/using-evm-client/onchain-read) or [write data to](/cre/guides/workflow/using-evm-client/onchain-write/overview) your contracts, or [trigger workflows from events](/cre/guides/workflow/using-triggers/evm-log-trigger). diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-read-go.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-read-go.mdx index 69e189775b5..20d9f6e0228 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-read-go.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-read-go.mdx @@ -7,7 +7,7 @@ date: Last Modified metadata: description: "Read data from smart contracts in Go: learn to call view functions and fetch verified blockchain state in your workflows." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2025-12-10" --- import { Aside } from "@components" @@ -153,28 +153,73 @@ When calling contract read methods, you must specify a block number. There are t ### Using magic numbers -- **Finalized block**: Use `big.NewInt(-3)` to read from the latest finalized block +- **Finalized block**: Use `big.NewInt(-3)` to read from the latest finalized block (recommended for production) - **Latest block**: Use `big.NewInt(-2)` to read from the latest block -- **Specific block**: Use `big.NewInt(blockNumber)` to read from a specific block -### Using rpc constants (alternative) +For explicit block numbers, see [Custom block depths](#custom-block-depths) below. -You can also use constants from the `go-ethereum/rpc` package for better readability: +### Custom block depths + +For use cases requiring fixed confirmation thresholds (e.g., regulatory compliance) or historical state verification, you can specify an exact block number. + +**Example 1 - Read from a specific historical block**: + +```go +// Read from block 12345678 +specificBlock := big.NewInt(12345678) +value, err := storageContract.Get(runtime, specificBlock).Await() +if err != nil { + return nil, fmt.Errorf("failed to read from specific block: %w", err) +} +``` + +**Example 2 - Read from 500 blocks ago from latest block**: ```go import ( - "math/big" - "github.com/ethereum/go-ethereum/rpc" + pb "github.com/smartcontractkit/chainlink-protos/cre/go/values/pb" ) -// For latest block -reqBlockNumber := big.NewInt(rpc.LatestBlockNumber.Int64()) +// Helper to convert protobuf BigInt to standard library big.Int +func pbBigIntToBigInt(pb *pb.BigInt) *big.Int { + if pb == nil { + return nil + } + result := new(big.Int).SetBytes(pb.AbsVal) + if pb.Sign < 0 { + result.Neg(result) + } + return result +} + +// Get the latest block number +latestHeader, err := evmClient.HeaderByNumber(runtime, &evm.HeaderByNumberRequest{}).Await() +if err != nil { + return nil, fmt.Errorf("failed to get latest block: %w", err) +} + +// Convert protobuf BigInt to standard library big.Int +latestBlockNum := pbBigIntToBigInt(latestHeader.Header.BlockNumber) +customDepth := big.NewInt(500) +customBlock := new(big.Int).Sub(latestBlockNum, customDepth) -// For finalized block -reqBlockNumber := big.NewInt(rpc.FinalizedBlockNumber.Int64()) +// Use the custom block number with the contract binding +value, err := storageContract.Get(runtime, customBlock).Await() +if err != nil { + return nil, fmt.Errorf("failed to read from custom block: %w", err) +} ``` -Both approaches are equivalent - use whichever you find more readable in your code. +**Understanding the conversion:** + +The `pbBigIntToBigInt` helper converts the SDK's protobuf `*pb.BigInt` type (which stores the value as `AbsVal []byte` and `Sign int64`) to Go's standard library `*big.Int`. This allows you to perform arithmetic operations like subtracting 500 blocks. + +<Aside type="note" title="SDK enhancement planned"> + The SDK team is working on a built-in helper to simplify this conversion. Until then, use the `pbBigIntToBigInt` + helper shown above. +</Aside> + +See [Finality and Confidence Levels](/cre/concepts/finality-go) for more details on when to use custom block depths. ## Complete example diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-read-ts.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-read-ts.mdx index 4dd526cc165..a18e0698f64 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-read-ts.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-read-ts.mdx @@ -7,7 +7,7 @@ date: Last Modified metadata: description: "Read data from smart contracts in TypeScript: learn to call view functions and fetch verified blockchain state in your workflows." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside } from "@components" @@ -49,7 +49,8 @@ Here's a complete example of reading from a Storage contract: ```typescript import { - cre, + CronCapability, + EVMClient, getNetwork, encodeCallMsg, bytesToHex, @@ -84,7 +85,7 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { } // Create EVM client with chain selector - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) // Encode the function call const callData = encodeFunctionData({ @@ -117,9 +118,10 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { } const initWorkflow = (config: Config) => { + const cron = new CronCapability() return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + cron.handler( + cron.trigger({ schedule: "*/10 * * * * *", // Every 10 seconds }), onCronTrigger @@ -131,8 +133,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Understanding the components @@ -168,7 +168,7 @@ When calling `callContract()`, you can specify which block to read from: - **`LAST_FINALIZED_BLOCK_NUMBER`**: Read from the last finalized block (recommended for production) - **`LATEST_BLOCK_NUMBER`**: Read from the latest block -- **Specific block**: Use an object with `{ absVal: "base64EncodedNumber", sign: "1" }` format +- **Custom block number**: Use a `BigIntJson` object for custom finality depths or historical queries ```typescript import { LAST_FINALIZED_BLOCK_NUMBER, LATEST_BLOCK_NUMBER } from "@chainlink/cre-sdk" @@ -186,6 +186,54 @@ const contractCall = evmClient.callContract(runtime, { }).result() ``` +#### Custom block depths + +For use cases requiring fixed confirmation thresholds (e.g., regulatory compliance) or historical state verification, you can specify an exact block number. + +**Example 1 - Read from a specific historical block**: + +```typescript +import { blockNumber } from '@chainlink/cre-sdk' + +const historicalBlock = 9767655n +const contractCall = evmClient.callContract(runtime, { + call: encodeCallMsg({...}), + blockNumber: blockNumber(historicalBlock), +}).result() +``` + +**Example 2 - Read from 500 blocks ago for custom finality**: + +```typescript +import { protoBigIntToBigint, blockNumber } from '@chainlink/cre-sdk' + +// Get the latest block number +const latestHeader = evmClient.headerByNumber(runtime, {}).result() +if (!latestHeader.header?.blockNumber) { + throw new Error("Failed to get latest block number") +} + +// Convert protobuf BigInt to native bigint and calculate custom block +const latestBlockNum = protoBigIntToBigint(latestHeader.header.blockNumber) +const customBlock = latestBlockNum - 500n + +// Call the contract at the custom block height +const contractCall = evmClient.callContract(runtime, { + call: encodeCallMsg({...}), + blockNumber: blockNumber(customBlock), +}).result() +``` + +**Helper functions:** + +The SDK provides two helper functions for working with block numbers: + +- **`protoBigIntToBigint(pb)`** — Converts a protobuf `BigInt` (returned by SDK methods like `headerByNumber`) to a native JavaScript `bigint`. Use this when you need to perform arithmetic on block numbers. + +- **`blockNumber(n)`** — Converts a native `bigint`, `number`, or `string` to the protobuf `BigInt` JSON format required by SDK methods. This is an alias for `bigintToProtoBigInt`. + +See [Finality and Confidence Levels](/cre/concepts/finality-ts) for more details on when to use custom block depths. + ### Encoding call messages with `encodeCallMsg()` The `encodeCallMsg()` helper converts your hex-formatted call data into the base64 format required by the EVM capability: @@ -249,7 +297,8 @@ Here's a full runnable workflow with external configuration: ```typescript import { - cre, + CronCapability, + EVMClient, getNetwork, encodeCallMsg, bytesToHex, @@ -280,7 +329,7 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { throw new Error(`Network not found: ${runtime.config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) const callData = encodeFunctionData({ abi: storageAbi, @@ -310,9 +359,10 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { } const initWorkflow = (config: Config) => { + const cron = new CronCapability() return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + cron.handler( + cron.trigger({ schedule: "*/10 * * * * *", }), onCronTrigger @@ -324,8 +374,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ### Configuration file (`config.json`) @@ -377,6 +425,6 @@ This pattern provides better organization, reusability, and type safety across y ## Next steps -- Learn how to [write data to contracts](/cre/guides/workflow/using-evm-client/onchain-write) +- Learn how to [write data to contracts](/cre/guides/workflow/using-evm-client/onchain-write/overview) - Explore the [EVM Client SDK Reference](/cre/reference/sdk/evm-client-ts) for all available methods - See [Part 3](/cre/getting-started/part-3-reading-onchain-value) and [Part 4](/cre/getting-started/part-4-writing-onchain) of the Getting Started guide for more examples diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts.mdx index b2bb6349e51..f05c3f441e2 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts.mdx @@ -5,10 +5,10 @@ date: Last Modified metadata: description: "Build smart contracts that receive CRE data: learn to implement the IReceiver interface and safely handle verified workflow reports." datePublished: "2025-11-04" - lastModified: "2025-11-20" + lastModified: "2026-02-03" --- -import { Aside, ClickToZoom } from "@components" +import { Aside, ClickToZoom, CodeSample } from "@components" When your workflow [writes data to the blockchain](/cre/guides/workflow/using-evm-client/onchain-write), it doesn't call your contract directly. Instead, it submits a signed report to a Chainlink `KeystoneForwarder` contract, which then calls your contract. @@ -16,12 +16,13 @@ This guide explains how to build a consumer contract that can securely receive a **In this guide:** -- [Core Concepts: The Onchain Data Flow](#1-core-concepts-the-onchain-data-flow) -- [The IReceiver Standard](#2-the-ireceiver-standard) -- [Using IReceiverTemplate](#3-using-ireceivertemplate) -- [Working with Simulation](#4-working-with-simulation) -- [Advanced Usage](#5-advanced-usage-optional) -- [Complete Examples](#6-complete-examples) +1. [Core Concepts: The Onchain Data Flow](#1-core-concepts-the-onchain-data-flow) +1. [The IReceiver Standard](#2-the-ireceiver-standard) +1. [Using ReceiverTemplate](#3-using-receivertemplate) +1. [Working with Simulation](#4-working-with-simulation) +1. [Advanced Usage](#5-advanced-usage-optional) +1. [Complete Examples](#6-complete-examples) +1. [Security Considerations](#7-security-considerations) ## 1. Core Concepts: The Onchain Data Flow @@ -38,29 +39,28 @@ To be a valid target for the `KeystoneForwarder`, your consumer contract must sa The `KeystoneForwarder` needs a standardized function to call. This is defined by the `IReceiver` interface, which mandates an `onReport` function. -```solidity -interface IReceiver is IERC165 { - function onReport(bytes calldata metadata, bytes calldata report) external; -} -``` +<CodeSample src="samples/CRE/IReceiver.sol" /> -- `metadata`: Contains information about the workflow (ID, name, owner). +- `metadata`: Contains information about the workflow (ID, name, owner). This is encoded by the Forwarder using `abi.encodePacked` with the following structure: `bytes32 workflowId`, `bytes10 workflowName`, `address workflowOwner`. - `report`: The raw, ABI-encoded data payload from your workflow. ### 2.2 Support ERC165 Interface Detection [ERC165](https://eips.ethereum.org/EIPS/eip-165) is a standard that allows contracts to publish the interfaces they support. The `KeystoneForwarder` uses this to check if your contract supports the `IReceiver` interface before sending a report. -## 3. Using `IReceiverTemplate` +Link to the `IERC165` interface: [IERC165.sol](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol) + +## 3. Using `ReceiverTemplate` ### 3.1 Overview -While you can implement these standards manually, we provide an abstract contract, `IReceiverTemplate.sol`, that does the heavy lifting for you. Inheriting from it is the recommended best practice. +While you can implement these standards manually, we provide an abstract contract, `ReceiverTemplate.sol`, that does the heavy lifting for you. Inheriting from it is the recommended best practice. **Key features:** -- **Optional Permission Controls**: Choose your security level—enable forwarder address checks, workflow ID validation, workflow owner verification, or any combination -- **Flexible and Updatable**: All permission settings can be configured and updated via setter functions after deployment +- **Secure by Default**: Requires forwarder address at deployment, ensuring your contract is protected from the start +- **Layered Security**: Add optional workflow ID validation, workflow owner verification, or any combination for defense-in-depth +- **Flexible Configuration**: All permission settings can be updated via setter functions after deployment - **Simplified Logic**: You only need to implement `_processReport(bytes calldata report)` with your business logic - **Built-in Access Control**: Includes OpenZeppelin's `Ownable` for secure permission management - **ERC165 Support**: Includes the necessary `supportsInterface` function @@ -68,175 +68,17 @@ While you can implement these standards manually, we provide an abstract contrac ### 3.2 Contract Source Code -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {IERC165} from "./IERC165.sol"; -import {IReceiver} from "./IReceiver.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - -/// @title IReceiverTemplate - Abstract receiver with optional permission controls -/// @notice Provides flexible, updatable security checks for receiving workflow reports -/// @dev All permission fields default to zero (disabled). Use setter functions to enable checks. -abstract contract IReceiverTemplate is IReceiver, Ownable { - // Optional permission fields (all default to zero = disabled) - address public forwarderAddress; // If set, only this address can call onReport - address public expectedAuthor; // If set, only reports from this workflow owner are accepted - bytes10 public expectedWorkflowName; // If set, only reports with this workflow name are accepted - bytes32 public expectedWorkflowId; // If set, only reports from this specific workflow ID are accepted - - // Custom errors - error InvalidSender(address sender, address expected); - error InvalidAuthor(address received, address expected); - error InvalidWorkflowName(bytes10 received, bytes10 expected); - error InvalidWorkflowId(bytes32 received, bytes32 expected); - - /// @notice Constructor sets msg.sender as the owner - /// @dev All permission fields are initialized to zero (disabled by default) - constructor() Ownable(msg.sender) {} - - /// @inheritdoc IReceiver - /// @dev Performs optional validation checks based on which permission fields are set - function onReport(bytes calldata metadata, bytes calldata report) external override { - // Security Check 1: Verify caller is the trusted Chainlink Forwarder (if configured) - if (forwarderAddress != address(0) && msg.sender != forwarderAddress) { - revert InvalidSender(msg.sender, forwarderAddress); - } - - // Security Checks 2-4: Verify workflow identity - ID, owner, and/or name (if any are configured) - if (expectedWorkflowId != bytes32(0) || expectedAuthor != address(0) || expectedWorkflowName != bytes10(0)) { - (bytes32 workflowId, bytes10 workflowName, address workflowOwner) = _decodeMetadata(metadata); - - if (expectedWorkflowId != bytes32(0) && workflowId != expectedWorkflowId) { - revert InvalidWorkflowId(workflowId, expectedWorkflowId); - } - if (expectedAuthor != address(0) && workflowOwner != expectedAuthor) { - revert InvalidAuthor(workflowOwner, expectedAuthor); - } - if (expectedWorkflowName != bytes10(0) && workflowName != expectedWorkflowName) { - revert InvalidWorkflowName(workflowName, expectedWorkflowName); - } - } - - _processReport(report); - } - - /// @notice Updates the forwarder address that is allowed to call onReport - /// @param _forwarder The new forwarder address (use address(0) to disable this check) - function setForwarderAddress(address _forwarder) external onlyOwner { - forwarderAddress = _forwarder; - } - - /// @notice Updates the expected workflow owner address - /// @param _author The new expected author address (use address(0) to disable this check) - function setExpectedAuthor(address _author) external onlyOwner { - expectedAuthor = _author; - } - - /// @notice Updates the expected workflow name from a plaintext string - /// @param _name The workflow name as a string (use empty string "" to disable this check) - /// @dev The name is hashed using SHA256 and truncated - function setExpectedWorkflowName(string calldata _name) external onlyOwner { - if (bytes(_name).length == 0) { - expectedWorkflowName = bytes10(0); - return; - } - - // Convert workflow name to bytes10: - // SHA256 hash → hex encode → take first 10 chars → hex encode those chars - bytes32 hash = sha256(bytes(_name)); - bytes memory hexString = _bytesToHexString(abi.encodePacked(hash)); - bytes memory first10 = new bytes(10); - for (uint i = 0; i < 10; i++) { - first10[i] = hexString[i]; - } - expectedWorkflowName = bytes10(first10); - } - - /// @notice Updates the expected workflow ID - /// @param _id The new expected workflow ID (use bytes32(0) to disable this check) - function setExpectedWorkflowId(bytes32 _id) external onlyOwner { - expectedWorkflowId = _id; - } - - /// @notice Helper function to convert bytes to hex string - /// @param data The bytes to convert - /// @return The hex string representation - function _bytesToHexString(bytes memory data) private pure returns (bytes memory) { - bytes memory hexChars = "0123456789abcdef"; - bytes memory hexString = new bytes(data.length * 2); - - for (uint256 i = 0; i < data.length; i++) { - hexString[i * 2] = hexChars[uint8(data[i] >> 4)]; - hexString[i * 2 + 1] = hexChars[uint8(data[i] & 0x0f)]; - } - - return hexString; - } - - /// @notice Extracts all metadata fields from the onReport metadata parameter - /// @param metadata The metadata in bytes format - /// @return workflowId The unique identifier of the workflow (bytes32) - /// @return workflowName The name of the workflow (bytes10) - /// @return workflowOwner The owner address of the workflow - function _decodeMetadata(bytes memory metadata) - internal - pure - returns (bytes32 workflowId, bytes10 workflowName, address workflowOwner) - { - // Metadata structure: - // - First 32 bytes: length of the byte array (standard for dynamic bytes) - // - Offset 32, size 32: workflow_id (bytes32) - // - Offset 64, size 10: workflow_name (bytes10) - // - Offset 74, size 20: workflow_owner (address) - assembly { - workflowId := mload(add(metadata, 32)) - workflowName := mload(add(metadata, 64)) - workflowOwner := shr(mul(12, 8), mload(add(metadata, 74))) - } - } - - /// @notice Abstract function to process the report data - /// @param report The report calldata containing your workflow's encoded data - /// @dev Implement this function with your contract's business logic - function _processReport(bytes calldata report) internal virtual; - - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { - return interfaceId == type(IReceiver).interfaceId || interfaceId == type(IERC165).interfaceId; - } -} -``` +<CodeSample src="samples/CRE/ReceiverTemplate.sol" /> ### 3.3 Quick Start -The simplest way to use `IReceiverTemplate` is to inherit from it and implement the `_processReport` function: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; -import { IReceiverTemplate } from "./IReceiverTemplate.sol"; - -contract MyConsumer is IReceiverTemplate { - uint256 public storedValue; - event ValueUpdated(uint256 newValue); +The simplest way to use `ReceiverTemplate` is to inherit from it and implement the `_processReport` function: - // Simple constructor - no parameters needed - constructor() IReceiverTemplate() {} - - // Implement your business logic here - function _processReport(bytes calldata report) internal override { - uint256 newValue = abi.decode(report, (uint256)); - storedValue = newValue; - emit ValueUpdated(newValue); - } -} -``` +<CodeSample src="samples/CRE/BasicConsumer.sol" /> ### 3.4 Configuring Permissions -After deploying your contract, the owner can enable any combination of security checks using the setter functions. +The forwarder address is configured at deployment via the constructor and provides your first line of defense. After deploying your contract, the owner can configure additional security checks or update the forwarder address if needed. {/* prettier-ignore */} <Aside type="caution" title="For simulation"> @@ -245,21 +87,23 @@ After deploying your contract, the owner can enable any combination of security {/* prettier-ignore */} <Aside type="tip" title="Finding forwarder addresses"> - For a complete list of `KeystoneForwarder` contract addresses on all supported networks, see [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks). + For a complete list of `KeystoneForwarder` and `MockForwarder` contract addresses on all supported networks, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). </Aside> **Configuration examples:** ```solidity -// Example: Enable forwarder check only -myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia +// Example: Update forwarder address (e.g., when moving from simulation to production) +myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia KeystoneForwarder -// Example: Enable workflow ID check +// Example: Add workflow ID check for additional security myConsumer.setExpectedWorkflowId(0x1234...); // Your specific workflow ID -// Example: Enable workflow owner and name checks +// Example: Add workflow owner check myConsumer.setExpectedAuthor(0xYourAddress...); -myConsumer.setExpectedWorkflowName("my_workflow"); // The plaintext workflow name + +// Example: Add workflow name check (requires author validation to be set) +myConsumer.setExpectedWorkflowName("my_workflow"); // Example: Disable a check later myConsumer.setExpectedWorkflowName(""); // Empty string disables the check @@ -267,27 +111,30 @@ myConsumer.setExpectedWorkflowName(""); // Empty string disables the check {/* prettier-ignore */} <Aside type="tip" title="Recommended production setup"> - For production contracts, we recommend enabling at minimum the `forwarderAddress` check. For highest security, combine it with `expectedWorkflowId` to ensure only your specific workflow can update the contract. + The forwarder address is required at deployment and provides basic security. For production contracts, we strongly recommend adding additional validation: + - Use `setExpectedWorkflowId()` if only one workflow writes to your contract (highest security) + - Use `setExpectedAuthor()` if multiple workflows from the same owner write to your contract </Aside> **What the template handles for you:** -- Validates the caller address (if `forwarderAddress` is set) -- Validates the workflow ID (if `expectedWorkflowId` is set) -- Validates the workflow owner (if `expectedAuthor` is set) -- Validates the workflow name (if `expectedWorkflowName` is set) -- Validates the ERC165 interface detection -- Validates the Access control via OpenZeppelin's `Ownable` +- Validates the caller address against the configured forwarder (required at deployment) +- Validates the workflow ID (if `expectedWorkflowId` is configured) +- Validates the workflow owner (if `expectedAuthor` is configured) +- Validates the workflow name (if both `expectedWorkflowName` AND `expectedAuthor` are configured) +- Implements ERC165 interface detection +- Provides access control via OpenZeppelin's `Ownable` - Calls your `_processReport` function with validated data **What you implement:** +- Pass the forwarder address to the constructor during deployment - Your business logic in `_processReport` -- (Optional) Configure permissions after deployment using setter functions +- (Optional) Configure additional permissions after deployment using setter functions #### How workflow names are encoded -The `workflowName` field in the metadata uses the **`bytes10`** type rather than plaintext strings. When you call `setExpectedWorkflowName("my_workflow")`, the `IReceiverTemplate` automatically encodes it using the same algorithm as the CRE engine: +The `workflowName` field in the metadata uses the **`bytes10`** type rather than plaintext strings. When you call `setExpectedWorkflowName("my_workflow")`, the `ReceiverTemplate` automatically encodes it using the same algorithm as the CRE engine: 1. Compute SHA256 hash of the workflow name 1. Convert hash to hex string (64 characters) @@ -298,14 +145,22 @@ The `workflowName` field in the metadata uses the **`bytes10`** type rather than This encoding ensures consistent, fixed-size representation regardless of the original workflow name length. +{/* prettier-ignore */} +<Aside type="caution" title="Workflow name validation requires author validation"> + Workflow name validation is **only performed when author validation is also configured**. The code enforces this at runtime: if you set `expectedWorkflowName`, you must also set `expectedAuthor`, otherwise the validation will revert with `WorkflowNameRequiresAuthorValidation()`. This prevents the 40-bit collision attack by ensuring workflow names are validated in combination with the owner address. See [Security Considerations](#7-security-considerations) for details. +</Aside> + **Usage:** ```solidity -// Just use the plaintext workflow name - the interface handles the encoding automatically +// Set the expected author first (required) +myConsumer.setExpectedAuthor(0xYourAddress...); + +// Then set the expected workflow name (only works with author validation) myConsumer.setExpectedWorkflowName("my_workflow"); -// To disable the check later -myConsumer.setExpectedWorkflowName(""); // Empty string disables the check +// To disable the workflow name check +myConsumer.setExpectedWorkflowName(""); // Empty string clears the stored value ``` ## 4. Working with Simulation @@ -316,20 +171,21 @@ When you run `cre workflow simulate`, your workflow interacts with a **`MockKeys This is a **temporary limitation** until the `MockKeystoneForwarder` is updated to provide full metadata. </Aside> -### Forwarder address validation +### Deploying for Simulation -You **can** configure the forwarder address check during simulation using the **Mock Forwarder Address**: +When deploying your consumer contract for simulation, pass the **Mock Forwarder address** to the constructor: ```solidity -// Example: Use Mock Forwarder for Ethereum Sepolia simulation -myConsumer.setForwarderAddress(0x15fC6ae953E024d975e77382eEeC56A9101f9F88); +// Deploy with MockForwarder address for Ethereum Sepolia simulation +address mockForwarder = 0x15fC6ae953E024d975e77382eEeC56A9101f9F88; // Ethereum Sepolia MockForwarder +MyConsumer myConsumer = new MyConsumer(mockForwarder); ``` -Find Mock Forwarder addresses for all networks in the [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks) page. +Find Mock Forwarder addresses for all networks in the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) page. {/* prettier-ignore */} <Aside type="caution" title="Important: Different addresses for simulation vs production"> - The `MockKeystoneForwarder` address used during simulation is **different** from the `KeystoneForwarder` address used by deployed workflows. If you configure the forwarder address for simulation, remember to update it to the production `KeystoneForwarder` address after deploying. See [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks) for forwarder addresses. + The `MockKeystoneForwarder` address used during simulation is **different** from the `KeystoneForwarder` address used by deployed workflows. After testing with simulation, deploy a new instance with the production `KeystoneForwarder` address, or update the forwarder address using `setForwarderAddress()`. See [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) for forwarder addresses. </Aside> ### Metadata-based validation @@ -342,18 +198,28 @@ Find Mock Forwarder addresses for all networks in the [Supported Networks](/cre/ Setting any of these will cause your simulation to fail. -### After deployment +### Transitioning to Production + +Once you're ready to deploy your workflow to production: -Once you deploy your workflow: +**Option 1: Deploy a new contract instance** -1. Update the forwarder address to the real `KeystoneForwarder` (if you configured it for simulation) -1. Configure additional metadata-based validation as needed +```solidity +// Deploy with production KeystoneForwarder address +address keystoneForwarder = 0xF8344CFd5c43616a4366C34E3EEE75af79a74482; // Ethereum Sepolia +MyConsumer myConsumer = new MyConsumer(keystoneForwarder); + +// Configure additional security checks +myConsumer.setExpectedWorkflowId(0xYourWorkflowId); +``` + +**Option 2: Update existing contract's forwarder** ```solidity -// Update to production KeystoneForwarder address -myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Example: Ethereum Sepolia +// Update forwarder to production KeystoneForwarder +myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia -// Now you can enable metadata-based validation +// Add metadata-based validation myConsumer.setExpectedWorkflowId(0xYourWorkflowId); ``` @@ -366,25 +232,29 @@ See [Configuring Permissions](#34-configuring-permissions) for complete details. You can override `onReport` to add your own validation logic before or after the standard checks: ```solidity -import { IReceiverTemplate } from "./IReceiverTemplate.sol"; +import { ReceiverTemplate } from "./ReceiverTemplate.sol"; -contract AdvancedConsumer is IReceiverTemplate { - uint256 public minReportInterval = 1 hours; - uint256 public lastReportTime; +contract AdvancedConsumer is ReceiverTemplate { + uint256 private s_minReportInterval = 1 hours; + uint256 private s_lastReportTime; error ReportTooFrequent(uint256 timeSinceLastReport, uint256 minInterval); + event MinReportIntervalUpdated(uint256 previousInterval, uint256 newInterval); + + constructor(address _forwarderAddress) ReceiverTemplate(_forwarderAddress) {} + // Add custom validation before parent's checks function onReport(bytes calldata metadata, bytes calldata report) external override { // Custom check: Rate limiting - if (block.timestamp < lastReportTime + minReportInterval) { - revert ReportTooFrequent(block.timestamp - lastReportTime, minReportInterval); + if (block.timestamp < s_lastReportTime + s_minReportInterval) { + revert ReportTooFrequent(block.timestamp - s_lastReportTime, s_minReportInterval); } // Call parent implementation for standard permission checks super.onReport(metadata, report); - lastReportTime = block.timestamp; + s_lastReportTime = block.timestamp; } function _processReport(bytes calldata report) internal override { @@ -393,9 +263,24 @@ contract AdvancedConsumer is IReceiverTemplate { // ... store or process the value ... } - // Allow owner to update rate limit + /// @notice Returns the minimum interval between reports + /// @return The minimum interval in seconds + function getMinReportInterval() external view returns (uint256) { + return s_minReportInterval; + } + + /// @notice Returns the timestamp of the last report + /// @return The last report timestamp + function getLastReportTime() external view returns (uint256) { + return s_lastReportTime; + } + + /// @notice Updates the minimum interval between reports + /// @param _interval The new minimum interval in seconds function setMinReportInterval(uint256 _interval) external onlyOwner { - minReportInterval = _interval; + uint256 previousInterval = s_minReportInterval; + s_minReportInterval = _interval; + emit MinReportIntervalUpdated(previousInterval, _interval); } } ``` @@ -405,8 +290,10 @@ contract AdvancedConsumer is IReceiverTemplate { The `_decodeMetadata` helper function is available for use in your `_processReport` implementation. This allows you to access workflow metadata for custom business logic: ```solidity -contract MetadataAwareConsumer is IReceiverTemplate { - mapping(bytes32 => uint256) public reportCountByWorkflow; +contract MetadataAwareConsumer is ReceiverTemplate { + mapping(bytes32 => uint256) public s_reportCountByWorkflow; + + constructor(address _forwarderAddress) ReceiverTemplate(_forwarderAddress) {} function _processReport(bytes calldata report) internal override { // Access the metadata to get workflow ID @@ -414,7 +301,7 @@ contract MetadataAwareConsumer is IReceiverTemplate { (bytes32 workflowId, , ) = _decodeMetadata(metadata); // Use workflow ID in your business logic - reportCountByWorkflow[workflowId]++; + s_reportCountByWorkflow[workflowId]++; // Process the report data uint256 value = abi.decode(report, (uint256)); @@ -432,35 +319,44 @@ contract MetadataAwareConsumer is IReceiverTemplate { ### Example 1: Simple Consumer Contract -This example inherits from `IReceiverTemplate` to store a temperature value. +This example inherits from `ReceiverTemplate` to store a temperature value. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -import { IReceiverTemplate } from "./IReceiverTemplate.sol"; +import { ReceiverTemplate } from "./ReceiverTemplate.sol"; -contract TemperatureConsumer is IReceiverTemplate { - int256 public currentTemperature; +contract TemperatureConsumer is ReceiverTemplate { + int256 public s_currentTemperature; event TemperatureUpdated(int256 newTemperature); - // Simple constructor - no parameters needed - constructor() IReceiverTemplate() {} + // Constructor requires forwarder address + constructor(address _forwarderAddress) ReceiverTemplate(_forwarderAddress) {} function _processReport(bytes calldata report) internal override { int256 newTemperature = abi.decode(report, (int256)); - currentTemperature = newTemperature; + s_currentTemperature = newTemperature; emit TemperatureUpdated(newTemperature); } } ``` -**Configuring permissions after deployment:** +**Deployment:** ```solidity -// Enable forwarder check for production -temperatureConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia +// For simulation: Use MockForwarder address +address mockForwarder = 0x15fC6ae953E024d975e77382eEeC56A9101f9F88; // e.g. Ethereum Sepolia +TemperatureConsumer temperatureConsumer = new TemperatureConsumer(mockForwarder); + +// For production: Use KeystoneForwarder address +address keystoneForwarder = 0xF8344CFd5c43616a4366C34E3EEE75af79a74482; // e.g. Ethereum Sepolia +TemperatureConsumer temperatureConsumer = new TemperatureConsumer(keystoneForwarder); +``` + +**Adding additional security after deployment:** -// Enable workflow ID check for highest security +```solidity +// Add workflow ID check for highest security temperatureConsumer.setExpectedWorkflowId(0xYourWorkflowId...); ``` @@ -469,7 +365,7 @@ temperatureConsumer.setExpectedWorkflowId(0xYourWorkflowId...); For more complex scenarios, it's best to separate your Chainlink-aware code from your core business logic. The **Proxy Pattern** is a robust architecture that uses two contracts to achieve this: - **A Logic Contract**: Holds the state and the core functions of your application. It knows nothing about the Forwarder contract or the `onReport` function. -- **A Proxy Contract**: Acts as the secure entry point. It inherits from `IReceiverTemplate` and forwards validated reports to the Logic Contract. +- **A Proxy Contract**: Acts as the secure entry point. It inherits from `ReceiverTemplate` and forwards validated reports to the Logic Contract. This separation makes your business logic more modular and reusable. @@ -489,28 +385,59 @@ contract ReserveManager is Ownable { uint256 btcPrice; } - address public proxyAddress; - uint256 public lastEthPrice; - uint256 public lastBtcPrice; - uint256 public lastUpdateTime; + address private s_proxyAddress; + uint256 private s_lastEthPrice; + uint256 private s_lastBtcPrice; + uint256 private s_lastUpdateTime; event ReservesUpdated(uint256 ethPrice, uint256 btcPrice, uint256 updateTime); + event ProxyAddressUpdated(address indexed previousProxy, address indexed newProxy); modifier onlyProxy() { - require(msg.sender == proxyAddress, "Caller is not the authorized proxy"); + require(msg.sender == s_proxyAddress, "Caller is not the authorized proxy"); _; } constructor() Ownable(msg.sender) {} + /// @notice Returns the proxy address + /// @return The authorized proxy address + function getProxyAddress() external view returns (address) { + return s_proxyAddress; + } + + /// @notice Returns the last ETH price + /// @return The last recorded ETH price + function getLastEthPrice() external view returns (uint256) { + return s_lastEthPrice; + } + + /// @notice Returns the last BTC price + /// @return The last recorded BTC price + function getLastBtcPrice() external view returns (uint256) { + return s_lastBtcPrice; + } + + /// @notice Returns the last update timestamp + /// @return The timestamp of the last update + function getLastUpdateTime() external view returns (uint256) { + return s_lastUpdateTime; + } + + /// @notice Updates the authorized proxy address + /// @param _proxyAddress The new proxy address function setProxyAddress(address _proxyAddress) external onlyOwner { - proxyAddress = _proxyAddress; + address previousProxy = s_proxyAddress; + s_proxyAddress = _proxyAddress; + emit ProxyAddressUpdated(previousProxy, _proxyAddress); } + /// @notice Updates the reserve prices + /// @param data The new reserve data containing ETH and BTC prices function updateReserves(UpdateReserves memory data) external onlyProxy { - lastEthPrice = data.ethPrice; - lastBtcPrice = data.btcPrice; - lastUpdateTime = block.timestamp; + s_lastEthPrice = data.ethPrice; + s_lastBtcPrice = data.btcPrice; + s_lastUpdateTime = block.timestamp; emit ReservesUpdated(data.ethPrice, data.btcPrice, block.timestamp); } } @@ -518,23 +445,29 @@ contract ReserveManager is Ownable { #### The Proxy Contract (`UpdateReservesProxy.sol`) -This contract, our "bouncer", is the only contract that interacts with the Chainlink platform. It inherits `IReceiverTemplate` to validate incoming reports and then calls the `ReserveManager`. +This contract, our "bouncer", is the only contract that interacts with the Chainlink platform. It inherits `ReceiverTemplate` to validate incoming reports and then calls the `ReserveManager`. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ReserveManager } from "./ReserveManager.sol"; -import { IReceiverTemplate } from "./keystone/IReceiverTemplate.sol"; +import { ReceiverTemplate } from "./ReceiverTemplate.sol"; -contract UpdateReservesProxy is IReceiverTemplate { - ReserveManager public s_reserveManager; +contract UpdateReservesProxy is ReceiverTemplate { + ReserveManager private s_reserveManager; - constructor(address reserveManagerAddress) { + constructor(address _forwarderAddress, address reserveManagerAddress) ReceiverTemplate(_forwarderAddress) { s_reserveManager = ReserveManager(reserveManagerAddress); } - /// @inheritdoc IReceiverTemplate + /// @notice Returns the reserve manager contract address + /// @return The ReserveManager contract instance + function getReserveManager() external view returns (ReserveManager) { + return s_reserveManager; + } + + /// @inheritdoc ReceiverTemplate function _processReport(bytes calldata report) internal override { ReserveManager.UpdateReserves memory updateReservesData = abi.decode(report, (ReserveManager.UpdateReserves)); s_reserveManager.updateReserves(updateReservesData); @@ -545,16 +478,13 @@ contract UpdateReservesProxy is IReceiverTemplate { **Configuring permissions after deployment:** ```solidity -// Enable forwarder check (recommended) -updateReservesProxy.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia - -// Enable workflow ID check for production (highest security) +// Additional validation can be added after deployment updateReservesProxy.setExpectedWorkflowId(0xYourWorkflowId...); ``` {/* prettier-ignore */} <Aside type="note" title="KeystoneForwarder address shown"> - The examples above use the Ethereum Sepolia forwarder address. For other networks, see [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks). + The examples above use the Ethereum Sepolia forwarder address. For other networks, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). </Aside> #### How it Works @@ -562,7 +492,7 @@ updateReservesProxy.setExpectedWorkflowId(0xYourWorkflowId...); The deployment and configuration process involves these steps: 1. **Deploy the Logic Contract**: Deploy `ReserveManager.sol`. The wallet that deploys this contract becomes its `owner`. -1. **Deploy the Proxy Contract**: Deploy `UpdateReservesProxy.sol`, passing the address of the deployed `ReserveManager` contract to its constructor. +1. **Deploy the Proxy Contract**: Deploy `UpdateReservesProxy.sol`, passing the forwarder address and the address of the deployed `ReserveManager` contract to its constructor. 1. **Link the Contracts**: The `owner` of the `ReserveManager` contract must call its `setProxyAddress` function, passing in the address of the `UpdateReservesProxy` contract. This authorizes the proxy to call the logic contract. 1. **Configure Permissions** (Recommended): The `owner` of the proxy should call setter functions to enable security checks: ```solidity @@ -572,11 +502,11 @@ The deployment and configuration process involves these steps: 1. **Configure Workflow**: In your workflow's `config.json`, use the address of the **Proxy Contract** as the receiver address. 1. **Execution Flow**: When your workflow runs: - The Chainlink Forwarder calls `onReport` on your **Proxy** - - The Proxy validates the report (forwarder address, workflow ID, etc.) + - The Proxy validates the report (forwarder address is verified automatically; additional checks like workflow ID can be added) - The Proxy's `_processReport` function calls the `updateReserves` function on your **Logic Contract** - Because the caller is the trusted proxy, the `onlyProxy` check passes, and your state is securely updated 1. **(Optional) Upgrade**: If you later need to deploy a new proxy, the owner can: - - Deploy the new proxy contract + - Deploy the new proxy contract with the appropriate forwarder address - Call `setProxyAddress` on the `ReserveManager` to point it to the new proxy's address - Update the workflow configuration to use the new proxy address @@ -584,8 +514,54 @@ The deployment and configuration process involves these steps: <ClickToZoom src="/images/cre/consumer-contracts-proxy-pattern.png" alt="Building Consumer Contracts: Proxy Pattern" /> -## Where to go next? +## 7. Security Considerations + +### Forwarder address + +**The forwarder address is the foundation of your contract's security.** The `KeystoneForwarder` contract performs cryptographic verification of DON signatures before calling your consumer. By requiring the forwarder address in the constructor, `ReceiverTemplate` ensures your contract is secure from deployment. + +{/* prettier-ignore */} +<Aside type="caution" title="Never set forwarder to address(0) in production"> + While the `setForwarderAddress()` function allows updating to `address(0)`, this disables the critical security check and allows **anyone** to call your `onReport()` function with arbitrary data. The function emits a `SecurityWarning` event if you attempt this. Only use `address(0)` for testing if you fully understand the implications. +</Aside> + +### Replay protection + +The `KeystoneForwarder` contract includes built-in replay protection that prevents successful reports from being executed multiple times. By requiring the forwarder address at construction time, `ReceiverTemplate` ensures your consumer benefits from this protection automatically. + +{/* prettier-ignore */} +<Aside type="note" title="Failed reports can be retried"> + If a report fails (reverts), the forwarder's replay protection allows it to be retried. This is safe because reverts undo all state changes, ensuring no duplicate effects occur in your contract. +</Aside> + +### Additional validation layers + +The forwarder address provides baseline security, but you can add additional validation for defense-in-depth: + +- **`expectedWorkflowId`**: Ensures only one specific workflow can update your contract. Use this when a single workflow writes to your consumer (highest security for single-workflow scenarios). +- **`expectedAuthor`**: Restricts to workflows owned by a specific address. Use this when multiple workflows from the same owner should access your contract. +- **`expectedWorkflowName`**: Can be used in combination with `expectedAuthor` for additional validation. Requires author validation to be configured. See [Workflow name validation](#workflow-name-validation) below. + +### Workflow name validation + +{/* prettier-ignore */} +<Aside type="caution" title="Workflow name validation requires author validation"> + The `expectedWorkflowName` check in `ReceiverTemplate.onReport()` **requires author validation** to be configured: + + - **Collision Risk**: Workflow names use only 40-bit truncation (bytes10), making collision attacks computationally feasible when used alone + - **Unique per owner**: Workflow names are unique per owner but not across different owners + - **Runtime enforcement**: The code enforces that if `expectedWorkflowName` is set, `expectedAuthor` must also be set, otherwise it reverts with `WorkflowNameRequiresAuthorValidation()` + + By combining workflow name (40-bit) with author validation (160-bit address), the contract achieves adequate collision resistance. You can safely use workflow name validation as long as author validation is also enabled. +</Aside> -Now that you know how to build a consumer contract, the next step is to call it from your workflow. +### Best practices -- **[Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write)**: Learn how to use the `EVMClient` to send data to your new consumer contract. +1. **Always deploy with a valid forwarder address** - The constructor requires this for security. Use `MockForwarder` for simulation, `KeystoneForwarder` for production. Forwarder addresses are available in the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) page. +1. **Add additional validation for production**: + - **Single workflow**: Use `setExpectedWorkflowId()` to restrict to one specific workflow (highest security) + - **Multiple workflows from same owner**: Use `setExpectedAuthor()` to restrict to workflows you own + - **Multiple workflows from different owners**: Implement custom validation logic in your `onReport()` override +1. **Keep your owner key secure** - The owner can update all permission settings +1. **Test permission configurations** - Verify your security settings work as expected before production deployment +1. **Workflow name validation** - Can be used with `setExpectedWorkflowName()` but requires `setExpectedAuthor()` to also be configured for security diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx index 235046d3551..ff25a277d36 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx @@ -250,7 +250,7 @@ func main() { ## Learn more -- **[Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write)**: Understand all onchain write approaches +- **[Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview)**: Understand all onchain write approaches - **[Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain)**: Submit your generated report to the blockchain - **[Generating Reports: Structs](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-structs)**: Manually encode and generate reports for struct data - **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Create contracts that can receive your reports diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-write/overview-go.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-write/overview-go.mdx index 0ee855ddada..125cc10a3db 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-write/overview-go.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-write/overview-go.mdx @@ -180,7 +180,7 @@ max := big.NewInt(1000) randomValue := new(big.Int).Rand(rnd, max) ``` -**Note**: For a complete understanding of how randomness works in CRE, including the difference between DON mode and Node mode randomness, see [Random in CRE](/cre/concepts/random-in-cre). +**Note**: For a complete understanding of how randomness works in CRE, including the difference between DON mode and Node mode randomness, see [Using Randomness in Workflows](/cre/guides/workflow/using-randomness). ### Constructing input structs diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain.mdx index 2e108704895..c7a230a597f 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain.mdx @@ -258,7 +258,7 @@ By default, `cre workflow simulate` performs a dry run without broadcasting tran cre workflow simulate my-workflow --broadcast --target staging-settings ``` -See the [CLI Reference](/cre/reference/cli#cre-workflow-simulate) for more details. +See the [CLI Reference](/cre/reference/cli/workflow#cre-workflow-simulate) for more details. ## Troubleshooting diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-write/using-write-report-helpers.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-write/using-write-report-helpers.mdx index 9bc7e2d3916..34a91b3a53a 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-write/using-write-report-helpers.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-write/using-write-report-helpers.mdx @@ -18,7 +18,7 @@ This guide explains how to write data to a smart contract using the `WriteReport - You're sending a **struct** to your consumer contract - The struct appears in a `public` or `external` function's signature (as a parameter or return value); this is required for the binding generator to detect it in your contract's ABI and create the helper method -**Don't meet these requirements?** See the [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write#choosing-your-approach-which-guide-should-you-follow) page to find the right approach for your scenario. +**Don't meet these requirements?** See the [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview-go#choosing-your-approach-which-guide-should-you-follow) page to find the right approach for your scenario. ## Prerequisites diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain.mdx index 45b8f4da95b..ac97779cba8 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain.mdx @@ -6,7 +6,7 @@ date: Last Modified metadata: description: "Write workflow results to the blockchain in TypeScript: complete guide to generating and submitting verified data to smart contracts." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside } from "@components" @@ -69,7 +69,7 @@ This example shows how to write a single `uint256` value to your consumer contra ### Step 1: Set up your imports ```typescript -import { cre, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime } from "@chainlink/cre-sdk" import { encodeAbiParameters, parseAbiParameters } from "viem" ``` @@ -88,9 +88,21 @@ const reportData = encodeAbiParameters(parseAbiParameters("address"), ["0x123456 const reportData = encodeAbiParameters(parseAbiParameters("bool"), [true]) ``` -<Aside type="note" title="BigInt literals"> - Use the `n` suffix for integer literals to create `bigint` values in TypeScript. This is required for **all** Solidity - integer types (`uint8`, `uint256`, `int8`, `int256`, etc.) when using viem: `12345n`, `1000000000000000000n`, etc. +{/* prettier-ignore */} +<Aside type="caution" title="Always use bigint for Solidity integers"> + JavaScript `number` loses precision for values above ~9 quadrillion (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER" target="_blank" rel="noopener noreferrer">Number.MAX_SAFE_INTEGER</a>). This causes **silent precision loss** — your workflow sends the wrong value without any error. + +**Always use `bigint`** (with the `n` suffix) for all Solidity integer types: `12345n`, `1000000000000000000n`, etc. + +```typescript +// WRONG - silent precision loss +const amount = 10000000000000001 // 10 quadrillion + 1 +// Silently becomes 10000000000000000 (the +1 vanishes) + +// CORRECT - use bigint +const amount = 10000000000000001n // Stays exactly 10000000000000001 +``` + </Aside> ### Step 3: Generate the signed report @@ -270,7 +282,7 @@ export { CalculatorResultParams, type CalculatorResult } from "./ConsumerContrac Now you can import and use these definitions in your workflow: ```typescript -import { cre, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime } from "@chainlink/cre-sdk" import { encodeAbiParameters } from "viem" import { CalculatorResultParams, type CalculatorResult } from "../contracts/abi" @@ -285,7 +297,7 @@ const writeDataOnchain = (runtime: Runtime<Config>): string => { throw new Error(`Network not found`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) // Create type-safe data object const data: CalculatorResult = { @@ -357,7 +369,16 @@ Here's a full workflow that writes a struct to a consumer contract: ### Workflow code (`main.ts`) ```typescript -import { cre, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime, Runner } from "@chainlink/cre-sdk" +import { + CronCapability, + EVMClient, + getNetwork, + hexToBase64, + bytesToHex, + TxStatus, + type Runtime, + Runner, +} from "@chainlink/cre-sdk" import { encodeAbiParameters, parseAbiParameters } from "viem" import { z } from "zod" @@ -384,7 +405,7 @@ const writeDataOnchain = (runtime: Runtime<Config>): string => { } // Create EVM client - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) // 1. Encode your data (struct with 3 fields) const reportData = encodeAbiParameters( @@ -428,9 +449,10 @@ const writeDataOnchain = (runtime: Runtime<Config>): string => { } const initWorkflow = (config: Config) => { + const cron = new CronCapability() return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + cron.handler( + cron.trigger({ schedule: config.schedule, }), writeDataOnchain @@ -442,8 +464,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Working with complex types diff --git a/src/content/cre/guides/workflow/using-evm-client/overview-go.mdx b/src/content/cre/guides/workflow/using-evm-client/overview-go.mdx index 0498cc062a4..9fe2e6dd5a5 100644 --- a/src/content/cre/guides/workflow/using-evm-client/overview-go.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/overview-go.mdx @@ -29,5 +29,5 @@ This approach gives you IDE autocompletion, compile-time type checking, and elim - **[Generating Contract Bindings](/cre/guides/workflow/using-evm-client/generating-bindings)**: Learn how to generate type-safe Go bindings from contract ABIs using the CRE CLI - **[Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read)**: Learn how to call `view` and `pure` functions on your smart contracts to read onchain state -- **[Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write)**: Learn how to call state-changing functions on your smart contracts to write data to the blockchain +- **[Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview)**: Learn how to call state-changing functions on your smart contracts to write data to the blockchain - **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Learn how to write your own consumer contracts that can receive reports from your workflow diff --git a/src/content/cre/guides/workflow/using-evm-client/supported-networks-go.mdx b/src/content/cre/guides/workflow/using-evm-client/supported-networks-go.mdx deleted file mode 100644 index f63bada249b..00000000000 --- a/src/content/cre/guides/workflow/using-evm-client/supported-networks-go.mdx +++ /dev/null @@ -1,96 +0,0 @@ ---- -section: cre -title: "Supported Networks" -date: Last Modified -sdkLang: "go" -pageId: "evm-supported-networks" -metadata: - description: "Learn which EVM networks are supported for read and write operations in CRE workflows." - datePublished: "2025-11-04" - lastModified: "2025-11-20" ---- - -import { Aside, CopyText } from "@components" - -This page lists the EVM-compatible networks supported by CRE workflows, along with their chain names (for configuration) and forwarder contract addresses (for consumer contract validation). - -## How to Use This Page - -This reference provides three key pieces of information for each network: - -1. **Network Name**: The human-readable network identifier -1. **Chain Name**: The value to use in your [`project.yaml`](/cre/reference/project-configuration-go#31-global-configuration-projectyaml) configuration and [EVM Client code](/cre/reference/sdk/evm-client-go#chain-selectors) -1. **Forwarder Address**: The contract address for optional consumer contract validation - -## Understanding Forwarder Addresses - -Forwarder addresses are relevant **only if you want to add security validation to your consumer contracts**. Your workflow code does not interact with forwarders directly—the EVM capability handles report delivery automatically. Learn more: [Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview-go). - -**Optional security layer**: You can configure your consumer contract's `onReport()` function to accept calls only from the trusted forwarder address. See [Configuring Permissions](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#34-configuring-permissions) for implementation details. - -### Simulation vs Production Addresses - -**Important**: Forwarder contracts differ between local simulation and production: - -| Environment | Contract Type | Section | -| ---------------- | ----------------------- | ----------------------------------------------- | -| Local simulation | `MockKeystoneForwarder` | [Simulation Forwarders](#simulation-forwarders) | -| Production | `KeystoneForwarder` | [Production Forwarders](#production-forwarders) | - -If you configure forwarder validation in your consumer contract, **remember to update the forwarder address** when deploying to production. Learn more: [Working with Simulation](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#4-working-with-simulation). - -## Simulation Forwarders - -These `MockKeystoneForwarder` addresses are used when running `cre workflow simulate` with the `--broadcast` flag. Use these addresses **only** during local development and testing. - -### Simulation Mainnets - -| Network | Chain Name | Mock Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------ | -| <a href="https://arbiscan.io/address/0xd770499057619c9a76205fd4168161cf94abc532" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | <CopyText text="ethereum-mainnet-arbitrum-1" code/> | <CopyText text="0xd770499057619c9a76205fd4168161cf94abc532" code/> | -| <a href="https://snowscan.xyz/address/0xdc21e279934ff6721cadfdd112dafb3261f09a2c" target="_blank" rel="noopener noreferrer">Avalanche</a> | <CopyText text="avalanche-mainnet" code/> | <CopyText text="0xdc21e279934ff6721cadfdd112dafb3261f09a2c" code/> | -| <a href="https://basescan.org/address/0x5e342a8438b4f5d39e72875fcee6f76b39cce548" target="_blank" rel="noopener noreferrer">Base</a> | <CopyText text="ethereum-mainnet-base-1" code/> | <CopyText text="0x5e342a8438b4f5d39e72875fcee6f76b39cce548" code/> | -| <a href="https://bscscan.com/address/0x6f3239bbb26e98961e1115aba83f8a282e5508c8" target="_blank" rel="noopener noreferrer">BNB Chain</a> | <CopyText text="binance_smart_chain-mainnet" code/> | <CopyText text="0x6f3239bbb26e98961e1115aba83f8a282e5508c8" code/> | -| <a href="https://etherscan.io/address/0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | <CopyText text="ethereum-mainnet" code/> | <CopyText text="0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" code/> | -| <a href="https://optimistic.etherscan.io/address/0x9119a1501550ed94a3f2794038ed9258337afa18" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | <CopyText text="ethereum-mainnet-optimism-1" code/> | <CopyText text="0x9119a1501550ed94a3f2794038ed9258337afa18" code/> | -| <a href="https://polygonscan.com/address/0xf458d621885e29a5003ea9bbba5280d54e19b1ce" target="_blank" rel="noopener noreferrer">Polygon</a> | <CopyText text="polygon-mainnet" code/> | <CopyText text="0xf458d621885e29a5003ea9bbba5280d54e19b1ce" code/> | - -### Simulation Testnets - -| Network | Chain Name | Mock Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------ | -| <a href="https://sepolia.arbiscan.io/address/0xd41263567ddfead91504199b8c6c87371e83ca5d" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code/> | <CopyText text="0xd41263567ddfead91504199b8c6c87371e83ca5d" code/> | -| <a href="https://testnet.snowscan.xyz/address/0x2e7371a5d032489e4f60216d8d898a4c10805963" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | <CopyText text="avalanche-testnet-fuji" code/> | <CopyText text="0x2e7371a5d032489e4f60216d8d898a4c10805963" code/> | -| <a href="https://sepolia.basescan.org/address/0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-base-1" code/> | <CopyText text="0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" code/> | -| <a href="https://testnet.bscscan.com/address/0xa238e42cb8782808dbb2f37e19859244ec4779b0" target="_blank" rel="noopener noreferrer">BNB Chain Testnet</a> | <CopyText text="binance_smart_chain-testnet" code/> | <CopyText text="0xa238e42cb8782808dbb2f37e19859244ec4779b0" code/> | -| <a href="https://sepolia.etherscan.io/address/0x15fC6ae953E024d975e77382eEeC56A9101f9F88" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia" code/> | <CopyText text="0x15fC6ae953E024d975e77382eEeC56A9101f9F88" code/> | -| <a href="https://sepolia-optimism.etherscan.io/address/0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-optimism-1" code/> | <CopyText text="0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" code/> | -| <a href="https://amoy.polygonscan.com/address/0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | <CopyText text="polygon-testnet-amoy" code/> | <CopyText text="0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" code/> | - -## Production Forwarders - -These `KeystoneForwarder` addresses are used by deployed workflows. Use these addresses when configuring your consumer contracts for production. - -### Mainnets - -| Network | Chain Name | Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------ | -| <a href="https://arbiscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | <CopyText text="ethereum-mainnet-arbitrum-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche</a> | <CopyText text="avalanche-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base</a> | <CopyText text="ethereum-mainnet-base-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Chain</a> | <CopyText text="binance_smart_chain-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://etherscan.io/address/0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | <CopyText text="ethereum-mainnet" code/> | <CopyText text="0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" code/> | -| <a href="https://optimistic.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | <CopyText text="ethereum-mainnet-optimism-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon</a> | <CopyText text="polygon-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | - -### Testnets - -| Network | Chain Name | Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------ | -| <a href="https://sepolia.arbiscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://testnet.snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | <CopyText text="avalanche-testnet-fuji" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://sepolia.basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-base-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://testnet.bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Chain Testnet</a> | <CopyText text="binance_smart_chain-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://sepolia.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://sepolia-optimism.etherscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-optimism-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://amoy.polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | <CopyText text="polygon-testnet-amoy" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | diff --git a/src/content/cre/guides/workflow/using-evm-client/supported-networks-ts.mdx b/src/content/cre/guides/workflow/using-evm-client/supported-networks-ts.mdx deleted file mode 100644 index a2949f98d40..00000000000 --- a/src/content/cre/guides/workflow/using-evm-client/supported-networks-ts.mdx +++ /dev/null @@ -1,96 +0,0 @@ ---- -section: cre -title: "Supported Networks" -date: Last Modified -sdkLang: "ts" -pageId: "evm-supported-networks" -metadata: - description: "Learn which EVM networks are supported for read and write operations in CRE workflows." - datePublished: "2025-11-04" - lastModified: "2025-11-20" ---- - -import { Aside, CopyText } from "@components" - -This page lists the EVM-compatible networks supported by CRE workflows, along with their chain names (for configuration) and forwarder contract addresses (for consumer contract validation). - -## How to Use This Page - -This reference provides three key pieces of information for each network: - -1. **Network Name**: The human-readable network identifier (click to view the forwarder contract on the block explorer) -2. **Chain Name**: The value to use in your [`project.yaml`](/cre/reference/project-configuration-ts#31-global-configuration-projectyaml) configuration and [EVM Client code](/cre/reference/sdk/evm-client-ts#chain-selectors) -3. **Forwarder Address**: The contract address for optional consumer contract validation (click to copy) - -## Understanding Forwarder Addresses - -Forwarder addresses are relevant **only if you want to add security validation to your consumer contracts**. Your workflow code does not interact with forwarders directly—the EVM capability handles report delivery automatically. Learn more: [Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview-ts). - -**Optional security layer**: You can configure your consumer contract's `onReport()` function to accept calls only from the trusted forwarder address. See [Configuring Permissions](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#34-configuring-permissions) for implementation details. - -### Simulation vs Production Addresses - -**Important**: Forwarder contracts differ between local simulation and production: - -| Environment | Contract Type | Section | -| ---------------- | ----------------------- | ----------------------------------------------- | -| Local simulation | `MockKeystoneForwarder` | [Simulation Forwarders](#simulation-forwarders) | -| Production | `KeystoneForwarder` | [Production Forwarders](#production-forwarders) | - -If you configure forwarder validation in your consumer contract, **remember to update the forwarder address** when deploying to production. Learn more: [Working with Simulation](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#4-working-with-simulation). - -## Simulation Forwarders - -These `MockKeystoneForwarder` addresses are used when running `cre workflow simulate` with the `--broadcast` flag. Use these addresses **only** during local development and testing. - -### Simulation Mainnets - -| Network | Chain Name | Mock Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------ | -| <a href="https://arbiscan.io/address/0xd770499057619c9a76205fd4168161cf94abc532" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | <CopyText text="ethereum-mainnet-arbitrum-1" code/> | <CopyText text="0xd770499057619c9a76205fd4168161cf94abc532" code/> | -| <a href="https://snowscan.xyz/address/0xdc21e279934ff6721cadfdd112dafb3261f09a2c" target="_blank" rel="noopener noreferrer">Avalanche</a> | <CopyText text="avalanche-mainnet" code/> | <CopyText text="0xdc21e279934ff6721cadfdd112dafb3261f09a2c" code/> | -| <a href="https://basescan.org/address/0x5e342a8438b4f5d39e72875fcee6f76b39cce548" target="_blank" rel="noopener noreferrer">Base</a> | <CopyText text="ethereum-mainnet-base-1" code/> | <CopyText text="0x5e342a8438b4f5d39e72875fcee6f76b39cce548" code/> | -| <a href="https://bscscan.com/address/0x6f3239bbb26e98961e1115aba83f8a282e5508c8" target="_blank" rel="noopener noreferrer">BNB Smart Chain</a> | <CopyText text="binance_smart_chain-mainnet" code/> | <CopyText text="0x6f3239bbb26e98961e1115aba83f8a282e5508c8" code/> | -| <a href="https://etherscan.io/address/0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | <CopyText text="ethereum-mainnet" code/> | <CopyText text="0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" code/> | -| <a href="https://optimistic.etherscan.io/address/0x9119a1501550ed94a3f2794038ed9258337afa18" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | <CopyText text="ethereum-mainnet-optimism-1" code/> | <CopyText text="0x9119a1501550ed94a3f2794038ed9258337afa18" code/> | -| <a href="https://polygonscan.com/address/0xf458d621885e29a5003ea9bbba5280d54e19b1ce" target="_blank" rel="noopener noreferrer">Polygon</a> | <CopyText text="polygon-mainnet" code/> | <CopyText text="0xf458d621885e29a5003ea9bbba5280d54e19b1ce" code/> | - -### Simulation Testnets - -| Network | Chain Name | Mock Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------ | -| <a href="https://sepolia.arbiscan.io/address/0xd41263567ddfead91504199b8c6c87371e83ca5d" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code/> | <CopyText text="0xd41263567ddfead91504199b8c6c87371e83ca5d" code/> | -| <a href="https://testnet.snowscan.xyz/address/0x2e7371a5d032489e4f60216d8d898a4c10805963" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | <CopyText text="avalanche-testnet-fuji" code/> | <CopyText text="0x2e7371a5d032489e4f60216d8d898a4c10805963" code/> | -| <a href="https://sepolia.basescan.org/address/0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-base-1" code/> | <CopyText text="0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" code/> | -| <a href="https://testnet.bscscan.com/address/0xa238e42cb8782808dbb2f37e19859244ec4779b0" target="_blank" rel="noopener noreferrer">BSC Testnet</a> | <CopyText text="binance_smart_chain-testnet" code/> | <CopyText text="0xa238e42cb8782808dbb2f37e19859244ec4779b0" code/> | -| <a href="https://sepolia.etherscan.io/address/0x15fC6ae953E024d975e77382eEeC56A9101f9F88" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia" code/> | <CopyText text="0x15fC6ae953E024d975e77382eEeC56A9101f9F88" code/> | -| <a href="https://sepolia-optimism.etherscan.io/address/0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-optimism-1" code/> | <CopyText text="0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" code/> | -| <a href="https://amoy.polygonscan.com/address/0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | <CopyText text="polygon-testnet-amoy" code/> | <CopyText text="0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" code/> | - -## Production Forwarders - -These `KeystoneForwarder` addresses are used by deployed workflows. Use these addresses when configuring your consumer contracts for production. - -### Mainnets - -| Network | Chain Name | Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------ | -| <a href="https://arbiscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | <CopyText text="ethereum-mainnet-arbitrum-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche</a> | <CopyText text="avalanche-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base</a> | <CopyText text="ethereum-mainnet-base-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Smart Chain</a> | <CopyText text="binance_smart_chain-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://etherscan.io/address/0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | <CopyText text="ethereum-mainnet" code/> | <CopyText text="0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" code/> | -| <a href="https://optimistic.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | <CopyText text="ethereum-mainnet-optimism-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon</a> | <CopyText text="polygon-mainnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | - -### Testnets - -| Network | Chain Name | Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------ | -| <a href="https://sepolia.arbiscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://testnet.snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | <CopyText text="avalanche-testnet-fuji" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://sepolia.basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-base-1" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://testnet.bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BSC Testnet</a> | <CopyText text="binance_smart_chain-testnet" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://sepolia.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | <CopyText text="ethereum-testnet-sepolia" code/> | <CopyText text="0xF8344CFd5c43616a4366C34E3EEE75af79a74482" code/> | -| <a href="https://sepolia-optimism.etherscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | <CopyText text="ethereum-testnet-sepolia-optimism-1" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | -| <a href="https://amoy.polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | <CopyText text="polygon-testnet-amoy" code/> | <CopyText text="0x76c9cf548b4179F8901cda1f8623568b58215E62" code/> | diff --git a/src/content/cre/guides/workflow/using-http-client/get-request-go.mdx b/src/content/cre/guides/workflow/using-http-client/get-request-go.mdx index 40dc67fe131..0af264b455c 100644 --- a/src/content/cre/guides/workflow/using-http-client/get-request-go.mdx +++ b/src/content/cre/guides/workflow/using-http-client/get-request-go.mdx @@ -7,7 +7,7 @@ pageId: "guides-workflow-http-get-request" metadata: description: "Fetch data from APIs in Go: learn to make GET requests with consensus validation to bring offchain data into your workflow." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside } from "@components" @@ -17,12 +17,22 @@ The `http.Client` is the SDK's interface for the underlying [HTTP Capability](/c All HTTP requests are wrapped in a consensus mechanism to provide a single, reliable result. The SDK provides two ways to do this: - **[`http.SendRequest`](#1-the-httpsendrequest-pattern-recommended):** (Recommended) A high-level helper function that simplifies making requests. -- **[`cre.RunInNodeMode`](#2-the-cre-runinnodemode-pattern-low-level):** The lower-level pattern for more complex scenarios. +- **[`cre.RunInNodeMode`](#2-the-creruninnodemode-pattern-low-level):** The lower-level pattern for more complex scenarios. ## Prerequisites This guide assumes you have a basic understanding of CRE. If you are new, we strongly recommend completing the [Getting Started tutorial](/cre/getting-started/overview) first. +{/* prettier-ignore */} +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + +{/* prettier-ignore */} +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.Now()` instead of `time.Now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + ## Choosing your approach ### Use `http.SendRequest` (Section 1) when: diff --git a/src/content/cre/guides/workflow/using-http-client/get-request-ts.mdx b/src/content/cre/guides/workflow/using-http-client/get-request-ts.mdx index d5354da076d..c7efc0e4eae 100644 --- a/src/content/cre/guides/workflow/using-http-client/get-request-ts.mdx +++ b/src/content/cre/guides/workflow/using-http-client/get-request-ts.mdx @@ -7,7 +7,7 @@ pageId: "guides-workflow-http-get-request" metadata: description: "Fetch data from APIs in TypeScript: learn to make GET requests with consensus validation to bring offchain data into your workflow." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside } from "@components" @@ -23,6 +23,16 @@ All HTTP requests are wrapped in a consensus mechanism to provide a single, reli This guide assumes you have a basic understanding of CRE. If you are new, we strongly recommend completing the [Getting Started tutorial](/cre/getting-started/overview) first. +{/* prettier-ignore */} +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + +{/* prettier-ignore */} +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.now()` instead of `Date.now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + ## Choosing your approach ### Use `sendRequest` (Section 1) when: @@ -75,7 +85,7 @@ Add the API URL to your `config.json` file. Define TypeScript types for the API response and your internal data model. ```typescript -import { cre, type Runtime, type HTTPSendRequester, Runner } from "@chainlink/cre-sdk" +import { HTTPClient, type Runtime, type HTTPSendRequester, Runner } from "@chainlink/cre-sdk" import { z } from "zod" // Config schema @@ -137,17 +147,19 @@ const fetchAndParse = (sendRequester: HTTPSendRequester, config: Config): PriceD In your `onCronTrigger` handler, call `httpClient.sendRequest()`. This returns a function that you call with `runtime.config`. ```typescript +import { HTTPClient, ConsensusAggregationByFields, median, type Runtime } from "@chainlink/cre-sdk" + const onCronTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // sendRequest returns a function that we call with runtime.config const result = httpClient .sendRequest( runtime, fetchAndParse, - new cre.consensus.ConsensusAggregationByFields<PriceData>({ - price: cre.consensus.median<number>(), - lastUpdated: cre.consensus.median<Date>(), + ConsensusAggregationByFields<PriceData>({ + price: median<number>(), + lastUpdated: median<Date>(), }) )(runtime.config) // Call the returned function with config .result() @@ -163,7 +175,16 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { Here's the full workflow code: ```typescript -import { cre, type Runtime, type HTTPSendRequester, Runner } from "@chainlink/cre-sdk" +import { + CronCapability, + HTTPClient, + handler, + ConsensusAggregationByFields, + median, + type Runtime, + type HTTPSendRequester, + Runner, +} from "@chainlink/cre-sdk" import { z } from "zod" // Config schema @@ -211,15 +232,15 @@ const fetchAndParse = (sendRequester: HTTPSendRequester, config: Config): PriceD // Main workflow handler const onCronTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const result = httpClient .sendRequest( runtime, fetchAndParse, - new cre.consensus.ConsensusAggregationByFields<PriceData>({ - price: cre.consensus.median<number>(), - lastUpdated: cre.consensus.median<Date>(), + ConsensusAggregationByFields<PriceData>({ + price: median<number>(), + lastUpdated: median<Date>(), }) )(runtime.config) // Call with config .result() @@ -232,8 +253,8 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { // Initialize workflow const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -245,8 +266,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## 2. The `runInNodeMode` Pattern (Low-Level) @@ -261,7 +280,16 @@ The pattern works like a "map-reduce" for the DON: The example below is functionally identical to the `sendRequest` example above, but implemented using the low-level pattern. ```typescript -import { cre, type Runtime, type NodeRuntime, Runner } from "@chainlink/cre-sdk" +import { + CronCapability, + HTTPClient, + handler, + ConsensusAggregationByFields, + median, + type Runtime, + type NodeRuntime, + Runner, +} from "@chainlink/cre-sdk" import { z } from "zod" // Config and types (same as before) @@ -287,7 +315,7 @@ type ExternalApiResponse = { // fetchPriceData is a function that runs on each individual node const fetchPriceData = (nodeRuntime: NodeRuntime<Config>): PriceData => { // 1. Create HTTP client and fetch raw data - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const req = { url: nodeRuntime.config.apiUrl, @@ -315,9 +343,9 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { const result = runtime .runInNodeMode( fetchPriceData, - new cre.consensus.ConsensusAggregationByFields<PriceData>({ - price: cre.consensus.median<number>(), - lastUpdated: cre.consensus.median<Date>(), + ConsensusAggregationByFields<PriceData>({ + price: median<number>(), + lastUpdated: median<Date>(), }) )() .result() @@ -330,8 +358,8 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { // Initialize workflow (same as before) const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -343,8 +371,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Response helper functions @@ -357,5 +383,5 @@ The request object provides several fields to customize your HTTP call. See the - **Headers**: Custom HTTP headers - **Body**: Request payload (for POST, PUT, etc.) -- **Timeout**: Request timeout in milliseconds +- **Timeout**: Request timeout as a duration string in seconds (e.g., `"5s"`, `"8s"`) - **Cache settings**: Control response caching behavior diff --git a/src/content/cre/guides/workflow/using-http-client/index.mdx b/src/content/cre/guides/workflow/using-http-client/index.mdx index 3ec5577bb61..903b8a1a7ff 100644 --- a/src/content/cre/guides/workflow/using-http-client/index.mdx +++ b/src/content/cre/guides/workflow/using-http-client/index.mdx @@ -6,11 +6,18 @@ isIndex: true metadata: description: "Connect your workflow to external APIs: learn to make GET and POST requests with built-in consensus for secure offchain data." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- +import { Aside } from "@components" + The CRE SDK provides an HTTP client that allows your workflows to interact with external APIs. Use it to fetch offchain data, send results to other systems, or trigger external events. +{/* prettier-ignore */} +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.now()` instead of `Date.now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + These guides will walk you through the common use cases for the HTTP client. ## Guides diff --git a/src/content/cre/guides/workflow/using-http-client/post-request-go.mdx b/src/content/cre/guides/workflow/using-http-client/post-request-go.mdx index 4b5cb4e3542..008586c4798 100644 --- a/src/content/cre/guides/workflow/using-http-client/post-request-go.mdx +++ b/src/content/cre/guides/workflow/using-http-client/post-request-go.mdx @@ -7,7 +7,7 @@ pageId: "guides-workflow-http-post-request" metadata: description: "Send data to external APIs in Go: learn to make POST requests from your workflow with authentication and custom headers." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside } from "@components" @@ -26,6 +26,11 @@ All HTTP requests are wrapped in a consensus mechanism. The SDK provides two way - **[`http.SendRequest`](#1-the-httpsendrequest-pattern-recommended):** A high-level helper function that simplifies making requests. This is the recommended approach for most use cases. - **[`cre.RunInNodeMode`](#2-the-cre-runinnodemode-pattern-low-level):** The lower-level pattern for more complex scenarios. +{/* prettier-ignore */} +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.Now()` instead of `time.Now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + ## Choosing your approach ### Use `http.SendRequest` (Section 1) when: @@ -52,6 +57,11 @@ For this example, we will use <a href="https://webhook.site/" target="_blank">** This guide assumes you have a basic understanding of CRE. If you are new, we strongly recommend completing the [Getting Started tutorial](/cre/getting-started/overview) first. +{/* prettier-ignore */} +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + ## 1. The `http.SendRequest` Pattern (recommended) The `http.SendRequest` helper function is the simplest and recommended way to make `POST` requests. It automatically handles the `cre.RunInNodeMode` pattern for you. diff --git a/src/content/cre/guides/workflow/using-http-client/post-request-ts.mdx b/src/content/cre/guides/workflow/using-http-client/post-request-ts.mdx index f78ef48d0e6..6821e38c348 100644 --- a/src/content/cre/guides/workflow/using-http-client/post-request-ts.mdx +++ b/src/content/cre/guides/workflow/using-http-client/post-request-ts.mdx @@ -7,7 +7,7 @@ pageId: "guides-workflow-http-post-request" metadata: description: "Send data to external APIs in TypeScript: learn to make POST requests from your workflow with authentication and custom headers." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside } from "@components" @@ -26,6 +26,11 @@ All HTTP requests are wrapped in a consensus mechanism. The SDK provides two way - **[High-level `sendRequest`](#1-the-high-level-sendrequest-pattern-recommended):** A high-level helper method that simplifies making requests. This is the recommended approach for most use cases. - **[Low-level `runInNodeMode`](#2-the-low-level-runinnodemode-pattern):** The lower-level pattern for more complex scenarios. +{/* prettier-ignore */} +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.now()` instead of `Date.now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + ## Choosing your approach ### Use High-Level `sendRequest` (Section 1) when: @@ -52,6 +57,11 @@ For this example, we will use <a href="https://webhook.site/" target="_blank">** This guide assumes you have a basic understanding of CRE. If you are new, we strongly recommend completing the [Getting Started tutorial](/cre/getting-started/overview) first. +{/* prettier-ignore */} +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + ## 1. The High-Level `sendRequest` Pattern (recommended) The high-level `sendRequest()` method is the simplest and recommended way to make `POST` requests. It automatically handles the `runInNodeMode` pattern for you. @@ -102,7 +112,7 @@ In your `main.ts`, define the TypeScript types for your configuration and the da ```typescript import { - cre, + HTTPClient, ok, consensusIdenticalAggregation, type Runtime, @@ -179,8 +189,10 @@ const postData = (sendRequester: HTTPSendRequester, config: Config): PostRespons In your main `onCronTrigger` handler, call `httpClient.sendRequest()`, which returns a function that you call with `runtime.config`. ```typescript +import { HTTPClient, consensusIdenticalAggregation, type Runtime } from "@chainlink/cre-sdk" + const onCronTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const result = httpClient .sendRequest( @@ -200,10 +212,12 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { Finally, add the `initWorkflow` and `main` functions. ```typescript +import { CronCapability, handler, Runner } from "@chainlink/cre-sdk" + const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -217,15 +231,15 @@ export async function main() { }) await runner.run(initWorkflow) } - -main() ``` #### The complete workflow file ```typescript import { - cre, + CronCapability, + HTTPClient, + handler, ok, consensusIdenticalAggregation, type Runtime, @@ -291,7 +305,7 @@ const postData = (sendRequester: HTTPSendRequester, config: Config): PostRespons } const onCronTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const result = httpClient .sendRequest( @@ -307,8 +321,8 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -322,8 +336,6 @@ export async function main() { }) await runner.run(initWorkflow) } - -main() ``` ### Step 4: Run the simulation and verify @@ -364,7 +376,16 @@ For more complex scenarios, you can use the lower-level `runtime.runInNodeMode() Here's how to make a POST request with an API key from secrets: ```typescript -import { cre, ok, consensusIdenticalAggregation, type Runtime, type NodeRuntime, Runner } from "@chainlink/cre-sdk" +import { + CronCapability, + HTTPClient, + handler, + ok, + consensusIdenticalAggregation, + type Runtime, + type NodeRuntime, + Runner, +} from "@chainlink/cre-sdk" import { z } from "zod" // Config and types @@ -392,7 +413,7 @@ const postData = (nodeRuntime: NodeRuntime<Config>): PostResponse => { // Use the secret value const apiKey = secret.value - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // 2. Prepare the data const dataToSend: MyData = { @@ -440,8 +461,8 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -455,8 +476,6 @@ export async function main() { }) await runner.run(initWorkflow) } - -main() ``` ## Learn more diff --git a/src/content/cre/guides/workflow/using-http-client/submitting-reports-http-go.mdx b/src/content/cre/guides/workflow/using-http-client/submitting-reports-http-go.mdx index d499b28b905..33b1f6575ef 100644 --- a/src/content/cre/guides/workflow/using-http-client/submitting-reports-http-go.mdx +++ b/src/content/cre/guides/workflow/using-http-client/submitting-reports-http-go.mdx @@ -31,6 +31,11 @@ This guide shows how to send a cryptographically signed report (generated by you - Understanding of [generating reports](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) - A generated report from `runtime.GenerateReport()` +{/* prettier-ignore */} +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + ## Quick start: Minimal example Here's the simplest possible workflow that generates and submits a report via HTTP: @@ -124,7 +129,7 @@ Here are common patterns for formatting reports. Choose the one that matches you | Pattern | When to use | | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | | [**Pattern 1: Report in body**](#pattern-1-report-in-body-simplest) | Your API accepts raw binary data and handles decoding | -| [**Pattern 2: Report + signatures in body**](#pattern-2-report-signatures-in-body) | Your API needs everything concatenated in one binary blob | +| [**Pattern 2: Report + signatures in body**](#pattern-2-report--signatures-in-body) | Your API needs everything concatenated in one binary blob | | [**Pattern 3: Report in body, signatures in headers**](#pattern-3-report-in-body-signatures-in-headers) | Your API needs signatures separated for easier parsing | | [**Pattern 4: JSON-formatted report**](#pattern-4-json-formatted-report) | Your API only accepts JSON payloads | diff --git a/src/content/cre/guides/workflow/using-http-client/submitting-reports-http-ts.mdx b/src/content/cre/guides/workflow/using-http-client/submitting-reports-http-ts.mdx index 8df8c710036..eeb286668c6 100644 --- a/src/content/cre/guides/workflow/using-http-client/submitting-reports-http-ts.mdx +++ b/src/content/cre/guides/workflow/using-http-client/submitting-reports-http-ts.mdx @@ -7,7 +7,7 @@ pageId: "guides-workflow-http-submit-reports" metadata: description: "Send verified reports to external systems in TypeScript: learn to submit cryptographically signed workflow results via HTTP APIs." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside } from "@components" @@ -30,6 +30,11 @@ This guide shows how to send a cryptographically signed report (generated by you - Familiarity with [making POST requests](/cre/guides/workflow/using-http-client/post-request) - Familiarity with `runtime.report()` (covered [below](#generating-reports-for-http-submission)) +{/* prettier-ignore */} +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + ## Quick start: Minimal example Here's the simplest possible workflow that generates and submits a report via HTTP: @@ -126,7 +131,7 @@ Here are common patterns for formatting reports. Choose the one that matches you | Pattern | When to use | | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | | [**Pattern 1: Report in body**](#pattern-1-report-in-body-simplest) | Your API accepts raw binary data and handles decoding | -| [**Pattern 2: Report + signatures in body**](#pattern-2-report-signatures-in-body) | Your API needs everything concatenated in one binary blob | +| [**Pattern 2: Report + signatures in body**](#pattern-2-report--signatures-in-body) | Your API needs everything concatenated in one binary blob | | [**Pattern 3: Report in body, signatures in headers**](#pattern-3-report-in-body-signatures-in-headers) | Your API needs signatures separated for easier parsing | | [**Pattern 4: JSON-formatted report**](#pattern-4-json-formatted-report) | Your API only accepts JSON payloads | @@ -339,7 +344,7 @@ Use the high-level `httpClient.sendRequest()` pattern with `sendRequester.sendRe ```typescript import { - cre, + HTTPClient, consensusIdenticalAggregation, ok, type Runtime, @@ -364,7 +369,7 @@ const submitReportViaHTTP = (sendRequester: HTTPSendRequester, report: Report): // In your trigger callback const onCronTrigger = (runtime: Runtime<Config>): MyResult => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // Assume 'report' was generated earlier in your workflow @@ -391,7 +396,8 @@ This example shows a workflow that: ```typescript import { - cre, + CronCapability, + HTTPClient, Runner, consensusIdenticalAggregation, hexToBase64, @@ -417,9 +423,9 @@ interface SubmitResponse { type MyResult = Record<string, never> const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [cron.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } // Transformation function: defines how the API expects the report @@ -476,7 +482,7 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): MyResult runtime.log("Report generated successfully") // Step 2: Submit the report via HTTP - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const submitResult = httpClient .sendRequest( @@ -494,8 +500,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ### Configuration file (`config.json`) @@ -522,14 +526,21 @@ main() For complex scenarios where you need more control, use `clientCapability.sendReport()` with `runtime.runInNodeMode()`: ```typescript -import { cre, consensusIdenticalAggregation, ok, type Runtime, type NodeRuntime, type Report } from "@chainlink/cre-sdk" +import { + HTTPClient, + consensusIdenticalAggregation, + ok, + type Runtime, + type NodeRuntime, + type Report, +} from "@chainlink/cre-sdk" const onCronTrigger = (runtime: Runtime<Config>): MyResult => { // Assume 'report' was generated earlier const result = runtime .runInNodeMode((nodeRuntime: NodeRuntime<Config>) => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const response = httpClient.sendReport(nodeRuntime, report, formatReportSimple).result() diff --git a/src/content/cre/concepts/random-in-cre.mdx b/src/content/cre/guides/workflow/using-randomness.mdx similarity index 99% rename from src/content/cre/concepts/random-in-cre.mdx rename to src/content/cre/guides/workflow/using-randomness.mdx index 5c29596e986..6e378ea4064 100644 --- a/src/content/cre/concepts/random-in-cre.mdx +++ b/src/content/cre/guides/workflow/using-randomness.mdx @@ -1,12 +1,12 @@ --- section: cre -title: "Random in CRE" +title: "Using Randomness in Workflows" sdkLang: "go" date: Last Modified metadata: description: "Generate random numbers safely in CRE: use runtime.Rand() to ensure all nodes get the same values and maintain consensus." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-05" --- import { Aside } from "@components" diff --git a/src/content/cre/guides/workflow/using-triggers/cron-trigger-ts.mdx b/src/content/cre/guides/workflow/using-triggers/cron-trigger-ts.mdx index c119eb21a62..64442c3e33b 100644 --- a/src/content/cre/guides/workflow/using-triggers/cron-trigger-ts.mdx +++ b/src/content/cre/guides/workflow/using-triggers/cron-trigger-ts.mdx @@ -7,7 +7,7 @@ date: Last Modified metadata: description: "Schedule workflows with Cron in TypeScript: learn to run your workflow at specific times or intervals using cron expressions." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside } from "@components" @@ -52,7 +52,7 @@ The timezone-aware scheduler automatically handles daylight saving time transiti </Aside> ```typescript -import { cre, type Runtime, type CronPayload, Runner } from "@chainlink/cre-sdk" +import { CronCapability, handler, type Runtime, type CronPayload, Runner } from "@chainlink/cre-sdk" type Config = {} @@ -68,25 +68,23 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = const initWorkflow = (config: Config) => { // Create the trigger - fires every 30 seconds in UTC - const cronTrigger = new cre.capabilities.CronCapability().trigger({ + const cronTrigger = new CronCapability().trigger({ schedule: "*/30 * * * * *", }) // Or use a timezone-aware schedule - fires daily at 9 AM Eastern Time - // const cronTrigger = new cre.capabilities.CronCapability().trigger({ + // const cronTrigger = new CronCapability().trigger({ // schedule: "TZ=America/New_York 0 9 * * *", // }) // Register a handler with the trigger and a callback function - return [cre.handler(cronTrigger, onCronTrigger)] + return [handler(cronTrigger, onCronTrigger)] } export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Callback and payload diff --git a/src/content/cre/guides/workflow/using-triggers/evm-log-trigger-ts.mdx b/src/content/cre/guides/workflow/using-triggers/evm-log-trigger-ts.mdx index dba998b53d7..3b42720ac48 100644 --- a/src/content/cre/guides/workflow/using-triggers/evm-log-trigger-ts.mdx +++ b/src/content/cre/guides/workflow/using-triggers/evm-log-trigger-ts.mdx @@ -7,7 +7,7 @@ date: Last Modified metadata: description: "React to blockchain events in TypeScript: learn to trigger your workflow when smart contracts emit specific events on EVM chain." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside } from "@components" @@ -23,12 +23,28 @@ This guide explains the two key parts of working with log triggers: You create an EVM Log trigger by calling the `EVMClient.logTrigger()` method with a `FilterLogTriggerRequest` configuration. This configuration specifies which contract addresses and event topics to listen for. +<Aside type="note" title="Base64 Encoding Required"> + **All addresses and topic values must be base64 encoded** using the `hexToBase64()` helper function from the CRE SDK. + While the workflow simulator accepts raw hex strings for convenience during development, **deployed workflows require + base64 encoding**. Always use `hexToBase64()` on addresses and topic values to ensure your workflow works in both + simulation and production. +</Aside> + ### Basic configuration The simplest configuration listens for **all events** from specific contract addresses: ```typescript -import { cre, getNetwork, type Runtime, type EVMLog, Runner, bytesToHex } from "@chainlink/cre-sdk" +import { + EVMClient, + handler, + getNetwork, + type Runtime, + type EVMLog, + Runner, + bytesToHex, + hexToBase64, +} from "@chainlink/cre-sdk" type Config = { chainSelectorName: string @@ -53,12 +69,12 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], }), onLogTrigger ), @@ -69,16 +85,15 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ### Filtering by event type -To listen for **specific event types**, you need to provide the event's signature hash as the first topic (`Topics[0]`). You can compute this using viem's `keccak256` and `toHex` functions: +To listen for **specific event types**, you need to provide the event's signature hash as the first topic (`Topics[0]`). You can compute this using viem's `keccak256` and `toBytes` functions: ```typescript -import { keccak256, toHex } from "viem" +import { keccak256, toBytes } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -91,17 +106,17 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) // Compute the event signature hash for Transfer(address,address,uint256) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Listen only for Transfer events + { values: [hexToBase64(transferEventHash)] }, // Listen only for Transfer events ], }), onLogTrigger @@ -118,13 +133,27 @@ EVM events can have up to 3 `indexed` parameters (in addition to the event signa - **`addresses`**: The trigger fires if the event is emitted from **any** contract in this list (**OR** logic). - **`topics`**: An event must match the conditions for **all** defined topic slots (**AND** logic between topics). Within a single topic, you can provide multiple values, and it will match if the event's topic is **any** of those values (**OR** logic within a topic). +- **Wildcarding topics**: To skip filtering on a specific topic position, omit it from the topics array or provide an empty values array `{ values: [] }`. For example, to filter on topic 1 and topic 3 but not topic 2, you would provide `[topic0, topic1, { values: [] }, topic3]`. + +<Aside type="caution" title="Topic values must be padded to 32 bytes and base64 encoded"> +EVM logs always store indexed parameters as **32-byte values**. When filtering on topics 1, 2, or 3: + +1. **Pad your values to 32 bytes** using `padHex(value, { size: 32 })` (e.g., addresses are 20 bytes and must be padded) +1. **Convert to base64** using `hexToBase64()` + +If you don't pad correctly, your filter won't match the actual log topics and the trigger will not fire. + +Topic 0 (the event signature from `keccak256`) is already 32 bytes and doesn't need padding. + +</Aside> #### Example 1: Filtering on a single indexed parameter To trigger only on `Transfer` events where the `from` address is a specific value: ```typescript -import { keccak256, toHex, pad } from "viem" +import { keccak256, toBytes, padHex } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -137,18 +166,18 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) - const aliceAddress = "0xAlice..." + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) + const aliceAddress = "0xAlice..." as `0x${string}` return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Topic 0: Event signature (Transfer) - { values: [pad(aliceAddress)] }, // Topic 1: from = Alice + { values: [hexToBase64(transferEventHash)] }, // Topic 0: Event signature (Transfer) + { values: [hexToBase64(padHex(aliceAddress, { size: 32 }))] }, // Topic 1: from = Alice ], }), onLogTrigger @@ -157,10 +186,12 @@ const initWorkflow = (config: Config) => { } ``` +{/* prettier-ignore */} <Aside type="note" title="Indexed Parameters and Topics"> - Only parameters marked as `indexed` in the Solidity event definition can be filtered using topics. The event signature - is always `Topics[0]`. Subsequent indexed parameters are `Topics[1]`, `Topics[2]`, and `Topics[3]`. Address values - must be padded to 32 bytes using viem's `pad()` function. +Only parameters marked as `indexed` in the Solidity event definition can be filtered using topics. The event signature is always `Topics[0]`. Subsequent indexed parameters are `Topics[1]`, `Topics[2]`, and `Topics[3]`. Encoding different types: +- **Addresses**: Cast as `` `0x${string}` ``, use `padHex(address, { size: 32 })` then `hexToBase64()` +- **uint256**: Use `padHex(numberToHex(value), { size: 32 })` then `hexToBase64()` +- **bytes32**: Ensure it's 32 bytes, then use `hexToBase64()` directly </Aside> #### Example 2: "AND" filtering @@ -168,7 +199,8 @@ const initWorkflow = (config: Config) => { To trigger on `Transfer` events where `from` is Alice **AND** `to` is Bob: ```typescript -import { keccak256, toHex, pad } from "viem" +import { keccak256, toBytes, padHex } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -181,20 +213,20 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) - const aliceAddress = "0xAlice..." - const bobAddress = "0xBob..." + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) + const aliceAddress = "0xAlice..." as `0x${string}` + const bobAddress = "0xBob..." as `0x${string}` return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Topic 0: Event signature (Transfer) - { values: [pad(aliceAddress)] }, // Topic 1: from = Alice - { values: [pad(bobAddress)] }, // Topic 2: to = Bob + { values: [hexToBase64(transferEventHash)] }, // Topic 0: Event signature (Transfer) + { values: [hexToBase64(padHex(aliceAddress, { size: 32 }))] }, // Topic 1: from = Alice + { values: [hexToBase64(padHex(bobAddress, { size: 32 }))] }, // Topic 2: to = Bob ], }), onLogTrigger @@ -208,7 +240,8 @@ const initWorkflow = (config: Config) => { To trigger on `Transfer` events where `from` is **either** Alice **OR** Charlie: ```typescript -import { keccak256, toHex, pad } from "viem" +import { keccak256, toBytes, padHex } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -221,19 +254,24 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) - const aliceAddress = "0xAlice..." - const charlieAddress = "0xCharlie..." + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) + const aliceAddress = "0xAlice..." as `0x${string}` + const charlieAddress = "0xCharlie..." as `0x${string}` return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Topic 0: Event signature (Transfer) - { values: [pad(aliceAddress), pad(charlieAddress)] }, // Topic 1: from = Alice OR Charlie + { values: [hexToBase64(transferEventHash)] }, // Topic 0: Event signature (Transfer) + { + values: [ + hexToBase64(padHex(aliceAddress, { size: 32 })), + hexToBase64(padHex(charlieAddress, { size: 32 })), + ], + }, // Topic 1: from = Alice OR Charlie ], }), onLogTrigger @@ -247,7 +285,8 @@ const initWorkflow = (config: Config) => { To listen for **multiple event types** from a single contract, provide multiple event signature hashes in `Topics[0]`: ```typescript -import { keccak256, toHex } from "viem" +import { keccak256, toBytes } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -260,17 +299,17 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) - const approvalEventHash = keccak256(toHex("Approval(address,address,uint256)")) + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) + const approvalEventHash = keccak256(toBytes("Approval(address,address,uint256)")) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash, approvalEventHash] }, // Listen for Transfer OR Approval + { values: [hexToBase64(transferEventHash), hexToBase64(approvalEventHash)] }, // Listen for Transfer OR Approval ], }), onLogTrigger @@ -284,6 +323,46 @@ const initWorkflow = (config: Config) => { To listen for the **same event from multiple contracts**, provide multiple addresses: ```typescript +import { keccak256, toBytes } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" + +const initWorkflow = (config: Config) => { + const network = getNetwork({ + chainFamily: "evm", + chainSelectorName: config.chainSelectorName, + isTestnet: true, + }) + + if (!network) { + throw new Error(`Network not found: ${config.chainSelectorName}`) + } + + const evmClient = new EVMClient(network.chainSelector.selector) + + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) + + return [ + handler( + evmClient.logTrigger({ + addresses: [hexToBase64("0xTokenA..."), hexToBase64("0xTokenB..."), hexToBase64("0xTokenC...")], + topics: [ + { values: [hexToBase64(transferEventHash)] }, // Listen for Transfer events from any of these contracts + ], + }), + onLogTrigger + ), + ] +} +``` + +#### Example 6: Filtering on uint256 indexed parameter + +To filter on indexed `uint256` or other numeric types, convert them to a 32-byte hex value: + +```typescript +import { keccak256, toBytes, numberToHex, padHex } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" + const initWorkflow = (config: Config) => { const network = getNetwork({ chainFamily: "evm", @@ -295,16 +374,21 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) + // Example: event ValueChanged(address indexed user, uint256 indexed newValue) + const eventHash = keccak256(toBytes("ValueChanged(address,uint256)")) + const userAddress = padHex("0xUser..." as `0x${string}`, { size: 32 }) + const targetValue = padHex(numberToHex(12345), { size: 32 }) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: ["0xTokenA...", "0xTokenB...", "0xTokenC..."], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Listen for Transfer events from any of these contracts + { values: [hexToBase64(eventHash)] }, // Topic 0: Event signature + { values: [hexToBase64(userAddress)] }, // Topic 1: user address + { values: [hexToBase64(targetValue)] }, // Topic 2: newValue = 12345 ], }), onLogTrigger @@ -313,13 +397,19 @@ const initWorkflow = (config: Config) => { } ``` +<Aside type="note" title="Converting Numbers to Topics"> + For indexed `uint256` parameters, use `numberToHex()` to convert the number to hex, then `padHex()` to ensure it's 32 + bytes, and finally `hexToBase64()` to encode it for the trigger configuration. For `bytes32` parameters, ensure + they're already 32 bytes and apply `hexToBase64()` directly. +</Aside> + ### Confidence level You can set the block confirmation level by adding the `confidence` field to the trigger configuration: ```typescript evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], confidence: "CONFIDENCE_LEVEL_FINALIZED", // Wait for finalized blocks }) ``` @@ -432,7 +522,7 @@ const onLogTrigger = (runtime: Runtime<Config>, log: EVMLog): string => { <Aside type="note" title="Type Assertion for Topics"> The type assertion ``` - as [\`0x${string}\`, ...\`0x${string}\`[]] + as [`0x${string}`, ...`0x${string}`[]] ``` tells TypeScript that `topics` is a non-empty array of @@ -472,8 +562,17 @@ const onLogTrigger = (runtime: Runtime<Config>, log: EVMLog): string => { Here's a complete example that listens for ERC20 `Transfer` events and decodes them: ```typescript -import { cre, getNetwork, type Runtime, type EVMLog, Runner, bytesToHex } from "@chainlink/cre-sdk" -import { keccak256, toHex, decodeEventLog, parseAbi } from "viem" +import { + EVMClient, + handler, + getNetwork, + type Runtime, + type EVMLog, + Runner, + bytesToHex, + hexToBase64, +} from "@chainlink/cre-sdk" +import { keccak256, toBytes, decodeEventLog, parseAbi } from "viem" type Config = { chainSelectorName: string @@ -509,14 +608,14 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) + const evmClient = new EVMClient(network.chainSelector.selector) + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.tokenAddress], - topics: [{ values: [transferEventHash] }], + addresses: [hexToBase64(config.tokenAddress)], + topics: [{ values: [hexToBase64(transferEventHash)] }], confidence: "CONFIDENCE_LEVEL_FINALIZED", }), onLogTrigger @@ -528,8 +627,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Testing log triggers in simulation diff --git a/src/content/cre/guides/workflow/using-triggers/http-trigger/code-snippets/simulation-example.ts b/src/content/cre/guides/workflow/using-triggers/http-trigger/code-snippets/simulation-example.ts index a84b971f1d6..8e670de963e 100644 --- a/src/content/cre/guides/workflow/using-triggers/http-trigger/code-snippets/simulation-example.ts +++ b/src/content/cre/guides/workflow/using-triggers/http-trigger/code-snippets/simulation-example.ts @@ -1,4 +1,4 @@ -import { cre, type Runtime, type HTTPPayload, Runner, decodeJson } from "@chainlink/cre-sdk" +import { HTTPCapability, handler, type Runtime, type HTTPPayload, Runner, decodeJson } from "@chainlink/cre-sdk" type Config = { minimumAmount: number @@ -31,10 +31,10 @@ const onHttpTrigger = (runtime: Runtime<Config>, payload: HTTPPayload): string = } const initWorkflow = (config: Config) => { - const http = new cre.capabilities.HTTPCapability() + const http = new HTTPCapability() return [ - cre.handler(http.trigger({}), onHttpTrigger), // Empty config OK for simulation + handler(http.trigger({}), onHttpTrigger), // Empty config OK for simulation ] } @@ -42,5 +42,3 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() diff --git a/src/content/cre/guides/workflow/using-triggers/http-trigger/configuration-go.mdx b/src/content/cre/guides/workflow/using-triggers/http-trigger/configuration-go.mdx index b7edb4423f7..8b98565caed 100644 --- a/src/content/cre/guides/workflow/using-triggers/http-trigger/configuration-go.mdx +++ b/src/content/cre/guides/workflow/using-triggers/http-trigger/configuration-go.mdx @@ -44,7 +44,7 @@ func onHttpTrigger(config *Config, runtime cre.Runtime, payload *http.Payload) ( logger := runtime.Logger() // Unmarshal the JSON input from bytes - var requestData map[string]interface{} + var requestData map[string]any if err := json.Unmarshal(payload.Input, &requestData); err != nil { return nil, fmt.Errorf("failed to unmarshal input: %w", err) } @@ -92,7 +92,7 @@ func onHttpTrigger(config *Config, runtime cre.Runtime, payload *http.Payload) ( // The payload.Input is []byte containing JSON data. // Unmarshal it into a map or a custom struct. - var requestData map[string]interface{} + var requestData map[string]any if err := json.Unmarshal(payload.Input, &requestData); err != nil { return nil, fmt.Errorf("failed to unmarshal input: %w", err) } diff --git a/src/content/cre/guides/workflow/using-triggers/http-trigger/configuration-ts.mdx b/src/content/cre/guides/workflow/using-triggers/http-trigger/configuration-ts.mdx index 3bc8816d4f6..2fcec552bb7 100644 --- a/src/content/cre/guides/workflow/using-triggers/http-trigger/configuration-ts.mdx +++ b/src/content/cre/guides/workflow/using-triggers/http-trigger/configuration-ts.mdx @@ -7,7 +7,7 @@ date: Last Modified metadata: description: "Configure HTTP triggers in TypeScript: learn to set up authorization, write handler functions, and process HTTP request payloads." datePublished: "2025-11-04" - lastModified: "2025-11-10" + lastModified: "2026-01-20" --- import { Aside } from "@components" @@ -30,7 +30,7 @@ You create an HTTP trigger by calling the `HTTPCapability.trigger()` method. Its </Aside> ```typescript -import { cre, type Runtime, type HTTPPayload, Runner } from "@chainlink/cre-sdk" +import { HTTPCapability, handler, type Runtime, type HTTPPayload, Runner } from "@chainlink/cre-sdk" type Config = { authorizedEVMAddress: string @@ -44,10 +44,10 @@ const onHttpTrigger = (runtime: Runtime<Config>, payload: HTTPPayload): string = } const initWorkflow = (config: Config) => { - const httpTrigger = new cre.capabilities.HTTPCapability() + const httpTrigger = new HTTPCapability() return [ - cre.handler( + handler( httpTrigger.trigger({ authorizedKeys: [ { @@ -65,8 +65,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` **About authorized keys:** diff --git a/src/content/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool.mdx b/src/content/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool.mdx index 01bde9510d8..4d87c43e742 100644 --- a/src/content/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool.mdx +++ b/src/content/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool.mdx @@ -5,7 +5,7 @@ date: Last Modified metadata: description: "Test deployed HTTP trigger workflows easily with the cre-http-trigger TypeScript tool: automatic JWT generation, local proxy server, and simple configuration." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-14" --- import { Aside } from "@components" @@ -39,7 +39,7 @@ The `cre-http-trigger` tool eliminates this complexity by: ## Prerequisites -- **Bun runtime**: The tool requires <a href="https://bun.sh" target="_blank" rel="noopener noreferrer">Bun</a> version 1.2.21 or higher +- **Bun runtime**: The tool requires <a href="https://bun.com" target="_blank" rel="noopener noreferrer">Bun</a> version 1.2.21 or higher - **Deployed workflow**: Your workflow must be deployed with an HTTP trigger - **Workflow ID**: Available from deployment output or the CRE UI - **Private key**: The private key corresponding to one of the `authorizedKeys` in your HTTP trigger configuration diff --git a/src/content/cre/guides/workflow/using-triggers/http-trigger/testing-in-simulation.mdx b/src/content/cre/guides/workflow/using-triggers/http-trigger/testing-in-simulation.mdx index 40b33c8dcf6..c550e082f2a 100644 --- a/src/content/cre/guides/workflow/using-triggers/http-trigger/testing-in-simulation.mdx +++ b/src/content/cre/guides/workflow/using-triggers/http-trigger/testing-in-simulation.mdx @@ -75,8 +75,9 @@ cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --htt ``` <Aside type="note" title="Non-interactive requirements"> - The `--http-payload` flag requires `--non-interactive` mode. You must also specify `--trigger-index` (0-based index of - your HTTP trigger). If your HTTP trigger is the only trigger or the first one defined, use `--trigger-index 0`. + The `--http-payload` flag requires `--non-interactive` mode. You must also specify `--trigger-index` to select which + handler to run. The index is 0-based: if the handler with your HTTP trigger is the first handler defined in your + `InitWorkflow` function, use `--trigger-index 0`; if it's the second, use `--trigger-index 1`, and so on. </Aside> <Aside type="note" title="Escaping quotes"> diff --git a/src/content/cre/index.mdx b/src/content/cre/index.mdx index 0dd323aa09b..69165c62c54 100644 --- a/src/content/cre/index.mdx +++ b/src/content/cre/index.mdx @@ -5,7 +5,7 @@ isIndex: true metadata: description: "Discover Chainlink Runtime Environment (CRE): the all-in-one orchestration layer that provides a secure, verifiable environment for your institutional-grade smart contracts." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside, CodeHighlightBlockMulti } from "@components" @@ -61,7 +61,7 @@ Workflows use a **trigger-and-callback model** to provide a code-first developer 1. **A Trigger**: An event source that starts a workflow execution (e.g., `cron.Trigger`). This is the "when" of your workflow. 1. **A Callback**: A function that contains your business logic. It is inside this function that you will use the SDK's clients to invoke capabilities. This is the "what" of your workflow. -1. **The `cre.handler()`**: The glue that connects a single trigger to a single callback. +1. **The `handler()`**: The glue that connects a single trigger to a single callback. You can define multiple trigger and callback combinations in your workflow. You can also attach the same callback to multiple triggers for reusability. @@ -113,7 +113,7 @@ Learn more about [Consensus Computing in CRE](/cre/concepts/consensus-computing) | Concept | One-liner | | ------------------ | ----------------------------------------------------------------- | | **Workflow** | Compiled WebAssembly (WASM) binary. | -| **Handler** | `cre.handler(trigger, callback)` pair; the atom of execution. | +| **Handler** | `handler(trigger, callback)` pair; the atom of execution. | | **Trigger** | Event that starts an execution (cron, HTTP, EVM log, …). | | **Callback** | Function that runs when its trigger fires; contains your logic. | | **Runtime** | Object passed to a callback; used to invoke capabilities. | diff --git a/src/content/cre/llms-full-go.txt b/src/content/cre/llms-full-go.txt index c5ee51d6a01..683eb5939d6 100644 --- a/src/content/cre/llms-full-go.txt +++ b/src/content/cre/llms-full-go.txt @@ -1,6 +1,6 @@ # Chainlink Runtime Environment (CRE) Source: https://docs.chain.link/cre -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 ## What is CRE? @@ -51,7 +51,7 @@ Workflows use a **trigger-and-callback model** to provide a code-first developer 1. **A Trigger**: An event source that starts a workflow execution (e.g., `cron.Trigger`). This is the "when" of your workflow. 2. **A Callback**: A function that contains your business logic. It is inside this function that you will use the SDK's clients to invoke capabilities. This is the "what" of your workflow. -3. **The `cre.handler()`**: The glue that connects a single trigger to a single callback. +3. **The `handler()`**: The glue that connects a single trigger to a single callback. You can define multiple trigger and callback combinations in your workflow. You can also attach the same callback to multiple triggers for reusability. @@ -102,7 +102,7 @@ Learn more about [Consensus Computing in CRE](/cre/concepts/consensus-computing) | Concept | One-liner | | ------------------ | ----------------------------------------------------------------- | | **Workflow** | Compiled WebAssembly (WASM) binary. | -| **Handler** | `cre.handler(trigger, callback)` pair; the atom of execution. | +| **Handler** | `handler(trigger, callback)` pair; the atom of execution. | | **Trigger** | Event that starts an execution (cron, HTTP, EVM log, …). | | **Callback** | Function that runs when its trigger fires; contains your logic. | | **Runtime** | Object passed to a callback; used to invoke capabilities. | @@ -249,7 +249,7 @@ The mechanism by which a DON comes to a single, reliable, and tamper-proof resul # Service Quotas Source: https://docs.chain.link/cre/service-quotas -Last Updated: 2025-11-04 +Last Updated: 2025-12-18 This page documents the service quotas for Chainlink Runtime Environment (CRE) workflows. @@ -261,15 +261,10 @@ This page documents the service quotas for Chainlink Runtime Environment (CRE) w These quotas apply to each workflow owner (user account) within an organization. -| Quota | Description | Value | -| ------------------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------- | -| Workflow Deployment Rate | Maximum rate at which an organization can deploy new workflows | Rate: 1 per minute <br /> Burst: 1 | -| Concurrent Workflow Executions | Maximum number of workflows that can execute simultaneously | 5 | -| Workflow Trigger Rate | Maximum rate at which triggers can fire for all workflows owned by a single owner (user account) | Rate: 5 per second <br /> Burst: 5 | -| Workflow Binary Size | Maximum size of the compiled WASM binary | 100 MB | -| Workflow Compressed Binary Size | Maximum size of the compressed WASM binary | 20 MB | -| Workflow Configuration Size | Maximum size of the workflow configuration | 1 MB | -| Secrets Size | Maximum total size of secrets accessible to a workflow | 1 MB | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | ----- | +| <a href="#perowner-workflowexecutionconcurrencylimit" id="perowner-workflowexecutionconcurrencylimit">`PerOwner.WorkflowExecutionConcurrencyLimit`</a> | Maximum number of workflows that can execute simultaneously | 5 | +| <a href="#perowner-vaultsecretslimit" id="perowner-vaultsecretslimit">`PerOwner.VaultSecretsLimit`</a> | Maximum number of secrets that can be stored per owner | 100 | <Aside type="note" title="Quota enforcement"> When workflow executions exceed the quotas defined above, they are queued and automatically retried for up to 10 @@ -280,57 +275,64 @@ These quotas apply to each workflow owner (user account) within an organization. These quotas apply to each individual workflow. +### Workflow deployment quotas + +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------ | +| <a href="#perworkflow-wasmbinarysizelimit" id="perworkflow-wasmbinarysizelimit">`PerWorkflow.WASMBinarySizeLimit`</a> | Maximum size of the compiled WASM binary | 100 MB | +| <a href="#perworkflow-wasmcompressedbinarysizelimit" id="perworkflow-wasmcompressedbinarysizelimit">`PerWorkflow.WASMCompressedBinarySizeLimit`</a> | Maximum size of the compressed WASM binary | 20 MB | +| <a href="#perworkflow-wasmconfigsizelimit" id="perworkflow-wasmconfigsizelimit">`PerWorkflow.WASMConfigSizeLimit`</a> | Maximum size of the workflow configuration | 1 MB | + ### Trigger quotas -| Quota | Description | Value | -| ----------------------------- | ---------------------------------------------------------------------- | -------------------------------------- | -| Trigger Rate | Maximum rate at which a workflow's triggers can fire | Rate: 1 per 30 seconds <br /> Burst: 3 | -| Maximum Triggers per Workflow | Maximum number of triggers that can be registered to a single workflow | 10 | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | ----- | +| <a href="#perworkflow-triggersubscriptionlimit" id="perworkflow-triggersubscriptionlimit">`PerWorkflow.TriggerSubscriptionLimit`</a> | Maximum number of triggers that can be registered to a single workflow | 10 | ### Execution quotas -| Quota | Description | Value | -| ----------------------------- | --------------------------------------------------------------- | ----------------- | -| Concurrent Workflow Instances | Maximum number of concurrent executions for a specific workflow | 5 <br /> Burst: 5 | -| Workflow Timeout | Maximum total execution time for a single workflow run | 5 minutes | -| Workflow Memory Allocation | Maximum memory allocated to a workflow | 100 MB | -| Response Size | Maximum size of the data a workflow can return | 100 KB | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | --------- | +| <a href="#perworkflow-executionconcurrencylimit" id="perworkflow-executionconcurrencylimit">`PerWorkflow.ExecutionConcurrencyLimit`</a> | Maximum number of concurrent executions for a specific workflow | 5 | +| <a href="#perworkflow-executiontimeout" id="perworkflow-executiontimeout">`PerWorkflow.ExecutionTimeout`</a> | Maximum total execution time for a single workflow run | 5 minutes | +| <a href="#perworkflow-wasmmemorylimit" id="perworkflow-wasmmemorylimit">`PerWorkflow.WASMMemoryLimit`</a> | Maximum memory allocated to a workflow | 100 MB | +| <a href="#perworkflow-executionresponselimit" id="perworkflow-executionresponselimit">`PerWorkflow.ExecutionResponseLimit`</a> | Maximum size of the data a workflow can return | 100 KB | -### Capability call quotas +### General capability quotas -| Quota | Description | Value | -| --------------------------- | ------------------------------------------------------------------------------------------------------ | --------- | -| Concurrent Capability Calls | Maximum concurrent capability calls (HTTP, EVM read/write, secrets) that can execute within a workflow | 3 | -| Capability Call Timeout | Maximum time a single capability call can take to complete | 3 minutes | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | --------- | +| <a href="#perworkflow-capabilityconcurrencylimit" id="perworkflow-capabilityconcurrencylimit">`PerWorkflow.CapabilityConcurrencyLimit`</a> | Maximum concurrent capability calls (HTTP, EVM read/write, secrets) that can execute within a workflow | 3 | +| <a href="#perworkflow-capabilitycalltimeout" id="perworkflow-capabilitycalltimeout">`PerWorkflow.CapabilityCallTimeout`</a> | Maximum time a single capability call can take to complete | 3 minutes | ### Secrets quotas -| Quota | Description | Value | -| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----- | -| Secrets Size | Maximum total size of secrets accessible to a workflow | 1 MB | -| Concurrent Secrets Fetches | Maximum number of secrets that can be fetched concurrently. [Learn how to fetch multiple secrets](/cre/guides/workflow/secrets). | 5 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----- | +| <a href="#perworkflow-wasmsecreetssizelimit" id="perworkflow-wasmsecreetssizelimit">`PerWorkflow.WASMSecretsSizeLimit`</a> | Maximum total size of secrets accessible to a workflow | 1 MB | +| <a href="#perworkflow-secretsconcurrencylimit" id="perworkflow-secretsconcurrencylimit">`PerWorkflow.SecretsConcurrencyLimit`</a> | Maximum number of secrets that can be fetched concurrently. [Learn how to fetch multiple secrets](/cre/guides/workflow/secrets). | 5 | ### Consensus quotas -| Quota | Description | Value | -| --------------------- | ---------------------------------------------------------------- | ------ | -| Observation Size | Maximum size of data that can be passed to consensus aggregation | 100 KB | -| Total Consensus Calls | Maximum number of consensus calls per workflow execution | 2,000 | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | ----- | +| <a href="#perworkflow-consensus-observationsizelimit" id="perworkflow-consensus-observationsizelimit">`PerWorkflow.Consensus.ObservationSizeLimit`</a> | Maximum size of data that can be passed to consensus aggregation | 25 KB | +| <a href="#perworkflow-consensus-calllimit" id="perworkflow-consensus-calllimit">`PerWorkflow.Consensus.CallLimit`</a> | Maximum number of consensus calls per workflow execution | 2,000 | ### Logging quotas -| Quota | Description | Value | -| ------------- | --------------------------------------------------- | ----- | -| Log Line Size | Maximum size of a single log line | 1 KB | -| Log Events | Maximum number of log events per workflow execution | 1,000 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ----- | +| <a href="#perworkflow-loglinelimit" id="perworkflow-loglinelimit">`PerWorkflow.LogLineLimit`</a> | Maximum size of a single log line | 1 KB | +| <a href="#perworkflow-logeventlimit" id="perworkflow-logeventlimit">`PerWorkflow.LogEventLimit`</a> | Maximum number of log events per workflow execution | 1,000 | ## Trigger-specific quotas ### Cron trigger -| Quota | Description | Value | -| ------------ | --------------------------------------------- | -------------------------------------- | -| Trigger Rate | Maximum rate at which a cron trigger can fire | Rate: 1 per 30 seconds <br /> Burst: 1 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ---------- | +| <a href="#perworkflow-crontrigger-fastestscheduleinterval" id="perworkflow-crontrigger-fastestscheduleinterval">`PerWorkflow.CRONTrigger.FastestScheduleInterval`</a> | Minimum interval between cron trigger fires | 30 seconds | <Aside type="note" title="Minimum cron schedule"> While the rate quota allows firing once per 30 seconds, you should consider the [Concurrent Workflow @@ -339,47 +341,46 @@ These quotas apply to each individual workflow. ### HTTP trigger -| Quota | Description | Value | -| ------------ | ---------------------------------------------- | -------------------------------------- | -| Trigger Rate | Maximum rate at which an HTTP trigger can fire | Rate: 1 per 30 seconds <br /> Burst: 3 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | -------------------------------------- | +| <a href="#perworkflow-httptrigger-ratelimit" id="perworkflow-httptrigger-ratelimit">`PerWorkflow.HTTPTrigger.RateLimit`</a> | Maximum rate at which an HTTP trigger can fire | Rate: 1 per 30 seconds <br /> Burst: 3 | ### EVM log trigger -| Quota | Description | Value | -| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | -| Maximum Log Triggers | Maximum number of EVM log triggers per workflow | 5 | -| Event Rate | Maximum rate at which log events can be processed | Rate: 10 per 6 seconds <br /> Burst: 10 | -| Filter Addresses | Maximum number of contract addresses that can be monitored | 5 | -| Filter Topics per Slot | Maximum number of topic values that can be specified within a single topic position (Topics[0], Topics[1], Topics[2], or Topics[3]). [Learn about topic filtering](/cre/guides/workflow/using-triggers/evm-log-trigger). | 10 | -| Event Size | Maximum size of a single log event | 5 KB | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | +| <a href="#perworkflow-logtrigger-eventratelimit" id="perworkflow-logtrigger-eventratelimit">`PerWorkflow.LogTrigger.EventRateLimit`</a> | Maximum rate at which log events can be processed | Rate: 10 per 6 seconds <br /> Burst: 10 | +| <a href="#perworkflow-logtrigger-filteraddresslimit" id="perworkflow-logtrigger-filteraddresslimit">`PerWorkflow.LogTrigger.FilterAddressLimit`</a> | Maximum number of contract addresses that can be monitored | 5 | +| <a href="#perworkflow-logtrigger-filtertopicsperslotlimit" id="perworkflow-logtrigger-filtertopicsperslotlimit">`PerWorkflow.LogTrigger.FilterTopicsPerSlotLimit`</a> | Maximum number of topic values that can be specified within a single topic position (Topics[0], Topics[1], Topics[2], or Topics[3]). [Learn about topic filtering](/cre/guides/workflow/using-triggers/evm-log-trigger). | 10 | +| <a href="#perworkflow-logtrigger-eventsizelimit" id="perworkflow-logtrigger-eventsizelimit">`PerWorkflow.LogTrigger.EventSizeLimit`</a> | Maximum size of a single log event | 5 KB | ## Capability-specific quotas ### EVM write capability -| Quota | Description | Value | -| --------------------- | --------------------------------------------------------- | --------- | -| Target Chains | Maximum number of destination chains for write operations | 10 | -| Report Size | Maximum size of a report payload | 5 KB | -| Transaction Gas Quota | Gas quota per EVM transaction | 5,000,000 | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | --------- | +| <a href="#perworkflow-chainwrite-targetslimit" id="perworkflow-chainwrite-targetslimit">`PerWorkflow.ChainWrite.TargetsLimit`</a> | Maximum number of destination chains for write operations | 10 | +| <a href="#perworkflow-chainwrite-reportsizelimit" id="perworkflow-chainwrite-reportsizelimit">`PerWorkflow.ChainWrite.ReportSizeLimit`</a> | Maximum size of a report payload | 5 KB | +| <a href="#perworkflow-chainwrite-evm-transactiongaslimit" id="perworkflow-chainwrite-evm-transactiongaslimit">`PerWorkflow.ChainWrite.EVM.TransactionGasLimit`</a> | Gas quota per EVM transaction | 5,000,000 | ### EVM read capability -| Quota | Description | Value | -| ------------------------ | ---------------------------------------------------------------- | ----- | -| Read Calls per Execution | Maximum number of EVM read calls per workflow execution | 10 | -| Log Query Block Quota | Maximum number of blocks that can be queried for historical logs | 100 | -| Payload Size | Maximum size of an EVM read request payload | 5 KB | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | ----- | +| <a href="#perworkflow-chainread-calllimit" id="perworkflow-chainread-calllimit">`PerWorkflow.ChainRead.CallLimit`</a> | Maximum number of EVM read calls per workflow execution | 10 | +| <a href="#perworkflow-chainread-logqueryblocklimit" id="perworkflow-chainread-logqueryblocklimit">`PerWorkflow.ChainRead.LogQueryBlockLimit`</a> | Maximum number of blocks that can be queried for historical logs | 100 | +| <a href="#perworkflow-chainread-payloadsizelimit" id="perworkflow-chainread-payloadsizelimit">`PerWorkflow.ChainRead.PayloadSizeLimit`</a> | Maximum size of an EVM read request payload | 5 KB | ### HTTP capability -| Quota | Description | Value | -| ------------------------ | ------------------------------------------------------ | ---------- | -| HTTP Calls per Execution | Maximum number of HTTP requests per workflow execution | 5 | -| Response Size | Maximum size of an HTTP response | 10 KB | -| Connection Timeout | Maximum time to establish an HTTP connection | 10 seconds | -| Request Size | Maximum size of an HTTP request payload | 100 KB | -| Cache Age | Maximum time HTTP responses can be cached | 10 minutes | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------ | ---------- | +| <a href="#perworkflow-httpaction-calllimit" id="perworkflow-httpaction-calllimit">`PerWorkflow.HTTPAction.CallLimit`</a> | Maximum number of HTTP requests per workflow execution | 5 | +| <a href="#perworkflow-httpaction-responsesizelimit" id="perworkflow-httpaction-responsesizelimit">`PerWorkflow.HTTPAction.ResponseSizeLimit`</a> | Maximum size of an HTTP response | 100 KB | +| <a href="#perworkflow-httpaction-connectiontimeout" id="perworkflow-httpaction-connectiontimeout">`PerWorkflow.HTTPAction.ConnectionTimeout`</a> | Maximum time to establish an HTTP connection | 10 seconds | +| <a href="#perworkflow-httpaction-requestsizelimit" id="perworkflow-httpaction-requestsizelimit">`PerWorkflow.HTTPAction.RequestSizeLimit`</a> | Maximum size of an HTTP request payload | 10 KB | +| <a href="#perworkflow-httpaction-cacheagelimit" id="perworkflow-httpaction-cacheagelimit">`PerWorkflow.HTTPAction.CacheAgeLimit`</a> | Maximum time HTTP responses can be cached | 10 minutes | ## Quota increases @@ -441,15 +442,173 @@ To help us assist you faster, please include: # Release Notes Source: https://docs.chain.link/cre/release-notes -Last Updated: 2025-11-20 +Last Updated: 2026-02-10 This page provides detailed release notes for CRE. It includes information on new features, significant changes, and known limitations. +## CLI v1.0.10 - February 9, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.10" target="_blank">CRE CLI version 1.0.10</a> is now available.** + +- **Bug Fix**: Fixed secret injection for the [Confidential HTTP](/cre/capabilities/confidential-http) capability in the simulator — template placeholders (`{{.secretName}}`) now resolve correctly during `cre workflow simulate` +- **Bug Fix**: Fixed project context not being set before writing changeset files + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.9...v1.0.10) + +## CLI v1.0.9 - February 6, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.9" target="_blank">CRE CLI version 1.0.9</a> is now available.** + +- **Confidential HTTP (Experimental)**: Added [Confidential HTTP](/cre/capabilities/confidential-http) capability support in the simulator. You can now simulate workflows that use privacy-preserving API calls with secret injection and optional response encryption. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.8...v1.0.9) + +## CLI v1.0.8 - February 6, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.8" target="_blank">CRE CLI version 1.0.8</a> is now available.** + +- Changed `chain-id` to `chain-selector` in simulator settings +- Support for longer workflow names +- Fixed a logic bug in the template contract `MessageEmitter.sol` + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.7...v1.0.8) + +## New Networks Support - January 29, 2026 + +CRE now supports additional testnets for workflow simulation and production deployment: + +- Apechain Curtis +- Arc Testnet +- Hyperliquid Testnet +- Ink Sepolia +- Jovay Testnet +- Linea Sepolia +- Plasma Testnet +- World Chain Sepolia + +**Required versions:** CLI v1.0.7+, Go SDK v1.1.4+, TS SDK v1.0.7+ + +## CLI v1.0.7 - January 29, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.7" target="_blank">CRE CLI version 1.0.7</a> is now available.** + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.6...v1.0.7) + +## TS SDK v1.0.7 - January 29, 2026 + +**TypeScript SDK version 1.0.7** includes internal improvements. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.5...v1.0.7) + +## TS SDK v1.0.5 - January 28, 2026 + +- **Bug Fix**: Fixed an issue with `runtime.now()` returning incorrect timestamps + +For details on using time in workflows, see [Time in CRE](/cre/guides/workflow/time-in-workflows-ts). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.4...v1.0.5) + +## ZKSync Era Support - January 26, 2026 + +CRE now supports **ZKSync Era mainnet and testnet** for workflow simulation and production deployment. You can now build and test workflows that interact with ZKSync Era chains. + +**Required versions:** CLI v1.0.6+, Go SDK v1.1.3+ (mainnet) / v1.1.2+ (testnet), TS SDK v1.0.7+ + +## TS SDK v1.0.4 - January 26, 2026 + +**TypeScript SDK version 1.0.4** includes internal improvements. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.3...v1.0.4) + +## CLI v1.0.6 - January 21, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.6" target="_blank">CRE CLI version 1.0.6</a> is now available.** + +- **ZKSync Era support**: Added ZKSync Era testnet and mainnet to the simulator + +This release also includes various small improvements and bug fixes, such as better error messages when hitting workflow limits. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +## TS SDK v1.0.3 - January 19, 2026 + +- **Bug Fixes**: Fixed issue where workflows could execute twice during simulation + +- **Examples Updated**: All workflow examples in the SDK repository now use **direct imports** (e.g., `import { HTTPClient } from "@chainlink/cre-sdk"`) instead of the namespace pattern (e.g., `cre.capabilities.HTTPClient`). Both patterns remain fully supported—choose whichever fits your coding style. See [Import styles](/cre/reference/sdk/core-ts#import-styles) for details. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.2...v1.0.3) + +## TS SDK v1.0.2 - January 16, 2026 + +**TypeScript SDK version 1.0.2** introduces several improvements to developer experience: + +**New features:** + +- **Optional `main()` call**: You no longer need to call `main()` at the end of your workflow files. The SDK now automatically executes the `main()` function during compilation. See [`main()` reference](/cre/reference/sdk/core-ts#main) for details. +- **Automatic error handling**: If you don't provide custom error handling, the SDK automatically adds `.catch(sendErrorResponse)` to your workflow's `main()` function. This ensures errors are properly reported instead of silently failing. +- **Direct imports**: You can now import SDK components directly (e.g., `import { HTTPClient } from "@chainlink/cre-sdk"`) instead of accessing them through the `cre` namespace (e.g., `cre.capabilities.HTTPClient`). Both import styles remain supported for backward compatibility. See [Import styles](/cre/reference/sdk/core-ts#import-styles) for details and guidance on when to use each pattern. + +**Migration notes:** + +- **Custom error handling**: If you need custom error handling, you can still add your own `.catch()` handler: `main().catch(myCustomHandler)`. The SDK will respect your custom handler and not override it. See [`main()` reference](/cre/reference/sdk/core-ts#main) for examples. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.1...v1.0.2) + +## CLI v1.0.5 - January 13, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.5" target="_blank">CRE CLI version 1.0.5</a> is now available.** This release includes various small improvements and bug fixes. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +## CLI v1.0.4 - January 9, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.4" target="_blank">CRE CLI version 1.0.4</a> is now available.** This release includes various small improvements and bug fixes. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +## CLI v1.0.3 - December 12, 2025 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.3" target="_blank">CRE CLI version 1.0.3</a> is now available.** This release includes various small improvements and bug fixes. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + ## CLI v1.0.2 - November 20, 2025 **<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.2" target="_blank">CRE CLI version 1.0.2</a> is now available.** This release includes various improvements based on user feedback. -### How to update +**How to update:** - **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. - **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). @@ -529,9 +688,9 @@ These guides explain how to install the Chainlink Developer Platform CLI (also r # Installing the CRE CLI on macOS and Linux Source: https://docs.chain.link/cre/getting-started/cli-installation/macos-linux -Last Updated: 2025-11-20 +Last Updated: 2026-02-10 -This page explains how to install the CRE CLI on macOS or Linux. The recommended version at the time of writing is **v1.0.2**. +This page explains how to install the CRE CLI on macOS or Linux. The recommended version at the time of writing is **v1.0.10**. ## Installation @@ -545,7 +704,7 @@ Choose your installation method: The easiest way to install the CRE CLI is using the installation script: ```bash -curl -sSL https://cre.chain.link/install.sh | sh +curl -sSL https://cre.chain.link/install.sh | bash ``` This script will: @@ -553,7 +712,7 @@ This script will: - Detect your operating system and architecture automatically - Download the correct binary for your system - Verify the binary's integrity -- Install it to `/usr/local/bin` (or prompt you for a custom location) +- Install it to `$HOME/.cre` - Make the binary executable After the script completes, verify the installation: @@ -562,7 +721,7 @@ After the script completes, verify the installation: cre version ``` -**Expected output:** `cre version v1.0.2` +**Expected output:** `cre version v1.0.10` <Aside type="note" title="macOS Gatekeeper"> If you see warnings about "unrecognized developer/source" on macOS, run:{" "} @@ -580,9 +739,15 @@ The CRE CLI is publicly available on GitHub. Visit the releases page and downloa - On **macOS** (darwin), run <CopyText text="uname -m" code />: - `arm64` (Apple Silicon) → Download `cre_darwin_arm64.zip` - `x86_64` (Intel) → Download `cre_darwin_amd64.zip` - - On **Linux**, run <CopyText text="uname -m" code />: - - `aarch64` (ARM) → Download `cre_linux_arm64.tar.gz` - - `x86_64` (AMD/Intel) → Download `cre_linux_amd64.tar.gz` + - On **Linux**, the binary depends on both your architecture and OS version. First, run <CopyText text="uname -m" code /> to check your architecture, then <CopyText text="lsb_release -rs" code /> to check your Ubuntu version: + - **Ubuntu 22.04 or older**: + - `x86_64` (AMD/Intel) → Download `cre_linux_amd64_ldd2-35.tar.gz` + - `aarch64` (ARM) → Download `cre_linux_arm64_ldd2-35.tar.gz` + - **Ubuntu 24.04 or newer**: + - `x86_64` (AMD/Intel) → Download `cre_linux_amd64.tar.gz` + - `aarch64` (ARM) → Download `cre_linux_arm64.tar.gz` + + **Note:** The `ldd2-35` binaries are compiled for older glibc versions (2.35 and below). If you're using a non-Ubuntu Linux distribution, check your glibc version with <CopyText text="ldd --version" code /> and use the `ldd2-35` binary if your version is 2.35 or lower. </Aside> After downloading the correct file from the releases page, move on to the next step to verify its integrity. @@ -601,16 +766,21 @@ shasum -a 256 cre_darwin_arm64.zip **Verify against official checksums** -Compare the output with the official checksum below: +Compare the output with the official checksum from the [CRE CLI releases page](https://github.com/smartcontractkit/cre-cli/releases): + +1. Go to [https://github.com/smartcontractkit/cre-cli/releases](https://github.com/smartcontractkit/cre-cli/releases) +2. Find the release version you downloaded (e.g., v1.0.10) +3. Under the **Assets** section, locate your downloaded file +4. Compare the SHA-256 checksum shown next to the file with your command output + +**Example:** For `cre_darwin_arm64.zip` in release v1.0.10, you'll see something like: -| File | SHA-256 Checksum | -| ------------------------ | ---------------------------------------------------------------- | -| `cre_darwin_amd64.zip` | 482e53d3a5f8471034d30c935196d2dca2ab09a5fe1ab2083ad336172565291b | -| `cre_darwin_arm64.zip` | 92b0409801dd4e44f90a85331615f3e4b8cf1fe9f90a8eab3ad8bb3458b4b6cf | -| `cre_linux_amd64.tar.gz` | d3a8b9b999b4b8bf73b2235d27386acf4efbc8f05d86d9e6066abda23ee9ce9b | -| `cre_linux_arm64.tar.gz` | f52d618727ccc8fb6ab4b1f9418b09424c8505428131a49c01bb33ca2bc86fe3 | +``` +cre_darwin_arm64.zip +sha256:1359415a1f1baee7643107b82b3a0589a3627aef71018644e5c488960a97e955 +``` -If the checksum doesn't match, do not proceed with installation. Contact your Chainlink point of contact for assistance. +If the checksums match, the file is authentic and safe to install. If they don't match, do not proceed with installation and contact the Chainlink team for assistance. #### 2. Extract and install @@ -633,7 +803,7 @@ If the checksum doesn't match, do not proceed with installation. Contact your Ch 3. **Rename the extracted binary to `cre`** ```bash - mv cre_v1.0.2_darwin_arm64 cre + mv cre_v1.0.10_darwin_arm64 cre ``` 4. **Make it executable**: @@ -706,13 +876,13 @@ cre version **Expected output:** -You should see version information: `cre version v1.0.2`. +You should see version information: `cre version v1.0.10`. **If it doesn't work:** - Make sure you opened a **new terminal window** after making PATH changes -- Check the binary location: `which cre` should return `/usr/local/bin/cre` (or your custom path) -- Check that the binary has execute permissions: `ls -la /usr/local/bin/cre` +- Check the binary location: `which cre` should return the path to your installation +- Check that the binary has execute permissions: `ls -la $(which cre)` - Verify your PATH includes the correct directory: `echo $PATH` #### 5. Confirm your PATH (troubleshooting) @@ -743,9 +913,9 @@ Once you're authenticated, you're ready to build your first workflow: # Installing the CRE CLI on Windows Source: https://docs.chain.link/cre/getting-started/cli-installation/windows -Last Updated: 2025-11-20 +Last Updated: 2026-02-10 -This page explains how to install the Chainlink Developer Platform CLI (also referred to as the CRE CLI) on Windows. The recommended version at the time of writing is **v1.0.2**. +This page explains how to install the Chainlink Developer Platform CLI (also referred to as the CRE CLI) on Windows. The recommended version at the time of writing is **v1.0.10**. ## Installation @@ -766,7 +936,7 @@ This script will: - Download the correct binary for Windows - Verify the binary's integrity -- Install it to a location in your PATH +- Install it to `$env:LOCALAPPDATA\Programs\cre` - Make the binary executable After the script completes, **open a new PowerShell window** and verify the installation: @@ -775,7 +945,7 @@ After the script completes, **open a new PowerShell window** and verify the inst cre version ``` -**Expected output:** `cre version v1.0.2` +**Expected output:** `cre version v1.0.10` ### Manual installation @@ -799,20 +969,28 @@ Get-FileHash cre_windows_amd64.zip -Algorithm SHA256 **Verify against the official checksum** -Compare the `Hash` value in the output with the official checksum below: +Compare the `Hash` value in the output with the official checksum from the [CRE CLI releases page](https://github.com/smartcontractkit/cre-cli/releases): + +1. Go to [https://github.com/smartcontractkit/cre-cli/releases](https://github.com/smartcontractkit/cre-cli/releases) +2. Find the release version you downloaded (e.g., v1.0.10) +3. Under the **Assets** section, locate `cre_windows_amd64.zip` +4. Compare the SHA-256 checksum shown next to the file with the `Hash` value from your PowerShell output + +**Example:** For `cre_windows_amd64.zip` in release v1.0.10, you'll see something like: -| File | SHA-256 Checksum | -| ----------------------- | ---------------------------------------------------------------- | -| `cre_windows_amd64.zip` | 60fe65b74619c4164c0a9d6442611bf8537a04a6daf1ed3ecefc608cbbffdb01 | +``` +cre_windows_amd64.zip +sha256:372d16566479ff6bbfe9eb1d5cebe0e1e2a3c67062c6f0439fc96c735ddeaa18 +``` -If the checksum doesn't match, do not proceed with installation. Contact your Chainlink point of contact for assistance. +If the checksums match, the file is authentic and safe to install. If they don't match, do not proceed with installation and contact the Chainlink team for assistance. #### 2. Extract and install 1. Navigate to the directory where you downloaded the archive. 2. Right-click the `.zip` file and select **Extract All...**. 3. Choose a permanent location for the extracted folder (e.g., `C:\Program Files\cre-cli`). -4. Inside the extracted folder, rename the file `cre_v1.0.2_windows_amd64.exe` to `cre.exe`. +4. Inside the extracted folder, rename the file `cre_v1.0.10_windows_amd64.exe` to `cre.exe`. #### 3. Add the CLI to your PATH @@ -837,7 +1015,7 @@ Open a new **PowerShell** or **Command Prompt** window and run: cre version ``` -You should see version information: `cre version v1.0.2`. +You should see version information: `cre version v1.0.10`. ## Next steps @@ -852,116 +1030,6 @@ Once you're authenticated, you're ready to build your first workflow: --- -# Conclusion & Next Steps -Source: https://docs.chain.link/cre/getting-started/conclusion -Last Updated: 2025-11-04 - -You've built a complete, end-to-end CRE workflow from scratch. - -You started with an empty project and progressively built a workflow that: - -- Fetches data from an offchain API with consensus -- Reads values from a smart contract -- Performs calculations combining onchain and offchain data -- Writes results back to the blockchain - -**This is no small achievement.** You've mastered the core pattern that powers most CRE workflows: the trigger-and-callback model with capabilities for HTTP, EVM, and consensus. - -## What's next? - -Now that you have a working workflow, here's your natural progression from simulation to production and beyond. - -### 1. See a complete example - -Ready to see all these concepts in a more complex, real-world scenario? - -- **[Run the Custom Data Feed Demo](/cre/templates/running-demo-workflow)** - Explore an advanced template that combines multiple capabilities - -**Why this matters:** Templates show production-ready patterns. - -### 2. Deploy your Calculator workflow to Production - -You've simulated your workflow locally. **The logical next step is to deploy it to the CRE production environment** so it runs across a Decentralized Oracle Network (DON). - - -<Aside type="note" title="Deployment access required"> - - Deploying workflows requires Early Access approval. If you don't have deployment access yet, <a href="https://cre.chain.link/request-access" target="_blank" rel="noopener noreferrer">request it here</a>. - - **While you wait:** Continue building and simulating workflows using [`cre workflow simulate`](/cre/guides/operations/simulating-workflows). -</Aside> - -**Follow this deployment sequence:** - -1. **[Link a Wallet Key](/cre/organization/linking-keys)** - Connect your wallet address to your organization (required before deployment) -2. **[Deploy Your Workflow](/cre/guides/operations/deploying-workflows)** - Push your calculator workflow live -3. **[Monitor Your Workflow](/cre/guides/operations/monitoring-workflows)** - Watch it execute in production and debug any issues - -**Why this matters:** Deploying moves your workflow from local simulation to production execution across a DON. - -### 3. Explore different triggers - -You used a **Cron trigger** (time-based). **Most production workflows react to real-world events.** - -**Try these next:** - -- **[HTTP Trigger](/cre/guides/workflow/using-triggers/http-trigger/overview)** - Let external systems trigger your workflow via API calls -- **[EVM Log Trigger](/cre/guides/workflow/using-triggers/evm-log-trigger)** - React to onchain events (e.g., token transfers, contract events) - -**Why this matters:** Event-driven workflows are more powerful than scheduled ones. They respond instantly to real-world changes. - -### 4. Add secrets - -Your calculator used a public API. **Real workflows often need API keys and other sensitive data.** - -**Learn how to secure your secrets:** - -- **[Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation)** - Store secrets in your local environment for development -- **[Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed)** - Store secrets in the Vault DON for production -- **[Managing Secrets with 1Password](/cre/guides/workflow/secrets/managing-secrets-1password)** - Best practice: inject secrets at runtime - -**Why this matters:** Hardcoded credentials are a security risk. CRE's secrets management lets you safely use authenticated APIs and private keys. - -### 5. Build your own consumer contract - -You used a **pre-deployed consumer contract**. **For production workflows, you'll create custom contracts tailored to your use case.** - -**Learn the secure pattern:** - -- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)** - Create contracts that safely receive CRE data - -**Why this matters:** Consumer contracts enforce business logic and validation onchain, enabling trustless and verifiable execution. - -## Reference: Deepen Your Understanding - -Want to dive deeper into specific concepts from the Getting Started guide? Use this section as a quick reference. - -**Workflow Structure & Triggers** - -- **[Core SDK Reference](/cre/reference/sdk/core/)** - Fundamental building blocks (`InitWorkflow`, `Handler`, `Runtime`) -- **[Triggers Overview](/cre/guides/workflow/using-triggers/overview)** - Compare all available event sources - -**HTTP & Offchain Data** - -- **[API Interactions Guide](/cre/guides/workflow/using-http-client/)** - Complete patterns for HTTP requests -- **[Consensus & Aggregation](/cre/reference/sdk/consensus)** - All aggregation methods (median, mode, custom) -- **[Consensus Computing Concept](/cre/concepts/consensus-computing)** - How CRE's consensus-based execution works - -**EVM & Onchain Interactions** - -- **[EVM Client Overview](/cre/guides/workflow/using-evm-client/overview)** - Introduction to smart contract interactions -- **[Onchain Read Guide](/cre/guides/workflow/using-evm-client/onchain-read)** - Reading from a smart contract -- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write)** - Complete write patterns and report generation - -**Configuration & Secrets** - -- **[Project Configuration](/cre/reference/project-configuration/)** - Complete guide to `project.yaml`, `workflow.yaml`, and targets -- **[Secrets Guide](/cre/guides/workflow/secrets)** - All secrets management patterns - -**All Capabilities** - -- **[Capabilities Overview](/cre/capabilities/)** - See the full list of CRE capabilities and how they work together - ---- - # Using Triggers Source: https://docs.chain.link/cre/guides/workflow/using-triggers/overview Last Updated: 2025-11-04 @@ -1045,8 +1113,9 @@ cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --htt ``` <Aside type="note" title="Non-interactive requirements"> - The `--http-payload` flag requires `--non-interactive` mode. You must also specify `--trigger-index` (0-based index of - your HTTP trigger). If your HTTP trigger is the only trigger or the first one defined, use `--trigger-index 0`. + The `--http-payload` flag requires `--non-interactive` mode. You must also specify `--trigger-index` to select which + handler to run. The index is 0-based: if the handler with your HTTP trigger is the first handler defined in your + `InitWorkflow` function, use `--trigger-index 0`; if it's the second, use `--trigger-index 1`, and so on. </Aside> <Aside type="note" title="Escaping quotes"> @@ -1629,7 +1698,7 @@ Manual JWT generation is complex and error-prone. For development and testing: # Testing with Local JWT Server Source: https://docs.chain.link/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool -Last Updated: 2025-11-04 +Last Updated: 2026-01-14 The <a href="https://github.com/smartcontractkit/cre-sdk-typescript/tree/main/packages/cre-http-trigger" target="_blank" rel="noopener noreferrer">`cre-http-trigger` TypeScript package</a> simplifies testing deployed workflows with HTTP triggers by handling JWT generation, signing, and request formatting automatically. It provides a local HTTP server that acts as a proxy between your test requests and the CRE gateway. @@ -1660,7 +1729,7 @@ The `cre-http-trigger` tool eliminates this complexity by: ## Prerequisites -- **Bun runtime**: The tool requires <a href="https://bun.sh" target="_blank" rel="noopener noreferrer">Bun</a> version 1.2.21 or higher +- **Bun runtime**: The tool requires <a href="https://bun.com" target="_blank" rel="noopener noreferrer">Bun</a> version 1.2.21 or higher - **Deployed workflow**: Your workflow must be deployed with an HTTP trigger - **Workflow ID**: Available from deployment output or the CRE UI - **Private key**: The private key corresponding to one of the `authorizedKeys` in your HTTP trigger configuration @@ -2328,13 +2397,13 @@ This generated test file demonstrates real-world patterns for testing complex wo ## Where to go next -Now that you know how to generate bindings, you can use them to [read data from](/cre/guides/workflow/using-evm-client/onchain-read) or [write data to](/cre/guides/workflow/using-evm-client/onchain-write) your contracts, or [trigger workflows from events](/cre/guides/workflow/using-triggers/evm-log-trigger). +Now that you know how to generate bindings, you can use them to [read data from](/cre/guides/workflow/using-evm-client/onchain-read) or [write data to](/cre/guides/workflow/using-evm-client/onchain-write/overview) your contracts, or [trigger workflows from events](/cre/guides/workflow/using-triggers/evm-log-trigger). --- # Building Consumer Contracts Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts -Last Updated: 2025-11-20 +Last Updated: 2026-02-03 When your workflow [writes data to the blockchain](/cre/guides/workflow/using-evm-client/onchain-write), it doesn't call your contract directly. Instead, it submits a signed report to a Chainlink `KeystoneForwarder` contract, which then calls your contract. @@ -2342,12 +2411,13 @@ This guide explains how to build a consumer contract that can securely receive a **In this guide:** -- [Core Concepts: The Onchain Data Flow](#1-core-concepts-the-onchain-data-flow) -- [The IReceiver Standard](#2-the-ireceiver-standard) -- [Using IReceiverTemplate](#3-using-ireceivertemplate) -- [Working with Simulation](#4-working-with-simulation) -- [Advanced Usage](#5-advanced-usage-optional) -- [Complete Examples](#6-complete-examples) +1. [Core Concepts: The Onchain Data Flow](#1-core-concepts-the-onchain-data-flow) +2. [The IReceiver Standard](#2-the-ireceiver-standard) +3. [Using ReceiverTemplate](#3-using-receivertemplate) +4. [Working with Simulation](#4-working-with-simulation) +5. [Advanced Usage](#5-advanced-usage-optional) +6. [Complete Examples](#6-complete-examples) +7. [Security Considerations](#7-security-considerations) ## 1. Core Concepts: The Onchain Data Flow @@ -2364,29 +2434,47 @@ To be a valid target for the `KeystoneForwarder`, your consumer contract must sa The `KeystoneForwarder` needs a standardized function to call. This is defined by the `IReceiver` interface, which mandates an `onReport` function. -```solidity +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC165} from "./IERC165.sol"; + +/// @title IReceiver - receives keystone reports +/// @notice Implementations must support the IReceiver interface through ERC165. interface IReceiver is IERC165 { - function onReport(bytes calldata metadata, bytes calldata report) external; + /// @notice Handles incoming keystone reports. + /// @dev If this function call reverts, it can be retried with a higher gas + /// limit. The receiver is responsible for discarding stale reports. + /// @param metadata Report's metadata. + /// @param report Workflow report. + function onReport( + bytes calldata metadata, + bytes calldata report + ) external; } ``` -- `metadata`: Contains information about the workflow (ID, name, owner). +- `metadata`: Contains information about the workflow (ID, name, owner). This is encoded by the Forwarder using `abi.encodePacked` with the following structure: `bytes32 workflowId`, `bytes10 workflowName`, `address workflowOwner`. - `report`: The raw, ABI-encoded data payload from your workflow. ### 2.2 Support ERC165 Interface Detection [ERC165](https://eips.ethereum.org/EIPS/eip-165) is a standard that allows contracts to publish the interfaces they support. The `KeystoneForwarder` uses this to check if your contract supports the `IReceiver` interface before sending a report. -## 3. Using `IReceiverTemplate` +Link to the `IERC165` interface: [IERC165.sol](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol) + +## 3. Using `ReceiverTemplate` ### 3.1 Overview -While you can implement these standards manually, we provide an abstract contract, `IReceiverTemplate.sol`, that does the heavy lifting for you. Inheriting from it is the recommended best practice. +While you can implement these standards manually, we provide an abstract contract, `ReceiverTemplate.sol`, that does the heavy lifting for you. Inheriting from it is the recommended best practice. **Key features:** -- **Optional Permission Controls**: Choose your security level—enable forwarder address checks, workflow ID validation, workflow owner verification, or any combination -- **Flexible and Updatable**: All permission settings can be configured and updated via setter functions after deployment +- **Secure by Default**: Requires forwarder address at deployment, ensuring your contract is protected from the start +- **Layered Security**: Add optional workflow ID validation, workflow owner verification, or any combination for defense-in-depth +- **Flexible Configuration**: All permission settings can be updated via setter functions after deployment - **Simplified Logic**: You only need to implement `_processReport(bytes calldata report)` with your business logic - **Built-in Access Control**: Includes OpenZeppelin's `Ownable` for secure permission management - **ERC165 Support**: Includes the necessary `supportsInterface` function @@ -2394,7 +2482,7 @@ While you can implement these standards manually, we provide an abstract contrac ### 3.2 Contract Source Code -```solidity +```sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; @@ -2402,159 +2490,267 @@ import {IERC165} from "./IERC165.sol"; import {IReceiver} from "./IReceiver.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -/// @title IReceiverTemplate - Abstract receiver with optional permission controls +/// @title ReceiverTemplate - Abstract receiver with optional permission controls /// @notice Provides flexible, updatable security checks for receiving workflow reports -/// @dev All permission fields default to zero (disabled). Use setter functions to enable checks. -abstract contract IReceiverTemplate is IReceiver, Ownable { - // Optional permission fields (all default to zero = disabled) - address public forwarderAddress; // If set, only this address can call onReport - address public expectedAuthor; // If set, only reports from this workflow owner are accepted - bytes10 public expectedWorkflowName; // If set, only reports with this workflow name are accepted - bytes32 public expectedWorkflowId; // If set, only reports from this specific workflow ID are accepted - - // Custom errors - error InvalidSender(address sender, address expected); - error InvalidAuthor(address received, address expected); - error InvalidWorkflowName(bytes10 received, bytes10 expected); - error InvalidWorkflowId(bytes32 received, bytes32 expected); - - /// @notice Constructor sets msg.sender as the owner - /// @dev All permission fields are initialized to zero (disabled by default) - constructor() Ownable(msg.sender) {} - - /// @inheritdoc IReceiver - /// @dev Performs optional validation checks based on which permission fields are set - function onReport(bytes calldata metadata, bytes calldata report) external override { - // Security Check 1: Verify caller is the trusted Chainlink Forwarder (if configured) - if (forwarderAddress != address(0) && msg.sender != forwarderAddress) { - revert InvalidSender(msg.sender, forwarderAddress); - } +/// @dev The forwarder address is required at construction time for security. +/// Additional permission fields can be configured using setter functions. +abstract contract ReceiverTemplate is IReceiver, Ownable { + // Required permission field at deployment, configurable after + address private s_forwarderAddress; // If set, only this address can call onReport + + // Optional permission fields (all default to zero = disabled) + address private s_expectedAuthor; // If set, only reports from this workflow owner are accepted + bytes10 private s_expectedWorkflowName; // Only validated when s_expectedAuthor is also set + bytes32 private s_expectedWorkflowId; // If set, only reports from this specific workflow ID are accepted + + // Hex character lookup table for bytes-to-hex conversion + bytes private constant HEX_CHARS = "0123456789abcdef"; + + // Custom errors + error InvalidForwarderAddress(); + error InvalidSender(address sender, address expected); + error InvalidAuthor(address received, address expected); + error InvalidWorkflowName(bytes10 received, bytes10 expected); + error InvalidWorkflowId(bytes32 received, bytes32 expected); + error WorkflowNameRequiresAuthorValidation(); + + // Events + event ForwarderAddressUpdated(address indexed previousForwarder, address indexed newForwarder); + event ExpectedAuthorUpdated(address indexed previousAuthor, address indexed newAuthor); + event ExpectedWorkflowNameUpdated(bytes10 indexed previousName, bytes10 indexed newName); + event ExpectedWorkflowIdUpdated(bytes32 indexed previousId, bytes32 indexed newId); + event SecurityWarning(string message); + + /// @notice Constructor sets msg.sender as the owner and configures the forwarder address + /// @param _forwarderAddress The address of the Chainlink Forwarder contract (cannot be address(0)) + /// @dev The forwarder address is required for security - it ensures only verified reports are processed + constructor( + address _forwarderAddress + ) Ownable(msg.sender) { + if (_forwarderAddress == address(0)) { + revert InvalidForwarderAddress(); + } + s_forwarderAddress = _forwarderAddress; + emit ForwarderAddressUpdated(address(0), _forwarderAddress); + } - // Security Checks 2-4: Verify workflow identity - ID, owner, and/or name (if any are configured) - if (expectedWorkflowId != bytes32(0) || expectedAuthor != address(0) || expectedWorkflowName != bytes10(0)) { - (bytes32 workflowId, bytes10 workflowName, address workflowOwner) = _decodeMetadata(metadata); + /// @notice Returns the configured forwarder address + /// @return The forwarder address (address(0) if disabled) + function getForwarderAddress() external view returns (address) { + return s_forwarderAddress; + } - if (expectedWorkflowId != bytes32(0) && workflowId != expectedWorkflowId) { - revert InvalidWorkflowId(workflowId, expectedWorkflowId); - } - if (expectedAuthor != address(0) && workflowOwner != expectedAuthor) { - revert InvalidAuthor(workflowOwner, expectedAuthor); - } - if (expectedWorkflowName != bytes10(0) && workflowName != expectedWorkflowName) { - revert InvalidWorkflowName(workflowName, expectedWorkflowName); - } - } + /// @notice Returns the expected workflow author address + /// @return The expected author address (address(0) if not set) + function getExpectedAuthor() external view returns (address) { + return s_expectedAuthor; + } - _processReport(report); - } + /// @notice Returns the expected workflow name + /// @return The expected workflow name (bytes10(0) if not set) + function getExpectedWorkflowName() external view returns (bytes10) { + return s_expectedWorkflowName; + } - /// @notice Updates the forwarder address that is allowed to call onReport - /// @param _forwarder The new forwarder address (use address(0) to disable this check) - function setForwarderAddress(address _forwarder) external onlyOwner { - forwarderAddress = _forwarder; - } + /// @notice Returns the expected workflow ID + /// @return The expected workflow ID (bytes32(0) if not set) + function getExpectedWorkflowId() external view returns (bytes32) { + return s_expectedWorkflowId; + } - /// @notice Updates the expected workflow owner address - /// @param _author The new expected author address (use address(0) to disable this check) - function setExpectedAuthor(address _author) external onlyOwner { - expectedAuthor = _author; + /// @inheritdoc IReceiver + /// @dev Performs optional validation checks based on which permission fields are set + function onReport( + bytes calldata metadata, + bytes calldata report + ) external override { + // Security Check 1: Verify caller is the trusted Chainlink Forwarder (if configured) + if (s_forwarderAddress != address(0) && msg.sender != s_forwarderAddress) { + revert InvalidSender(msg.sender, s_forwarderAddress); } - /// @notice Updates the expected workflow name from a plaintext string - /// @param _name The workflow name as a string (use empty string "" to disable this check) - /// @dev The name is hashed using SHA256 and truncated - function setExpectedWorkflowName(string calldata _name) external onlyOwner { - if (bytes(_name).length == 0) { - expectedWorkflowName = bytes10(0); - return; - } + // Security Checks 2-4: Verify workflow identity - ID, owner, and/or name (if any are configured) + if (s_expectedWorkflowId != bytes32(0) || s_expectedAuthor != address(0) || s_expectedWorkflowName != bytes10(0)) { + (bytes32 workflowId, bytes10 workflowName, address workflowOwner) = _decodeMetadata(metadata); - // Convert workflow name to bytes10: - // SHA256 hash → hex encode → take first 10 chars → hex encode those chars - bytes32 hash = sha256(bytes(_name)); - bytes memory hexString = _bytesToHexString(abi.encodePacked(hash)); - bytes memory first10 = new bytes(10); - for (uint i = 0; i < 10; i++) { - first10[i] = hexString[i]; + if (s_expectedWorkflowId != bytes32(0) && workflowId != s_expectedWorkflowId) { + revert InvalidWorkflowId(workflowId, s_expectedWorkflowId); + } + if (s_expectedAuthor != address(0) && workflowOwner != s_expectedAuthor) { + revert InvalidAuthor(workflowOwner, s_expectedAuthor); + } + + // ================================================================ + // WORKFLOW NAME VALIDATION - REQUIRES AUTHOR VALIDATION + // ================================================================ + // Do not rely on workflow name validation alone. Workflow names are unique + // per owner, but not across owners. + // Furthermore, workflow names use 40-bit truncation (bytes10), making collisions possible. + // Therefore, workflow name validation REQUIRES author (workflow owner) validation. + // The code enforces this dependency at runtime. + // ================================================================ + if (s_expectedWorkflowName != bytes10(0)) { + // Author must be configured if workflow name is used + if (s_expectedAuthor == address(0)) { + revert WorkflowNameRequiresAuthorValidation(); + } + // Validate workflow name matches (author already validated above) + if (workflowName != s_expectedWorkflowName) { + revert InvalidWorkflowName(workflowName, s_expectedWorkflowName); } - expectedWorkflowName = bytes10(first10); + } } - /// @notice Updates the expected workflow ID - /// @param _id The new expected workflow ID (use bytes32(0) to disable this check) - function setExpectedWorkflowId(bytes32 _id) external onlyOwner { - expectedWorkflowId = _id; + _processReport(report); + } + + /// @notice Updates the forwarder address that is allowed to call onReport + /// @param _forwarder The new forwarder address + /// @dev WARNING: Setting to address(0) disables forwarder validation. + /// This makes your contract INSECURE - anyone can call onReport() with arbitrary data. + /// Only use address(0) if you fully understand the security implications. + function setForwarderAddress( + address _forwarder + ) external onlyOwner { + address previousForwarder = s_forwarderAddress; + + // Emit warning if disabling forwarder check + if (_forwarder == address(0)) { + emit SecurityWarning("Forwarder address set to zero - contract is now INSECURE"); } - /// @notice Helper function to convert bytes to hex string - /// @param data The bytes to convert - /// @return The hex string representation - function _bytesToHexString(bytes memory data) private pure returns (bytes memory) { - bytes memory hexChars = "0123456789abcdef"; - bytes memory hexString = new bytes(data.length * 2); + s_forwarderAddress = _forwarder; + emit ForwarderAddressUpdated(previousForwarder, _forwarder); + } - for (uint256 i = 0; i < data.length; i++) { - hexString[i * 2] = hexChars[uint8(data[i] >> 4)]; - hexString[i * 2 + 1] = hexChars[uint8(data[i] & 0x0f)]; - } + /// @notice Updates the expected workflow owner address + /// @param _author The new expected author address (use address(0) to disable this check) + function setExpectedAuthor( + address _author + ) external onlyOwner { + address previousAuthor = s_expectedAuthor; + s_expectedAuthor = _author; + emit ExpectedAuthorUpdated(previousAuthor, _author); + } - return hexString; + /// @notice Updates the expected workflow name from a plaintext string + /// @param _name The workflow name as a string (use empty string "" to disable this check) + /// @dev IMPORTANT: Workflow name validation REQUIRES author validation to be enabled. + /// The workflow name uses only 40-bit truncation, making collision attacks feasible + /// when used alone. However, since workflow names are unique per owner, validating + /// both the name AND the author address provides adequate security. + /// You must call setExpectedAuthor() before or after calling this function. + /// The name is hashed using SHA256 and truncated to bytes10. + function setExpectedWorkflowName( + string calldata _name + ) external onlyOwner { + bytes10 previousName = s_expectedWorkflowName; + + if (bytes(_name).length == 0) { + s_expectedWorkflowName = bytes10(0); + emit ExpectedWorkflowNameUpdated(previousName, bytes10(0)); + return; } - /// @notice Extracts all metadata fields from the onReport metadata parameter - /// @param metadata The metadata in bytes format - /// @return workflowId The unique identifier of the workflow (bytes32) - /// @return workflowName The name of the workflow (bytes10) - /// @return workflowOwner The owner address of the workflow - function _decodeMetadata(bytes memory metadata) - internal - pure - returns (bytes32 workflowId, bytes10 workflowName, address workflowOwner) - { - // Metadata structure: - // - First 32 bytes: length of the byte array (standard for dynamic bytes) - // - Offset 32, size 32: workflow_id (bytes32) - // - Offset 64, size 10: workflow_name (bytes10) - // - Offset 74, size 20: workflow_owner (address) - assembly { - workflowId := mload(add(metadata, 32)) - workflowName := mload(add(metadata, 64)) - workflowOwner := shr(mul(12, 8), mload(add(metadata, 74))) - } + // Convert workflow name to bytes10: + // SHA256 hash → hex encode → take first 10 chars → hex encode those chars + bytes32 hash = sha256(bytes(_name)); + bytes memory hexString = _bytesToHexString(abi.encodePacked(hash)); + bytes memory first10 = new bytes(10); + for (uint256 i = 0; i < 10; i++) { + first10[i] = hexString[i]; + } + s_expectedWorkflowName = bytes10(first10); + emit ExpectedWorkflowNameUpdated(previousName, s_expectedWorkflowName); + } + + /// @notice Updates the expected workflow ID + /// @param _id The new expected workflow ID (use bytes32(0) to disable this check) + function setExpectedWorkflowId( + bytes32 _id + ) external onlyOwner { + bytes32 previousId = s_expectedWorkflowId; + s_expectedWorkflowId = _id; + emit ExpectedWorkflowIdUpdated(previousId, _id); + } + + /// @notice Helper function to convert bytes to hex string + /// @param data The bytes to convert + /// @return The hex string representation + function _bytesToHexString( + bytes memory data + ) private pure returns (bytes memory) { + bytes memory hexString = new bytes(data.length * 2); + + for (uint256 i = 0; i < data.length; i++) { + hexString[i * 2] = HEX_CHARS[uint8(data[i] >> 4)]; + hexString[i * 2 + 1] = HEX_CHARS[uint8(data[i] & 0x0f)]; } - /// @notice Abstract function to process the report data - /// @param report The report calldata containing your workflow's encoded data - /// @dev Implement this function with your contract's business logic - function _processReport(bytes calldata report) internal virtual; + return hexString; + } - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { - return interfaceId == type(IReceiver).interfaceId || interfaceId == type(IERC165).interfaceId; + /// @notice Extracts all metadata fields from the onReport metadata parameter + /// @param metadata The metadata bytes encoded using abi.encodePacked(workflowId, workflowName, workflowOwner) + /// @return workflowId The unique identifier of the workflow (bytes32) + /// @return workflowName The name of the workflow (bytes10) + /// @return workflowOwner The owner address of the workflow + function _decodeMetadata( + bytes memory metadata + ) internal pure returns (bytes32 workflowId, bytes10 workflowName, address workflowOwner) { + // Metadata structure (encoded using abi.encodePacked by the Forwarder): + // - First 32 bytes: length of the byte array (standard for dynamic bytes) + // - Offset 32, size 32: workflow_id (bytes32) + // - Offset 64, size 10: workflow_name (bytes10) + // - Offset 74, size 20: workflow_owner (address) + assembly { + workflowId := mload(add(metadata, 32)) + workflowName := mload(add(metadata, 64)) + workflowOwner := shr(mul(12, 8), mload(add(metadata, 74))) } + return (workflowId, workflowName, workflowOwner); + } + + /// @notice Abstract function to process the report data + /// @param report The report calldata containing your workflow's encoded data + /// @dev Implement this function with your contract's business logic + function _processReport( + bytes calldata report + ) internal virtual; + + /// @inheritdoc IERC165 + function supportsInterface( + bytes4 interfaceId + ) public view virtual override returns (bool) { + return interfaceId == type(IReceiver).interfaceId || interfaceId == type(IERC165).interfaceId; + } } ``` ### 3.3 Quick Start -The simplest way to use `IReceiverTemplate` is to inherit from it and implement the `_processReport` function: +The simplest way to use `ReceiverTemplate` is to inherit from it and implement the `_processReport` function: -```solidity +```sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -import { IReceiverTemplate } from "./IReceiverTemplate.sol"; +import {ReceiverTemplate} from "./ReceiverTemplate.sol"; -contract MyConsumer is IReceiverTemplate { - uint256 public storedValue; +contract MyConsumer is ReceiverTemplate { + uint256 public s_storedValue; event ValueUpdated(uint256 newValue); - // Simple constructor - no parameters needed - constructor() IReceiverTemplate() {} + // Constructor requires forwarder address + constructor( + address _forwarderAddress + ) ReceiverTemplate(_forwarderAddress) {} // Implement your business logic here - function _processReport(bytes calldata report) internal override { + function _processReport( + bytes calldata report + ) internal override { uint256 newValue = abi.decode(report, (uint256)); - storedValue = newValue; + s_storedValue = newValue; emit ValueUpdated(newValue); } } @@ -2562,7 +2758,7 @@ contract MyConsumer is IReceiverTemplate { ### 3.4 Configuring Permissions -After deploying your contract, the owner can enable any combination of security checks using the setter functions. +The forwarder address is configured at deployment via the constructor and provides your first line of defense. After deploying your contract, the owner can configure additional security checks or update the forwarder address if needed. <Aside type="caution" title="For simulation"> @@ -2571,21 +2767,23 @@ After deploying your contract, the owner can enable any combination of security <Aside type="tip" title="Finding forwarder addresses"> - For a complete list of `KeystoneForwarder` contract addresses on all supported networks, see [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks). + For a complete list of `KeystoneForwarder` and `MockForwarder` contract addresses on all supported networks, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). </Aside> **Configuration examples:** ```solidity -// Example: Enable forwarder check only -myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia +// Example: Update forwarder address (e.g., when moving from simulation to production) +myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia KeystoneForwarder -// Example: Enable workflow ID check +// Example: Add workflow ID check for additional security myConsumer.setExpectedWorkflowId(0x1234...); // Your specific workflow ID -// Example: Enable workflow owner and name checks +// Example: Add workflow owner check myConsumer.setExpectedAuthor(0xYourAddress...); -myConsumer.setExpectedWorkflowName("my_workflow"); // The plaintext workflow name + +// Example: Add workflow name check (requires author validation to be set) +myConsumer.setExpectedWorkflowName("my_workflow"); // Example: Disable a check later myConsumer.setExpectedWorkflowName(""); // Empty string disables the check @@ -2593,27 +2791,31 @@ myConsumer.setExpectedWorkflowName(""); // Empty string disables the check <Aside type="tip" title="Recommended production setup"> - For production contracts, we recommend enabling at minimum the `forwarderAddress` check. For highest security, combine it with `expectedWorkflowId` to ensure only your specific workflow can update the contract. + The forwarder address is required at deployment and provides basic security. For production contracts, we strongly recommend adding additional validation: + + - Use `setExpectedWorkflowId()` if only one workflow writes to your contract (highest security) + - Use `setExpectedAuthor()` if multiple workflows from the same owner write to your contract </Aside> **What the template handles for you:** -- Validates the caller address (if `forwarderAddress` is set) -- Validates the workflow ID (if `expectedWorkflowId` is set) -- Validates the workflow owner (if `expectedAuthor` is set) -- Validates the workflow name (if `expectedWorkflowName` is set) -- Validates the ERC165 interface detection -- Validates the Access control via OpenZeppelin's `Ownable` +- Validates the caller address against the configured forwarder (required at deployment) +- Validates the workflow ID (if `expectedWorkflowId` is configured) +- Validates the workflow owner (if `expectedAuthor` is configured) +- Validates the workflow name (if both `expectedWorkflowName` AND `expectedAuthor` are configured) +- Implements ERC165 interface detection +- Provides access control via OpenZeppelin's `Ownable` - Calls your `_processReport` function with validated data **What you implement:** +- Pass the forwarder address to the constructor during deployment - Your business logic in `_processReport` -- (Optional) Configure permissions after deployment using setter functions +- (Optional) Configure additional permissions after deployment using setter functions #### How workflow names are encoded -The `workflowName` field in the metadata uses the **`bytes10`** type rather than plaintext strings. When you call `setExpectedWorkflowName("my_workflow")`, the `IReceiverTemplate` automatically encodes it using the same algorithm as the CRE engine: +The `workflowName` field in the metadata uses the **`bytes10`** type rather than plaintext strings. When you call `setExpectedWorkflowName("my_workflow")`, the `ReceiverTemplate` automatically encodes it using the same algorithm as the CRE engine: 1. Compute SHA256 hash of the workflow name 2. Convert hash to hex string (64 characters) @@ -2624,14 +2826,22 @@ The `workflowName` field in the metadata uses the **`bytes10`** type rather than This encoding ensures consistent, fixed-size representation regardless of the original workflow name length. + +<Aside type="caution" title="Workflow name validation requires author validation"> + Workflow name validation is **only performed when author validation is also configured**. The code enforces this at runtime: if you set `expectedWorkflowName`, you must also set `expectedAuthor`, otherwise the validation will revert with `WorkflowNameRequiresAuthorValidation()`. This prevents the 40-bit collision attack by ensuring workflow names are validated in combination with the owner address. See [Security Considerations](#7-security-considerations) for details. +</Aside> + **Usage:** ```solidity -// Just use the plaintext workflow name - the interface handles the encoding automatically +// Set the expected author first (required) +myConsumer.setExpectedAuthor(0xYourAddress...); + +// Then set the expected workflow name (only works with author validation) myConsumer.setExpectedWorkflowName("my_workflow"); -// To disable the check later -myConsumer.setExpectedWorkflowName(""); // Empty string disables the check +// To disable the workflow name check +myConsumer.setExpectedWorkflowName(""); // Empty string clears the stored value ``` ## 4. Working with Simulation @@ -2642,20 +2852,21 @@ When you run `cre workflow simulate`, your workflow interacts with a **`MockKeys This is a **temporary limitation** until the `MockKeystoneForwarder` is updated to provide full metadata. </Aside> -### Forwarder address validation +### Deploying for Simulation -You **can** configure the forwarder address check during simulation using the **Mock Forwarder Address**: +When deploying your consumer contract for simulation, pass the **Mock Forwarder address** to the constructor: ```solidity -// Example: Use Mock Forwarder for Ethereum Sepolia simulation -myConsumer.setForwarderAddress(0x15fC6ae953E024d975e77382eEeC56A9101f9F88); +// Deploy with MockForwarder address for Ethereum Sepolia simulation +address mockForwarder = 0x15fC6ae953E024d975e77382eEeC56A9101f9F88; // Ethereum Sepolia MockForwarder +MyConsumer myConsumer = new MyConsumer(mockForwarder); ``` -Find Mock Forwarder addresses for all networks in the [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks) page. +Find Mock Forwarder addresses for all networks in the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) page. <Aside type="caution" title="Important: Different addresses for simulation vs production"> - The `MockKeystoneForwarder` address used during simulation is **different** from the `KeystoneForwarder` address used by deployed workflows. If you configure the forwarder address for simulation, remember to update it to the production `KeystoneForwarder` address after deploying. See [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks) for forwarder addresses. + The `MockKeystoneForwarder` address used during simulation is **different** from the `KeystoneForwarder` address used by deployed workflows. After testing with simulation, deploy a new instance with the production `KeystoneForwarder` address, or update the forwarder address using `setForwarderAddress()`. See [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) for forwarder addresses. </Aside> ### Metadata-based validation @@ -2668,18 +2879,28 @@ Find Mock Forwarder addresses for all networks in the [Supported Networks](/cre/ Setting any of these will cause your simulation to fail. -### After deployment +### Transitioning to Production + +Once you're ready to deploy your workflow to production: + +**Option 1: Deploy a new contract instance** + +```solidity +// Deploy with production KeystoneForwarder address +address keystoneForwarder = 0xF8344CFd5c43616a4366C34E3EEE75af79a74482; // Ethereum Sepolia +MyConsumer myConsumer = new MyConsumer(keystoneForwarder); -Once you deploy your workflow: +// Configure additional security checks +myConsumer.setExpectedWorkflowId(0xYourWorkflowId); +``` -1. Update the forwarder address to the real `KeystoneForwarder` (if you configured it for simulation) -2. Configure additional metadata-based validation as needed +**Option 2: Update existing contract's forwarder** ```solidity -// Update to production KeystoneForwarder address -myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Example: Ethereum Sepolia +// Update forwarder to production KeystoneForwarder +myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia -// Now you can enable metadata-based validation +// Add metadata-based validation myConsumer.setExpectedWorkflowId(0xYourWorkflowId); ``` @@ -2692,25 +2913,29 @@ See [Configuring Permissions](#34-configuring-permissions) for complete details. You can override `onReport` to add your own validation logic before or after the standard checks: ```solidity -import { IReceiverTemplate } from "./IReceiverTemplate.sol"; +import { ReceiverTemplate } from "./ReceiverTemplate.sol"; -contract AdvancedConsumer is IReceiverTemplate { - uint256 public minReportInterval = 1 hours; - uint256 public lastReportTime; +contract AdvancedConsumer is ReceiverTemplate { + uint256 private s_minReportInterval = 1 hours; + uint256 private s_lastReportTime; error ReportTooFrequent(uint256 timeSinceLastReport, uint256 minInterval); + event MinReportIntervalUpdated(uint256 previousInterval, uint256 newInterval); + + constructor(address _forwarderAddress) ReceiverTemplate(_forwarderAddress) {} + // Add custom validation before parent's checks function onReport(bytes calldata metadata, bytes calldata report) external override { // Custom check: Rate limiting - if (block.timestamp < lastReportTime + minReportInterval) { - revert ReportTooFrequent(block.timestamp - lastReportTime, minReportInterval); + if (block.timestamp < s_lastReportTime + s_minReportInterval) { + revert ReportTooFrequent(block.timestamp - s_lastReportTime, s_minReportInterval); } // Call parent implementation for standard permission checks super.onReport(metadata, report); - lastReportTime = block.timestamp; + s_lastReportTime = block.timestamp; } function _processReport(bytes calldata report) internal override { @@ -2719,9 +2944,24 @@ contract AdvancedConsumer is IReceiverTemplate { // ... store or process the value ... } - // Allow owner to update rate limit + /// @notice Returns the minimum interval between reports + /// @return The minimum interval in seconds + function getMinReportInterval() external view returns (uint256) { + return s_minReportInterval; + } + + /// @notice Returns the timestamp of the last report + /// @return The last report timestamp + function getLastReportTime() external view returns (uint256) { + return s_lastReportTime; + } + + /// @notice Updates the minimum interval between reports + /// @param _interval The new minimum interval in seconds function setMinReportInterval(uint256 _interval) external onlyOwner { - minReportInterval = _interval; + uint256 previousInterval = s_minReportInterval; + s_minReportInterval = _interval; + emit MinReportIntervalUpdated(previousInterval, _interval); } } ``` @@ -2731,8 +2971,10 @@ contract AdvancedConsumer is IReceiverTemplate { The `_decodeMetadata` helper function is available for use in your `_processReport` implementation. This allows you to access workflow metadata for custom business logic: ```solidity -contract MetadataAwareConsumer is IReceiverTemplate { - mapping(bytes32 => uint256) public reportCountByWorkflow; +contract MetadataAwareConsumer is ReceiverTemplate { + mapping(bytes32 => uint256) public s_reportCountByWorkflow; + + constructor(address _forwarderAddress) ReceiverTemplate(_forwarderAddress) {} function _processReport(bytes calldata report) internal override { // Access the metadata to get workflow ID @@ -2740,7 +2982,7 @@ contract MetadataAwareConsumer is IReceiverTemplate { (bytes32 workflowId, , ) = _decodeMetadata(metadata); // Use workflow ID in your business logic - reportCountByWorkflow[workflowId]++; + s_reportCountByWorkflow[workflowId]++; // Process the report data uint256 value = abi.decode(report, (uint256)); @@ -2758,35 +3000,44 @@ contract MetadataAwareConsumer is IReceiverTemplate { ### Example 1: Simple Consumer Contract -This example inherits from `IReceiverTemplate` to store a temperature value. +This example inherits from `ReceiverTemplate` to store a temperature value. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -import { IReceiverTemplate } from "./IReceiverTemplate.sol"; +import { ReceiverTemplate } from "./ReceiverTemplate.sol"; -contract TemperatureConsumer is IReceiverTemplate { - int256 public currentTemperature; +contract TemperatureConsumer is ReceiverTemplate { + int256 public s_currentTemperature; event TemperatureUpdated(int256 newTemperature); - // Simple constructor - no parameters needed - constructor() IReceiverTemplate() {} + // Constructor requires forwarder address + constructor(address _forwarderAddress) ReceiverTemplate(_forwarderAddress) {} function _processReport(bytes calldata report) internal override { int256 newTemperature = abi.decode(report, (int256)); - currentTemperature = newTemperature; + s_currentTemperature = newTemperature; emit TemperatureUpdated(newTemperature); } } ``` -**Configuring permissions after deployment:** +**Deployment:** ```solidity -// Enable forwarder check for production -temperatureConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia +// For simulation: Use MockForwarder address +address mockForwarder = 0x15fC6ae953E024d975e77382eEeC56A9101f9F88; // e.g. Ethereum Sepolia +TemperatureConsumer temperatureConsumer = new TemperatureConsumer(mockForwarder); -// Enable workflow ID check for highest security +// For production: Use KeystoneForwarder address +address keystoneForwarder = 0xF8344CFd5c43616a4366C34E3EEE75af79a74482; // e.g. Ethereum Sepolia +TemperatureConsumer temperatureConsumer = new TemperatureConsumer(keystoneForwarder); +``` + +**Adding additional security after deployment:** + +```solidity +// Add workflow ID check for highest security temperatureConsumer.setExpectedWorkflowId(0xYourWorkflowId...); ``` @@ -2795,7 +3046,7 @@ temperatureConsumer.setExpectedWorkflowId(0xYourWorkflowId...); For more complex scenarios, it's best to separate your Chainlink-aware code from your core business logic. The **Proxy Pattern** is a robust architecture that uses two contracts to achieve this: - **A Logic Contract**: Holds the state and the core functions of your application. It knows nothing about the Forwarder contract or the `onReport` function. -- **A Proxy Contract**: Acts as the secure entry point. It inherits from `IReceiverTemplate` and forwards validated reports to the Logic Contract. +- **A Proxy Contract**: Acts as the secure entry point. It inherits from `ReceiverTemplate` and forwards validated reports to the Logic Contract. This separation makes your business logic more modular and reusable. @@ -2815,28 +3066,59 @@ contract ReserveManager is Ownable { uint256 btcPrice; } - address public proxyAddress; - uint256 public lastEthPrice; - uint256 public lastBtcPrice; - uint256 public lastUpdateTime; + address private s_proxyAddress; + uint256 private s_lastEthPrice; + uint256 private s_lastBtcPrice; + uint256 private s_lastUpdateTime; event ReservesUpdated(uint256 ethPrice, uint256 btcPrice, uint256 updateTime); + event ProxyAddressUpdated(address indexed previousProxy, address indexed newProxy); modifier onlyProxy() { - require(msg.sender == proxyAddress, "Caller is not the authorized proxy"); + require(msg.sender == s_proxyAddress, "Caller is not the authorized proxy"); _; } constructor() Ownable(msg.sender) {} + /// @notice Returns the proxy address + /// @return The authorized proxy address + function getProxyAddress() external view returns (address) { + return s_proxyAddress; + } + + /// @notice Returns the last ETH price + /// @return The last recorded ETH price + function getLastEthPrice() external view returns (uint256) { + return s_lastEthPrice; + } + + /// @notice Returns the last BTC price + /// @return The last recorded BTC price + function getLastBtcPrice() external view returns (uint256) { + return s_lastBtcPrice; + } + + /// @notice Returns the last update timestamp + /// @return The timestamp of the last update + function getLastUpdateTime() external view returns (uint256) { + return s_lastUpdateTime; + } + + /// @notice Updates the authorized proxy address + /// @param _proxyAddress The new proxy address function setProxyAddress(address _proxyAddress) external onlyOwner { - proxyAddress = _proxyAddress; + address previousProxy = s_proxyAddress; + s_proxyAddress = _proxyAddress; + emit ProxyAddressUpdated(previousProxy, _proxyAddress); } + /// @notice Updates the reserve prices + /// @param data The new reserve data containing ETH and BTC prices function updateReserves(UpdateReserves memory data) external onlyProxy { - lastEthPrice = data.ethPrice; - lastBtcPrice = data.btcPrice; - lastUpdateTime = block.timestamp; + s_lastEthPrice = data.ethPrice; + s_lastBtcPrice = data.btcPrice; + s_lastUpdateTime = block.timestamp; emit ReservesUpdated(data.ethPrice, data.btcPrice, block.timestamp); } } @@ -2844,23 +3126,29 @@ contract ReserveManager is Ownable { #### The Proxy Contract (`UpdateReservesProxy.sol`) -This contract, our "bouncer", is the only contract that interacts with the Chainlink platform. It inherits `IReceiverTemplate` to validate incoming reports and then calls the `ReserveManager`. +This contract, our "bouncer", is the only contract that interacts with the Chainlink platform. It inherits `ReceiverTemplate` to validate incoming reports and then calls the `ReserveManager`. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ReserveManager } from "./ReserveManager.sol"; -import { IReceiverTemplate } from "./keystone/IReceiverTemplate.sol"; +import { ReceiverTemplate } from "./ReceiverTemplate.sol"; -contract UpdateReservesProxy is IReceiverTemplate { - ReserveManager public s_reserveManager; +contract UpdateReservesProxy is ReceiverTemplate { + ReserveManager private s_reserveManager; - constructor(address reserveManagerAddress) { + constructor(address _forwarderAddress, address reserveManagerAddress) ReceiverTemplate(_forwarderAddress) { s_reserveManager = ReserveManager(reserveManagerAddress); } - /// @inheritdoc IReceiverTemplate + /// @notice Returns the reserve manager contract address + /// @return The ReserveManager contract instance + function getReserveManager() external view returns (ReserveManager) { + return s_reserveManager; + } + + /// @inheritdoc ReceiverTemplate function _processReport(bytes calldata report) internal override { ReserveManager.UpdateReserves memory updateReservesData = abi.decode(report, (ReserveManager.UpdateReserves)); s_reserveManager.updateReserves(updateReservesData); @@ -2871,16 +3159,13 @@ contract UpdateReservesProxy is IReceiverTemplate { **Configuring permissions after deployment:** ```solidity -// Enable forwarder check (recommended) -updateReservesProxy.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia - -// Enable workflow ID check for production (highest security) +// Additional validation can be added after deployment updateReservesProxy.setExpectedWorkflowId(0xYourWorkflowId...); ``` <Aside type="note" title="KeystoneForwarder address shown"> - The examples above use the Ethereum Sepolia forwarder address. For other networks, see [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks). + The examples above use the Ethereum Sepolia forwarder address. For other networks, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). </Aside> #### How it Works @@ -2888,7 +3173,7 @@ updateReservesProxy.setExpectedWorkflowId(0xYourWorkflowId...); The deployment and configuration process involves these steps: 1. **Deploy the Logic Contract**: Deploy `ReserveManager.sol`. The wallet that deploys this contract becomes its `owner`. -2. **Deploy the Proxy Contract**: Deploy `UpdateReservesProxy.sol`, passing the address of the deployed `ReserveManager` contract to its constructor. +2. **Deploy the Proxy Contract**: Deploy `UpdateReservesProxy.sol`, passing the forwarder address and the address of the deployed `ReserveManager` contract to its constructor. 3. **Link the Contracts**: The `owner` of the `ReserveManager` contract must call its `setProxyAddress` function, passing in the address of the `UpdateReservesProxy` contract. This authorizes the proxy to call the logic contract. 4. **Configure Permissions** (Recommended): The `owner` of the proxy should call setter functions to enable security checks: ```solidity @@ -2898,21 +3183,67 @@ The deployment and configuration process involves these steps: 5. **Configure Workflow**: In your workflow's `config.json`, use the address of the **Proxy Contract** as the receiver address. 6. **Execution Flow**: When your workflow runs: - The Chainlink Forwarder calls `onReport` on your **Proxy** - - The Proxy validates the report (forwarder address, workflow ID, etc.) + - The Proxy validates the report (forwarder address is verified automatically; additional checks like workflow ID can be added) - The Proxy's `_processReport` function calls the `updateReserves` function on your **Logic Contract** - Because the caller is the trusted proxy, the `onlyProxy` check passes, and your state is securely updated 7. **(Optional) Upgrade**: If you later need to deploy a new proxy, the owner can: - - Deploy the new proxy contract + - Deploy the new proxy contract with the appropriate forwarder address - Call `setProxyAddress` on the `ReserveManager` to point it to the new proxy's address - Update the workflow configuration to use the new proxy address #### End-to-End Sequence -## Where to go next? +## 7. Security Considerations + +### Forwarder address + +**The forwarder address is the foundation of your contract's security.** The `KeystoneForwarder` contract performs cryptographic verification of DON signatures before calling your consumer. By requiring the forwarder address in the constructor, `ReceiverTemplate` ensures your contract is secure from deployment. + + +<Aside type="caution" title="Never set forwarder to address(0) in production"> + While the `setForwarderAddress()` function allows updating to `address(0)`, this disables the critical security check and allows **anyone** to call your `onReport()` function with arbitrary data. The function emits a `SecurityWarning` event if you attempt this. Only use `address(0)` for testing if you fully understand the implications. +</Aside> + +### Replay protection + +The `KeystoneForwarder` contract includes built-in replay protection that prevents successful reports from being executed multiple times. By requiring the forwarder address at construction time, `ReceiverTemplate` ensures your consumer benefits from this protection automatically. + + +<Aside type="note" title="Failed reports can be retried"> + If a report fails (reverts), the forwarder's replay protection allows it to be retried. This is safe because reverts undo all state changes, ensuring no duplicate effects occur in your contract. +</Aside> + +### Additional validation layers + +The forwarder address provides baseline security, but you can add additional validation for defense-in-depth: + +- **`expectedWorkflowId`**: Ensures only one specific workflow can update your contract. Use this when a single workflow writes to your consumer (highest security for single-workflow scenarios). +- **`expectedAuthor`**: Restricts to workflows owned by a specific address. Use this when multiple workflows from the same owner should access your contract. +- **`expectedWorkflowName`**: Can be used in combination with `expectedAuthor` for additional validation. Requires author validation to be configured. See [Workflow name validation](#workflow-name-validation) below. + +### Workflow name validation + + +<Aside type="caution" title="Workflow name validation requires author validation"> + The `expectedWorkflowName` check in `ReceiverTemplate.onReport()` **requires author validation** to be configured: + + - **Collision Risk**: Workflow names use only 40-bit truncation (bytes10), making collision attacks computationally feasible when used alone + - **Unique per owner**: Workflow names are unique per owner but not across different owners + - **Runtime enforcement**: The code enforces that if `expectedWorkflowName` is set, `expectedAuthor` must also be set, otherwise it reverts with `WorkflowNameRequiresAuthorValidation()` + + By combining workflow name (40-bit) with author validation (160-bit address), the contract achieves adequate collision resistance. You can safely use workflow name validation as long as author validation is also enabled. +</Aside> -Now that you know how to build a consumer contract, the next step is to call it from your workflow. +### Best practices -- **[Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write)**: Learn how to use the `EVMClient` to send data to your new consumer contract. +1. **Always deploy with a valid forwarder address** - The constructor requires this for security. Use `MockForwarder` for simulation, `KeystoneForwarder` for production. Forwarder addresses are available in the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) page. +2. **Add additional validation for production**: + - **Single workflow**: Use `setExpectedWorkflowId()` to restrict to one specific workflow (highest security) + - **Multiple workflows from same owner**: Use `setExpectedAuthor()` to restrict to workflows you own + - **Multiple workflows from different owners**: Implement custom validation logic in your `onReport()` override +3. **Keep your owner key secure** - The owner can update all permission settings +4. **Test permission configurations** - Verify your security settings work as expected before production deployment +5. **Workflow name validation** - Can be used with `setExpectedWorkflowName()` but requires `setExpectedAuthor()` to also be configured for security --- @@ -2927,7 +3258,7 @@ This guide explains how to write data to a smart contract using the `WriteReport - You're sending a **struct** to your consumer contract - The struct appears in a `public` or `external` function's signature (as a parameter or return value); this is required for the binding generator to detect it in your contract's ABI and create the helper method -**Don't meet these requirements?** See the [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write#choosing-your-approach-which-guide-should-you-follow) page to find the right approach for your scenario. +**Don't meet these requirements?** See the [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview-go#choosing-your-approach-which-guide-should-you-follow) page to find the right approach for your scenario. ## Prerequisites @@ -3457,7 +3788,7 @@ func main() { ## Learn more -- **[Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write)**: Understand all onchain write approaches +- **[Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview)**: Understand all onchain write approaches - **[Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain)**: Submit your generated report to the blockchain - **[Generating Reports: Structs](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-structs)**: Manually encode and generate reports for struct data - **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Create contracts that can receive your reports @@ -4082,7 +4413,7 @@ By default, `cre workflow simulate` performs a dry run without broadcasting tran cre workflow simulate my-workflow --broadcast --target staging-settings ``` -See the [CLI Reference](/cre/reference/cli#cre-workflow-simulate) for more details. +See the [CLI Reference](/cre/reference/cli/workflow#cre-workflow-simulate) for more details. ## Troubleshooting @@ -4131,10 +4462,15 @@ See the [CLI Reference](/cre/reference/cli#cre-workflow-simulate) for more detai # API Interactions Source: https://docs.chain.link/cre/guides/workflow/using-http-client -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 The CRE SDK provides an HTTP client that allows your workflows to interact with external APIs. Use it to fetch offchain data, send results to other systems, or trigger external events. + +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.now()` instead of `Date.now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + These guides will walk you through the common use cases for the HTTP client. ## Guides @@ -4145,6 +4481,25 @@ These guides will walk you through the common use cases for the HTTP client. --- +# Confidential API Interactions (Experimental) +Source: https://docs.chain.link/cre/guides/workflow/using-confidential-http-client +Last Updated: 2026-02-06 + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The CRE SDK provides a Confidential HTTP client that allows your workflows to interact with external APIs while keeping sensitive data private. Requests execute inside a secure enclave, secrets are injected via templates, and responses can optionally be encrypted. + +For a conceptual overview of what Confidential HTTP is and how it differs from the regular HTTP capability, see [The Confidential HTTP Capability](/cre/capabilities/confidential-http). + +## Guides + +- **[Making Confidential Requests](/cre/guides/workflow/using-confidential-http-client/making-requests)**: Learn how to make a confidential HTTP request with secret injection and optional response encryption. + +--- + # Managing Secrets Source: https://docs.chain.link/cre/guides/workflow/secrets Last Updated: 2025-11-04 @@ -4228,7 +4583,7 @@ For detailed CLI command documentation, see: # Using Secrets with Deployed Workflows Source: https://docs.chain.link/cre/guides/workflow/secrets/using-secrets-deployed -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 When your workflow is deployed, it cannot access your local `.env` file or environment variables. Instead, secrets must be stored in the **Vault DON**—a decentralized, secure secret storage system that your deployed workflows can access at runtime. @@ -4584,6 +4939,226 @@ By following this pattern, you can manage your secrets securely without ever exp --- +# Using Randomness in Workflows +Source: https://docs.chain.link/cre/guides/workflow/using-randomness +Last Updated: 2026-02-05 + +<Aside type="note" title="TL;DR"> + Use `runtime.Rand()` to generate random numbers in your workflows. This provides secure, deterministic randomness that + enables all nodes in the network to reach consensus. Do **not** use Go's global `rand` package—it can break consensus. +</Aside> + +## The problem: Why randomness needs special handling + +Workflows often need randomness for various purposes: generating nonces, selecting winners from a list, or creating unpredictable values. However, in a decentralized network, naive use of random number generators creates a critical problem: + +**If each node generates different random values, they cannot reach consensus on the workflow's output.** + +For example, if your workflow selects a lottery winner using each node's local random generator, different nodes would select different winners, making it impossible to agree on a single result to write onchain. + +## The solution: Consensus-safe randomness + +CRE provides randomness through the `runtime.Rand()` method, which returns a standard Go `*rand.Rand` object. This random generator is managed by the CRE platform to ensure all nodes generate the same sequence of random values, enabling consensus while still providing unpredictability across different workflow executions. + +### Usage + +```go +// Get the random generator from the runtime +rnd, err := runtime.Rand() +if err != nil { + return err +} + +// Use it with standard Go rand methods +randomInt := rnd.Intn(100) // Random int in [0, 100) +randomBigInt := new(big.Int).Rand(rnd, big.NewInt(1000)) // Random big.Int +``` + +## Common use cases + +- Selecting a winner from a lottery or pool +- Generating nonces for transactions +- Creating random identifiers or values +- Any random selection that needs to be agreed upon by all nodes + +## Working with big.Int random values + +For Solidity `uint256` types, you often need random `*big.Int` values: + +```go +rnd, err := runtime.Rand() +if err != nil { + return err +} + +// Generate a random number in the range [0, max) +max := new(big.Int) +max.SetString("1000000000000000000", 10) // 1 ETH in wei + +randomAmount := new(big.Int).Rand(rnd, max) +// randomAmount is a random value between 0 and 1 ETH +``` + +## Complete example: Random lottery + +Here's a complete example that demonstrates using DON mode randomness to select a lottery winner and generate a prize amount: + +```go +//go:build wasip1 + +package main + +import ( + "fmt" + "log/slog" + "math/big" + + "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" + "github.com/smartcontractkit/cre-sdk-go/cre" + "github.com/smartcontractkit/cre-sdk-go/cre/wasm" +) + +type Config struct { + Schedule string `json:"schedule"` +} + +type MyResult struct { + WinnerIndex int + Winner string + RandomBigInt string +} + +func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { + return cre.Workflow[*Config]{ + cre.Handler(cron.Trigger(&cron.Config{Schedule: config.Schedule}), onCronTrigger), + }, nil +} + +func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) { + logger := runtime.Logger() + logger.Info("Running random lottery") + + // Define participants + participants := []string{"Alice", "Bob", "Charlie", "Diana", "Eve"} + logger.Info("Participants in lottery", "count", len(participants), "names", participants) + + // Get the DON mode random generator + rnd, err := runtime.Rand() + if err != nil { + return nil, fmt.Errorf("failed to get random generator: %w", err) + } + + // Select a random winner (index in range [0, 5)) + winnerIndex := rnd.Intn(len(participants)) + winner := participants[winnerIndex] + logger.Info("Selected winner", "index", winnerIndex, "winner", winner) + + // Generate a random prize amount up to 1,000,000 wei + maxPrize := big.NewInt(1000000) + randomPrize := new(big.Int).Rand(rnd, maxPrize) + logger.Info("Generated random prize", "amount", randomPrize.String()) + + // Return the results + result := &MyResult{ + WinnerIndex: winnerIndex, + Winner: winner, + RandomBigInt: randomPrize.String(), + } + + logger.Info("Random lottery complete!", "result", result) + return result, nil +} + +func main() { + wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow) +} +``` + +**What this example demonstrates:** + +1. **DON mode context**: The randomness is called directly in the trigger callback (DON mode), ensuring all nodes in the network would select the same winner and prize amount. + +2. **Random selection**: Uses `rnd.Intn(len(participants))` to select a random index from the participant list. The `Intn(n)` method returns a value in the range `[0, n)`. + +3. **Random big.Int for Solidity**: Generates a `*big.Int` value suitable for use with Solidity `uint256` types. + +4. **Error handling**: Properly checks for errors when calling `runtime.Rand()`. + +When you run this workflow multiple times, each execution will select different winners and prize amounts (because each execution gets a different seed), but within a single execution, all nodes in the DON would arrive at the same winner. + +## Best practices + +### Do: + +- **Always use `runtime.Rand()`** for randomness in your workflows +- **Check for errors** when calling `runtime.Rand()` + ```go + rnd, err := runtime.Rand() + if err != nil { + return fmt.Errorf("failed to get random generator: %w", err) + } + ``` + +### Don't: + +- **Don't use Go's global `rand` package** directly. Always get your random generator from `runtime.Rand()` first. + +## Mode-aware behavior + +The randomness provided by `runtime.Rand()` is **mode-aware**. The examples above demonstrate DON mode (the default execution mode for workflows). There is also a Node mode with different random behavior, used in advanced scenarios. Each mode provides a different type of randomness. + +### DON mode (default) + +The examples above all use DON mode. In this mode: + +- All nodes generate the **same** random sequence +- Enables consensus on random values +- This is the mode your main workflow callback runs in + +### Node mode + +When using `cre.RunInNodeMode`, you can access Node mode randomness: + +- Each node generates **different** random values +- Useful for scenarios where per-node variability is accepted +- Access via `nodeRuntime.Rand()` inside the Node mode function + +**Example:** + +```go +resultPromise := cre.RunInNodeMode(config, runtime, + func(config *Config, nodeRuntime cre.NodeRuntime) (int, error) { + rnd, err := nodeRuntime.Rand() + if err != nil { + return 0, err + } + // Each node generates a different value + return rnd.Intn(100), nil + }, + cre.ConsensusMedianAggregation[int](), +) +``` + +### Important: Mode isolation + +Random generators are tied to the mode they were created in. **Do not** attempt to use a random generator from one mode in another mode—it will cause a panic and crash your workflow. + +## FAQ + +**Is the randomness cryptographically secure?** + +The randomness is sourced from the host environment's secure random generator, but the standard Go `*rand.Rand` object is **not** intended for cryptographic purposes. For cryptographic operations, use dedicated crypto libraries. + +**What happens if I try to use randomness in the wrong mode?** + +The SDK will panic with the error: `"random cannot be used outside the mode it was created in"`. This is intentional—it prevents subtle consensus bugs. + +**Can I use the same random generator across multiple calls?** + +Yes. Once you call `runtime.Rand()` and get a `*rand.Rand` object, you can reuse it within the same execution mode. Each call to methods like `Intn()` will produce the next value in the deterministic sequence. + +--- + # Simulating Workflows Source: https://docs.chain.link/cre/guides/operations/simulating-workflows Last Updated: 2025-11-04 @@ -4673,7 +5248,7 @@ Non-interactive mode allows you to run simulations without prompts, making it id **Requirements:** - Use the `--non-interactive` flag -- Specify `--trigger-index` (0-based index of the trigger to run) +- Specify `--trigger-index` to select which handler to run (0-based position: `0` = first handler, `1` = second, etc.) - Provide trigger-specific flags as needed (see [Trigger-specific configuration](#trigger-specific-configuration)) **Example:** @@ -4682,6 +5257,14 @@ Non-interactive mode allows you to run simulations without prompts, making it id cre workflow simulate my-workflow --non-interactive --trigger-index 0 --target staging-settings ``` +<Aside type="tip" title="Understanding trigger-index"> + The `--trigger-index` flag selects **which handler** in your workflow to execute. Handlers are created in your + `InitWorkflow` function using `cre.Handler()`, where [each handler connects a trigger to a callback + function](/cre/key-terms#handler). If your workflow has only one handler, use `--trigger-index 0`. If you have + multiple handlers (e.g., one for an HTTP trigger and one for an EVM log trigger), use `0` for the first, `1` for the + second, etc., based on their order in your code. +</Aside> + ## The `--broadcast` flag By default, the simulator performs a **dry run** for onchain write operations. It prepares the transaction but does not broadcast it to the blockchain. @@ -4789,6 +5372,20 @@ cre workflow simulate my-workflow \ --target staging-settings ``` + +<Aside type="tip" title="Understanding the two different indexes"> + **Two separate concepts:** + + - **`--trigger-index`** selects **which handler** in your workflow to run (e.g., if the + handler with an EVM log trigger is the third handler defined, use `--trigger-index 2`) + - **`--evm-event-index`** + specifies **which log/event within the transaction** to use for testing (e.g., if the transaction emitted 3 events and + you want the first one, use `--evm-event-index 0`) + + These are completely independent: one selects your workflow's + handler to execute, the other selects which event data from the blockchain to test with. +</Aside> + ## Additional flags ### `--engine-logs` (`-g`) @@ -5219,10 +5816,15 @@ For complete setup instructions, configuration requirements, and step-by-step gu # Updating Deployed Workflows Source: https://docs.chain.link/cre/guides/operations/updating-deployed-workflows -Last Updated: 2025-11-04 +Last Updated: 2026-01-23 When you update a deployed workflow, you redeploy it with the same workflow name. The new deployment replaces the previous version in the Workflow Registry contract. Currently, CRE does not maintain version history—each deployment overwrites the previous one. + +<Aside type="caution" title="Workflow ID changes on update"> + The workflow ID changes each time you update a workflow. This is because the workflow ID is a hash derived from the workflow binary and configuration. If your consumer contract uses the workflow ID for validation, make sure to update the expected workflow ID after each update. See [Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#34-configuring-permissions) for details. +</Aside> + ## Prerequisites Before updating a deployed workflow, ensure you have: @@ -5247,6 +5849,12 @@ cre workflow deploy my-workflow --target production-settings 2. **Upload**: The new binary and configuration files are uploaded to the CRE Storage Service 3. **Registration**: A new registration transaction is sent to the Workflow Registry contract 4. **Replacement**: The previous version is replaced with the new deployment +5. **Status preserved**: The workflow's status (active or paused) is preserved from the previous deployment + + +<Aside type="note" title="Workflow status is preserved"> + When you update a workflow, the CLI matches the status of the previously deployed version. If your workflow was paused, the updated version will remain paused. If it was active, the updated version will be active and immediately start responding to triggers. To change the workflow status, see [Activating & Pausing Workflows](/cre/guides/operations/activating-pausing-workflows). +</Aside> <Aside type="caution" title="No version history"> @@ -6371,17 +6979,107 @@ To unlink a key: The CLI will submit an onchain transaction to remove the address from the Workflow Registry. After the transaction is confirmed, the address and all its associated workflows will be deleted. -## Non-interactive mode - -For automation or CI/CD pipelines, use the `--yes` flag to skip confirmation prompts: +## Unlinking a key without the original private key -```bash -cre account link-key --owner-label "CI Pipeline Wallet" --yes --target production-settings -``` +If you need to unlink a key but no longer have access to the original private key (for example, the key owner left your organization), you can still complete the unlinking process using a different wallet. -## Using multi-sig wallets -If you're using a multi-sig wallet, you'll need to use the `--unsigned` flag to generate raw transaction data that you can then submit through your multi-sig interface (such as Safe). +<Aside type="caution" title="Destructive operation"> + **Unlinking a key will permanently delete all workflows registered under that address.** This action cannot be undone. Make sure you want to permanently remove all associated workflows before proceeding. +</Aside> + +### How it works + +When you run `cre account unlink-key --unsigned` while logged into your CRE organization, the CLI generates: + +1. An authorization signature proving you have permission to unlink the key (through your CRE organization membership) +2. Raw transaction data that any funded wallet can submit to the blockchain + + +<Aside type="note" title="Security"> + The authorization is tied to the **organization**, not to the individual who originally linked the key. Any authenticated member of the CRE organization can generate valid unlink authorization for keys linked to that organization. +</Aside> + +### Prerequisites + +- **Logged in to CRE CLI**: You must be authenticated as a member of the CRE organization that owns the key +- **`workflow-owner-address` configured**: Set this in your `project.yaml` to the address you want to unlink +- **A funded wallet**: Any wallet with ETH on Ethereum Mainnet to submit the transaction and pay gas fees + +### Steps + +1. **Configure your `project.yaml`** with the address you want to unlink: + + ```yaml + production-settings: + account: + workflow-owner-address: "<address_to_unlink>" + # ... other settings + ``` + +2. **Generate the unsigned transaction**: + + ```bash + cre account unlink-key --unsigned --target production-settings + ``` + + **Example output:** + + ```bash + Unlinking web3 key from your CRE organization + Target : production-settings + ✔ Using Address : 0x.... + + Starting unlinking: owner=0x.... + ✔ Yes + Contract address validation passed + --unsigned flag detected: transaction not sent on-chain. + Generating call data for offline signing and submission in your preferred tool: + + Ownership unlinking initialized successfully! + + Next steps: + + 1. Submit the following transaction on the target chain: + + Chain: ethereum-mainnet + Contract Address: 0x4Ac54353FA4Fa961AfcC5ec4B118596d3305E7e5 + + 2. Use the following transaction data: + + 39d68c6a000000000000000000... + + Unlinked successfully + ``` + +3. **Submit the transaction** using any wallet that supports sending transactions with custom data. + + + <Aside type="caution" title="Destructive operation"> + **Unlinking a key will permanently delete all workflows registered under that address.** This action cannot be undone. Make sure you want to permanently remove all associated workflows before proceeding. + </Aside> + + Here's an example using MetaMask: + + 1. In MetaMask, go to **Settings → Advanced** and enable **"Show hex data"** + 2. Click **Send** and enter the contract address as the recipient 0x4Ac54353FA4Fa961AfcC5ec4B118596d3305E7e5 + 3. Set the amount to **0 ETH** + 4. Paste the transaction data in the **Hex data** field (add `0x` prefix) + 5. Review and confirm the transaction + + The unlink operation completes once the transaction is confirmed onchain. All workflows registered under that address will be permanently deleted. + +## Non-interactive mode + +For automation or CI/CD pipelines, use the `--yes` flag to skip confirmation prompts: + +```bash +cre account link-key --owner-label "CI Pipeline Wallet" --yes --target production-settings +``` + +## Using multi-sig wallets + +If you're using a multi-sig wallet, you'll need to use the `--unsigned` flag to generate raw transaction data that you can then submit through your multi-sig interface (such as Safe). ### Prerequisites for multi-sig @@ -6571,9 +7269,10 @@ This section provides a high-level, conceptual overview of the capabilities curr - **[Triggers](/cre/capabilities/triggers)**: Event sources that start your workflow executions. - **[HTTP](/cre/capabilities/http)**: Fetch and post data from external APIs with decentralized consensus. +- **[Confidential HTTP](/cre/capabilities/confidential-http)** *(Experimental)*: Make privacy-preserving API calls with enclave execution, secret injection, and optional response encryption. - **[EVM Read & Write](/cre/capabilities/evm-read-write)**: Interact with smart contracts on EVM-compatible blockchains with decentralized consensus. -All execution capabilities (HTTP, EVM) automatically use [built-in consensus](/cre/concepts/consensus-computing) to validate results across multiple nodes, ensuring security and reliability. +All execution capabilities (HTTP, Confidential HTTP, EVM) automatically use [built-in consensus](/cre/concepts/consensus-computing) to validate results across multiple nodes, ensuring security and reliability. --- @@ -6787,737 +7486,724 @@ Learn more about how to use CRE capabilities with built-in consensus: --- -# Time in CRE -Source: https://docs.chain.link/cre/concepts/time-in-cre -Last Updated: 2025-11-04 +# CRE Templates +Source: https://docs.chain.link/cre/templates +Last Updated: 2025-11-21 -<Aside type="note" title="TL;DR"> - CRE provides **DON Time**: a consensus-derived timestamp so different nodes see the *same time*. Use the SDK's runtime - call, `runtime.Now()`, whenever your workflow logic depends on time. Do **not** read local system clocks or other - ad-hoc time sources in DON Mode — they introduce non-determinism. +Templates are workflow examples you can copy and customize for your own projects. They are curated and maintained by Chainlink, offering patterns you can use as references or starting points for your own workflows. + + +<Aside type="caution" title="Educational Example Disclaimer"> + This page includes educational examples to use a Chainlink system, product, or service and is provided to + demonstrate how to interact with Chainlink's systems, products, and services to integrate them into your own. This + template is provided "AS IS" and "AS AVAILABLE" without warranties of any kind, it has not been audited, and it may be + missing key checks or error handling to make the usage of the system, product or service more clear. Do not use the + code in this example in a production environment without completing your own audits and application of best practices. + Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs + that are generated due to errors in code. </Aside> -## The problem: Why time needs consensus +## Building Blocks and Starter Templates -Workflows often rely on time for decisions (market-hours checks), scheduling (retries/backoffs), and observability (log timestamps). In a decentralized network, nodes do not share an identical clock—clock drift, resource contention, and OS scheduling can skew each node's local time. If each node consults its own clock: +Templates are organized into two categories: -- Different nodes may take **different branches** of your logic (e.g., one thinks the market is open, another does not). -- Logs across nodes become **hard to correlate**. -- Data fetched using time (e.g., "fetch price at timestamp N") can be **inconsistent**. +### 1. Building Blocks -**DON Time** removes these divergences by making time **deterministic in the DON**. +[Building Blocks](https://github.com/smartcontractkit/cre-templates/tree/main/building-blocks) are small, focused examples that teach **one concept at a time**. Each Building Block is self-contained and demonstrates a specific CRE capability or pattern. They feature minimal code, clear configuration, and are runnable locally with `cre workflow simulate`. -## The solution: DON time +**Available Building Blocks:** -**DON Time** is a timestamp computed by an <a href="https://docs.chain.link/architecture-overview/off-chain-reporting" target="_blank" rel="noopener noreferrer">OCR (Off-Chain Reporting)</a> plugin and agreed upon by the nodes participating in CRE. You access it through the SDK's runtime call, `runtime.Now()`, not via an OS/System clock. The `runtime.Now()` function returns a standard Go `time.Time` object. +1. **`kv-store`** (Key-Value Store with AWS S3) + - Reads a value from an AWS S3 object, increments it, and writes it back + - Demonstrates: SigV4-signed HTTP requests, CRE secrets (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`), and consensus read → single write flow + - Use case: Learn offchain write patterns with secrets and consensus -**Key properties:** +2. **`read-data-feeds`** (Chainlink Data Feeds) + - Reads `decimals()` and `latestAnswer()` from <a href="https://docs.chain.link/data-feeds" target="_blank" rel="noopener noreferrer">Chainlink Data Feeds</a> on a cron schedule + - Demonstrates: Contract ABIs, Go bindings generation, RPC configuration, and onchain reads + - Use case: Learn how to read onchain data via contract calls -- **Deterministic across nodes**: nodes see the same timestamp. -- **Sequenced per workflow**: time responses are associated with a **time-call sequence number** inside each workflow execution (1st call, 2nd call, …). Node execution timing might be slightly off, but a given call will resolve to the **same DON timestamp**. -- **Low latency**: the plugin runs continuously with **delta round = 0**, and each node **transmits** results back to outstanding requests at the end of every round. -- **Tamper-resistant**: workflows don't expose host machine time, reducing timing-attack surface. +**When to use Building Blocks:** -<Aside type="note" title="A Note on Accuracy"> - DON Time is computed as the **median of nodes' local observations** in each round. It is designed for **consistency** - across the DON rather than exact alignment to an external UTC source. Think of it as a highly reliable clock for your - workflows. Do not treat it as a high-precision clock. -</Aside> +- You want to learn a specific feature quickly (e.g., secrets + HTTP signing, reading a data feed, cron triggers) +- You need a focused code snippet to copy into your project +- You're exploring a new capability before integrating it into a larger workflow -## How it works: A high-level view +### 2. Starter Templates -1. Your workflow calls **`runtime.Now()`**. -2. **The Chainlink network takes this request**: The Workflow Engine's **TimeProvider** assigns that call a **sequence number** and enqueues it in the **DON Time Store**. -3. **All the nodes agree on a single time (the DON Time)**: The **OCR Time Plugin** on each node reaches consensus on a new DON timestamp (the median of observed times). -4. Each node **returns** the newest DON timestamp to every pending request and updates its **last observed DON time** cache. -5. The result is written back into the WebAssembly execution, and your workflow continues. +[Starter Templates](https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates) are complete, end-to-end workflows that combine multiple capabilities and mirror real-world use cases. These templates are more comprehensive than Building Blocks and include production-like configuration, optional precompiled smart contracts, and generated bindings. They can be adapted directly into your own projects. -Because requests are sequenced, *Call 1* for a workflow instance will always return the same DON timestamp on every node. If Node A hits *Call 2* before Node B, A will block until the DON timestamp for *Call 2* is produced; when B reaches *Call 2*, it immediately reuses that value. +**Available Starter Templates:** -## Execution modes: DON mode vs. Node mode +1. **`custom-data-feed`** (Custom Data Feed) + - Periodically fetches offchain data via HTTP and pushes updates onchain + - Demonstrates: Cron scheduling, secrets management, contract bindings, and blockchain writes + - Use case: Build data feeds that combine offchain APIs with onchain smart contracts -### DON mode (default for workflows) +2. **`bring-your-own-data`** (BYOD - NAV & PoR) + - End-to-end examples for publishing Net Asset Value (NAV) and Proof of Reserve (PoR) data onchain + - Demonstrates: Complete workflow with demo contracts for publishing institutional data + - Use case: Publish verified financial or reserve data to smart contracts -- Time is **consensus-based** and **deterministic**. -- Use for **any** logic where different outcomes across nodes would be a bug. Examples: - - Market-hours gates - - Time-windowed queries ("last 15 minutes") - - Retry/backoff logic that must align across nodes - - Timestamps used for cross-node correlation (logging, audit trails) +3. **`multi-chain-token-manager`** (Multi-Chain Token Manager) + - Orchestrates token operations and state across multiple blockchain networks + - Demonstrates: Multi-chain RPC configuration, bindings, and cross-chain coordination patterns + - Use case: Manage token operations across different EVM chains from a single workflow -### Node mode (advanced / special cases) +**When to use Starter Templates:** -- Workflow authors handle consensus themselves. -- `runtime.Now()` in Node Mode is a non-blocking call that returns the **last generated DON timestamp** from the local node's cache. This is the same mechanism used by standard Go `time.Now()` calls within the Wasm environment. -- Useful in situation where you already expect non-determinism (e.g., inherently variable HTTP responses). +- You want a runnable reference architecture that shows production-ready patterns +- You're starting a new project and need a solid foundation +- You want to see how multiple CRE capabilities integrate in a real workflow -<Aside type="caution" title="Use DON Mode"> - Unless you have a specific reason and understand the trade-offs, **always use DON Mode** for time-dependent logic. -</Aside> +### How to access templates -## Best practices: Avoiding non-determinism in DON mode +All templates are available on GitHub at [github.com/smartcontractkit/cre-templates](https://github.com/smartcontractkit/cre-templates) -When running in DON Mode, you get determinism **if and only if** you base time-dependent logic on DON Time. +- Browse all Building Blocks and Starter Templates +- Clone or fork templates to customize them for your use case +- View individual READMEs for detailed usage instructions -**Avoid** these patterns: +<Aside type="tip" title="Quick Start: Custom Data Feed via CLI"> + The **Custom Data Feed** starter template is also available through `cre init` for a guided, interactive setup + experience. We provide a step-by-step guide: [Running a Demo Workflow](/cre/templates/running-demo-workflow). +</Aside> -- **Reading host/system time** (`time.Now()`, etc.). Always use `runtime.Now()` from the CRE SDK. -- **Mixing time sources** in the same control path. -- **Per-node "sleeps" based on local time** that gate deterministic decisions. +## When to use what -**Deterministic patterns:** +Choose the right template based on where you are in your CRE journey: -- ✅ Gate behavior with: - ```go - now := runtime.Now() - if market.IsOpenAt(now): - // proceed - ``` -- ✅ Compute windows from DON Time: - ```go - now := runtime.Now() - windowStart := now.Add(-15 * time.Minute) - fetchData(windowStart, now) - ``` +| Your Situation | Recommended Action | +| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------- | +| Just finished the [Getting Started guide](/cre/getting-started/overview) | Run the **Custom Data Feed** template to see a more complex, real-world example | +| Want to learn offchain writes with secrets and consensus | Clone the **`kv-store`** Building Block (AWS S3 example) | +| Need to read Chainlink Data Feeds in your workflow | Clone the **`read-data-feeds`** Building Block (onchain reads with ABIs) | +| Building a custom data feed for your protocol | Fork the **`custom-data-feed`** Starter Template and customize it | +| Publishing NAV or PoR data onchain | Fork the **`bring-your-own-data`** Starter Template (includes demo contracts) | +| Managing tokens across multiple chains | Fork the **`multi-chain-token-manager`** Starter Template (cross-chain patterns) | -## FAQ +## Next steps -**Is DON Time "real UTC time"?** +Ready to explore templates? -It's the **median of node observations** per round. It closely tracks real time but prioritizes **consistency** over absolute accuracy. +- **[Run the Custom Data Feed Template](/cre/templates/running-demo-workflow)** - Walk through this template with our step-by-step guide (available in Go and TypeScript) -**What is the resolution?** +- **[Browse all templates on GitHub](https://github.com/smartcontractkit/cre-templates)** - Explore the full collection of Building Blocks and Starter Templates -New DON timestamps are produced continuously (multiple per second). Treat it as coarse-grained real time suitable for gating and logging, not sub-millisecond measurement. +<Aside type="note" title="Contributing"> + The CRE Templates repository is open source under the MIT license. If you've built a useful workflow pattern and want + to share it with the community, consider contributing. +</Aside> --- -# Random in CRE -Source: https://docs.chain.link/cre/concepts/random-in-cre -Last Updated: 2025-11-04 +# AI-Powered Prediction Market +Source: https://docs.chain.link/cre/demos/prediction-market +Last Updated: 2025-11-21 -<Aside type="note" title="TL;DR"> - Use `runtime.Rand()` to generate random numbers in your workflows. This provides secure, deterministic randomness that - enables all nodes in the network to reach consensus. Do **not** use Go's global `rand` package—it can break consensus. -</Aside> +This demo showcases a complete, end-to-end prediction market application that integrates CRE with external services. Unlike [templates](/cre/templates) that are meant to be copied and customized, this demo is designed to be explored and studied to understand what's possible with CRE. -## The problem: Why randomness needs special handling -Workflows often need randomness for various purposes: generating nonces, selecting winners from a list, or creating unpredictable values. However, in a decentralized network, naive use of random number generators creates a critical problem: +<Aside type="caution" title="Educational Example Disclaimer"> + This page includes educational examples to use a Chainlink system, product, or service and is provided to + demonstrate how to interact with Chainlink's systems, products, and services to integrate them into your own. This + template is provided "AS IS" and "AS AVAILABLE" without warranties of any kind, it has not been audited, and it may be + missing key checks or error handling to make the usage of the system, product or service more clear. Do not use the + code in this example in a production environment without completing your own audits and application of best practices. + Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs + that are generated due to errors in code. +</Aside> -**If each node generates different random values, they cannot reach consensus on the workflow's output.** +## GitHub Repository -For example, if your workflow selects a lottery winner using each node's local random generator, different nodes would select different winners, making it impossible to agree on a single result to write onchain. +The [repository](https://github.com/smartcontractkit/cre-gcp-prediction-market-demo) contains complete setup instructions, including quick start guides and full end-to-end deployment steps. -## The solution: Consensus-safe randomness +## What this demo does -CRE provides randomness through the `runtime.Rand()` method, which returns a standard Go `*rand.Rand` object. This random generator is managed by the CRE platform to ensure all nodes generate the same sequence of random values, enabling consensus while still providing unpredictability across different workflow executions. +This demo showcases a fully automated prediction market where: -### Usage +1. **Users create markets** by asking binary (Yes/No) questions onchain +2. **Users stake ERC-20 tokens** (USDC) to make predictions +3. **After the market closes**, anyone can request settlement +4. **CRE automatically triggers** when it detects the settlement request event +5. **Gemini AI determines the outcome** using Google search grounding for factual verification +6. **CRE submits a cryptographically signed settlement** report back onchain +7. **Settlement data is stored in Firestore** for audit trails and frontend display +8. **Winners claim their proportional share** of the total pool -```go -// Get the random generator from the runtime -rnd, err := runtime.Rand() -if err != nil { - return err -} +## Key integrations -// Use it with standard Go rand methods -randomInt := rnd.Intn(100) // Random int in [0, 100) -randomBigInt := new(big.Int).Rand(rnd, big.NewInt(1000)) // Random big.Int -``` +This demo demonstrates several important CRE integration patterns: -## Common use cases +### Event-driven workflows -- Selecting a winner from a lottery or pool -- Generating nonces for transactions -- Creating random identifiers or values -- Any random selection that needs to be agreed upon by all nodes +The CRE workflow listens for `SettlementRequested` events onchain using CRE's [EVM log trigger capability](/cre/guides/workflow/using-triggers/evm-log-trigger). When a settlement is requested, the workflow automatically triggers and begins the settlement process. -## Working with big.Int random values +### External AI service integration -For Solidity `uint256` types, you often need random `*big.Int` values: +The workflow sends the market question to Google's Gemini AI with search grounding enabled. Gemini searches the web to determine the factual outcome and returns a result with a confidence score. -```go -rnd, err := runtime.Rand() -if err != nil { - return err -} +### Data persistence -// Generate a random number in the range [0, max) -max := new(big.Int) -max.SetString("1000000000000000000", 10) // 1 ETH in wei +Settlement results, including the AI's response and confidence level, are stored in [Firebase Firestore](https://firebase.google.com/docs/firestore). This creates a trail and enables the frontend to display settlement history. -randomAmount := new(big.Int).Rand(rnd, max) -// randomAmount is a random value between 0 and 1 ETH -``` +### Cryptographic signing -## Complete example: Random lottery +The workflow generates cryptographically signed settlement reports that the smart contract can verify. This ensures only authorized, consensus-approved data reaches the contract. -Here's a complete example that demonstrates using DON mode randomness to select a lottery winner and generate a prize amount: +### Full-stack architecture -```go -//go:build wasip1 +The demo includes: -package main +- **Smart contracts** (Solidity + Foundry): `SimpleMarket.sol` for managing prediction markets +- **CRE workflow** (TypeScript): Event-driven settlement logic with AI integration +- **Database** (Firebase/Firestore): Audit trail and data persistence +- **Frontend** (Next.js): User interface for viewing settlement history -import ( - "fmt" - "log/slog" - "math/big" +## What you'll learn - "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" - "github.com/smartcontractkit/cre-sdk-go/cre" - "github.com/smartcontractkit/cre-sdk-go/cre/wasm" -) +Exploring this demo will teach you: -type Config struct { - Schedule string `json:"schedule"` -} +1. **Event-driven workflow patterns**: How to use CRE's log trigger to react to onchain events in real-time +2. **External service integration**: Best practices for integrating AI services like Gemini with your workflows +3. **Error handling and validation**: How to validate external API responses before using them onchain +4. **Data persistence patterns**: Techniques for storing workflow results in external databases +5. **Full-stack dApp architecture**: How CRE fits into a complete application with smart contracts, workflows, and frontends +6. **Cryptographic signing**: How CRE generates and submits cryptographically signed reports -type MyResult struct { - WinnerIndex int - Winner string - RandomBigInt string -} +## Getting started -func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { - return cre.Workflow[*Config]{ - cre.Handler(cron.Trigger(&cron.Config{Schedule: config.Schedule}), onCronTrigger), - }, nil -} +The repository includes two quick start options: -func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) { - logger := runtime.Logger() - logger.Info("Running random lottery") +### Option 1: Test CRE Workflow Only (Fastest) - // Define participants - participants := []string{"Alice", "Bob", "Charlie", "Diana", "Eve"} - logger.Info("Participants in lottery", "count", len(participants), "names", participants) +Test the workflow using a pre-deployed contract and transaction. This lets you see the workflow in action without deploying anything yourself. - // Get the DON mode random generator - rnd, err := runtime.Rand() - if err != nil { - return nil, fmt.Errorf("failed to get random generator: %w", err) - } +### Option 2: Full End-to-End Test - // Select a random winner (index in range [0, 5)) - winnerIndex := rnd.Intn(len(participants)) - winner := participants[winnerIndex] - logger.Info("Selected winner", "index", winnerIndex, "winner", winner) +Deploy your own contracts, create markets, request settlements, and run the workflow end-to-end. This gives you complete hands-on experience with all components. - // Generate a random prize amount up to 1,000,000 wei - maxPrize := big.NewInt(1000000) - randomPrize := new(big.Int).Rand(rnd, maxPrize) - logger.Info("Generated random prize", "amount", randomPrize.String()) +See the [repository README](https://github.com/smartcontractkit/cre-gcp-prediction-market-demo) for detailed prerequisites and setup instructions. - // Return the results - result := &MyResult{ - WinnerIndex: winnerIndex, - Winner: winner, - RandomBigInt: randomPrize.String(), - } +## Next steps - logger.Info("Random lottery complete!", "result", result) - return result, nil -} +- **[Explore the repository](https://github.com/smartcontractkit/cre-gcp-prediction-market-demo)** - Clone the demo and follow the setup instructions +- **[Learn about log triggers](/cre/guides/workflow/using-triggers/evm-log-trigger)** - Understand how to build event-driven workflows +- **[Explore HTTP capabilities](/cre/guides/workflow/using-http-client)** - Learn more about integrating external APIs +- **[Browse templates](/cre/templates)** - Check out workflow templates you can copy and customize -func main() { - wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow) -} -``` +--- -**What this example demonstrates:** +# CLI Reference +Source: https://docs.chain.link/cre/reference/cli +Last Updated: 2026-02-10 -1. **DON mode context**: The randomness is called directly in the trigger callback (DON mode), ensuring all nodes in the network would select the same winner and prize amount. +<Aside type="note" title="Required CLI Version: v1.0.10"> + To ensure compatibility with the guides and examples in this documentation, please use version `v1.0.10` of the CRE + CLI. You can check your installed version by running `cre version`. Refer to the [CLI + Installation](/cre/getting-started/cli-installation/macos-linux) guide for more information. +</Aside> -2. **Random selection**: Uses `rnd.Intn(len(participants))` to select a random index from the participant list. The `Intn(n)` method returns a value in the range `[0, n)`. +The CRE Command Line Interface (CLI) is your primary tool for developing, testing, deploying, and managing workflows. It handles project setup, contract binding generation (Go workflows only), local simulation, and workflow lifecycle management. -3. **Random big.Int for Solidity**: Generates a `*big.Int` value suitable for use with Solidity `uint256` types. +## Global flags -4. **Error handling**: Properly checks for errors when calling `runtime.Rand()`. +These flags can be used with any `cre` command. -When you run this workflow multiple times, each execution will select different winners and prize amounts (because each execution gets a different seed), but within a single execution, all nodes in the DON would arrive at the same winner. +| Flag | Description | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `-h, --help` | Displays help information for any command | +| `-e, --env` | Specifies the path to your `.env` file (default: `".env"`) | +| `-T, --target` | Sets the target environment from your configuration files | +| `-R, --project-root` | Specifies the path to the project root directory. By default, the CLI automatically finds the project root by searching for `project.yaml` in the current directory and parent directories | +| `-v, --verbose` | Enables verbose logging to print `DEBUG` level logs | -## Best practices +## Commands overview -### Do: +### Authentication -- **Always use `runtime.Rand()`** for randomness in your workflows -- **Check for errors** when calling `runtime.Rand()` - ```go - rnd, err := runtime.Rand() - if err != nil { - return fmt.Errorf("failed to get random generator: %w", err) - } - ``` +Manage your authentication and account credentials. -### Don't: +- **`cre login`** — Authenticate with the CRE UI and save credentials locally +- **`cre logout`** — Revoke authentication tokens and remove local credentials +- **`cre whoami`** — Show your current account details -- **Don't use Go's global `rand` package** directly. Always get your random generator from `runtime.Rand()` first. +[View authentication commands →](/cre/reference/cli/authentication) -## Mode-aware behavior +*** -The randomness provided by `runtime.Rand()` is **mode-aware**. The examples above demonstrate DON mode (the default execution mode for workflows). There is also a Node mode with different random behavior, used in advanced scenarios. Each mode provides a different type of randomness. +### Project Setup -### DON mode (default) +Initialize projects and generate contract bindings (Go only). -The examples above all use DON mode. In this mode: +- **`cre init`** — Initialize a new CRE project with an interactive setup guide +- **`cre generate-bindings`** (Go only) — Generate Go bindings from contract ABI files for type-safe contract interactions -- All nodes generate the **same** random sequence -- Enables consensus on random values -- This is the mode your main workflow callback runs in +[View project setup commands →](/cre/reference/cli/project-setup) -### Node mode +*** -When using `cre.RunInNodeMode`, you can access Node mode randomness: +### Account Management -- Each node generates **different** random values -- Useful for scenarios where per-node variability is accepted -- Access via `nodeRuntime.Rand()` inside the Node mode function +Manage your linked public key addresses for workflow operations. -**Example:** +- **`cre account link-key`** — Link a public key address to your account +- **`cre account list-key`** — List workflow owners linked to your organization +- **`cre account unlink-key`** — Unlink a public key address from your account -```go -resultPromise := cre.RunInNodeMode(config, runtime, - func(config *Config, nodeRuntime cre.NodeRuntime) (int, error) { - rnd, err := nodeRuntime.Rand() - if err != nil { - return 0, err - } - // Each node generates a different value - return rnd.Intn(100), nil - }, - cre.ConsensusMedianAggregation[int](), -) -``` +[View account management commands →](/cre/reference/cli/account) -### Important: Mode isolation +*** -Random generators are tied to the mode they were created in. **Do not** attempt to use a random generator from one mode in another mode—it will cause a panic and crash your workflow. +### Workflow Commands -## FAQ +Manage workflows throughout their entire lifecycle. -**Is the randomness cryptographically secure?** +- **`cre workflow simulate`** — Compile and execute workflows in a local simulation environment +- **`cre workflow deploy`** — Deploy a workflow to the Workflow Registry contract +- **`cre workflow activate`** — Activate a workflow on the Workflow Registry contract +- **`cre workflow pause`** — Pause a workflow on the Workflow Registry contract +- **`cre workflow delete`** — Delete all versions of a workflow from the Workflow Registry -The randomness is sourced from the host environment's secure random generator, but the standard Go `*rand.Rand` object is **not** intended for cryptographic purposes. For cryptographic operations, use dedicated crypto libraries. +[View workflow commands →](/cre/reference/cli/workflow) -**What happens if I try to use randomness in the wrong mode?** +*** -The SDK will panic with the error: `"random cannot be used outside the mode it was created in"`. This is intentional—it prevents subtle consensus bugs. +### Secrets Management -**Can I use the same random generator across multiple calls?** +Manage secrets stored in the Vault DON for use in your workflows. -Yes. Once you call `runtime.Rand()` and get a `*rand.Rand` object, you can reuse it within the same execution mode. Each call to methods like `Intn()` will produce the next value in the deterministic sequence. +- **`cre secrets create`** — Create new secrets from a YAML file +- **`cre secrets update`** — Update existing secrets +- **`cre secrets delete`** — Delete secrets +- **`cre secrets list`** — List secret identifiers in a namespace ---- +[View secrets management commands →](/cre/reference/cli/secrets) -# CRE Templates -Source: https://docs.chain.link/cre/templates -Last Updated: 2025-11-21 +*** -Templates are workflow examples you can copy and customize for your own projects. They are curated and maintained by Chainlink, offering patterns you can use as references or starting points for your own workflows. +### Utilities +Additional utility commands. -<Aside type="caution" title="Educational Example Disclaimer"> - This page includes educational examples to use a Chainlink system, product, or service and is provided to - demonstrate how to interact with Chainlink's systems, products, and services to integrate them into your own. This - template is provided "AS IS" and "AS AVAILABLE" without warranties of any kind, it has not been audited, and it may be - missing key checks or error handling to make the usage of the system, product or service more clear. Do not use the - code in this example in a production environment without completing your own audits and application of best practices. - Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs - that are generated due to errors in code. -</Aside> +- **`cre update`** — Update the CRE CLI to the latest version +- **`cre version`** — Print the current version of the CRE CLI -## Building Blocks and Starter Templates +[View utility commands →](/cre/reference/cli/utilities) -Templates are organized into two categories: +## Typical development workflow -### 1. Building Blocks +The typical workflow development process uses these commands in sequence: -[Building Blocks](https://github.com/smartcontractkit/cre-templates/tree/main/building-blocks) are small, focused examples that teach **one concept at a time**. Each Building Block is self-contained and demonstrates a specific CRE capability or pattern. They feature minimal code, clear configuration, and are runnable locally with `cre workflow simulate`. +1. **`cre init`** — Initialize your project +2. **`cre generate-bindings`** — Generate contract bindings from ABIs (Go workflows only, if interacting with contracts) +3. **`cre workflow simulate`** — Test your workflow locally +4. **`cre workflow deploy`** — Deploy your workflow to the registry +5. **`cre workflow activate`** / **`cre workflow pause`** — Control workflow execution -**Available Building Blocks:** +## Learn more -1. **`kv-store`** (Key-Value Store with AWS S3) - - Reads a value from an AWS S3 object, increments it, and writes it back - - Demonstrates: SigV4-signed HTTP requests, CRE secrets (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`), and consensus read → single write flow - - Use case: Learn offchain write patterns with secrets and consensus +- **[CLI Installation](/cre/getting-started/cli-installation)** — How to install and set up the CRE CLI +- **[Getting Started](/cre/getting-started)** — Step-by-step tutorials using the CLI +- **[Project Configuration](/cre/reference/project-configuration)** — Understanding project structure and configuration files -2. **`read-data-feeds`** (Chainlink Data Feeds) - - Reads `decimals()` and `latestAnswer()` from <a href="https://docs.chain.link/data-feeds" target="_blank" rel="noopener noreferrer">Chainlink Data Feeds</a> on a cron schedule - - Demonstrates: Contract ABIs, Go bindings generation, RPC configuration, and onchain reads - - Use case: Learn how to read onchain data via contract calls +--- -**When to use Building Blocks:** +# Authentication Commands +Source: https://docs.chain.link/cre/reference/cli/authentication +Last Updated: 2025-11-04 -- You want to learn a specific feature quickly (e.g., secrets + HTTP signing, reading a data feed, cron triggers) -- You need a focused code snippet to copy into your project -- You're exploring a new capability before integrating it into a larger workflow +The authentication commands manage your CRE credentials and account information. -### 2. Starter Templates +<Aside type="note" title="Global flags"> + All `cre` commands support [global flags](/cre/reference/cli#global-flags) like `--env`, `--target`, `--project-root`, + and `--verbose`. +</Aside> -[Starter Templates](https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates) are complete, end-to-end workflows that combine multiple capabilities and mirror real-world use cases. These templates are more comprehensive than Building Blocks and include production-like configuration, optional precompiled smart contracts, and generated bindings. They can be adapted directly into your own projects. +## `cre login` -**Available Starter Templates:** +Starts the authentication flow. This command opens your browser for user login and saves your credentials locally. -1. **`custom-data-feed`** (Custom Data Feed) - - Periodically fetches offchain data via HTTP and pushes updates onchain - - Demonstrates: Cron scheduling, secrets management, contract bindings, and blockchain writes - - Use case: Build data feeds that combine offchain APIs with onchain smart contracts +**Usage:** -2. **`bring-your-own-data`** (BYOD - NAV & PoR) - - End-to-end examples for publishing Net Asset Value (NAV) and Proof of Reserve (PoR) data onchain - - Demonstrates: Complete workflow with demo contracts for publishing institutional data - - Use case: Publish verified financial or reserve data to smart contracts +```bash +cre login +``` -3. **`multi-chain-token-manager`** (Multi-Chain Token Manager) - - Orchestrates token operations and state across multiple blockchain networks - - Demonstrates: Multi-chain RPC configuration, bindings, and cross-chain coordination patterns - - Use case: Manage token operations across different EVM chains from a single workflow +**Authentication steps:** -**When to use Starter Templates:** +1. The CLI opens your default web browser to the login page +2. Enter your account email address +3. Enter your account password +4. Enter your one-time password (OTP) from your authenticator app +5. The CLI automatically captures and saves your credentials locally -- You want a runnable reference architecture that shows production-ready patterns -- You're starting a new project and need a solid foundation -- You want to see how multiple CRE capabilities integrate in a real workflow +## `cre logout` -### How to access templates +Revokes authentication tokens and removes local credentials. This invalidates the current authentication tokens and deletes stored credentials from your machine. -All templates are available on GitHub at [github.com/smartcontractkit/cre-templates](https://github.com/smartcontractkit/cre-templates) +**Usage:** -- Browse all Building Blocks and Starter Templates -- Clone or fork templates to customize them for your use case -- View individual READMEs for detailed usage instructions +```bash +cre logout +``` -<Aside type="tip" title="Quick Start: Custom Data Feed via CLI"> - The **Custom Data Feed** starter template is also available through `cre init` for a guided, interactive setup - experience. We provide a step-by-step guide: [Running a Demo Workflow](/cre/templates/running-demo-workflow). -</Aside> +## `cre whoami` -## When to use what +Shows your current account details. This command fetches and displays your account information, including your email and organization ID. -Choose the right template based on where you are in your CRE journey: +**Usage:** -| Your Situation | Recommended Action | -| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------- | -| Just finished the [Getting Started guide](/cre/getting-started/overview) | Run the **Custom Data Feed** template to see a more complex, real-world example | -| Want to learn offchain writes with secrets and consensus | Clone the **`kv-store`** Building Block (AWS S3 example) | -| Need to read Chainlink Data Feeds in your workflow | Clone the **`read-data-feeds`** Building Block (onchain reads with ABIs) | -| Building a custom data feed for your protocol | Fork the **`custom-data-feed`** Starter Template and customize it | -| Publishing NAV or PoR data onchain | Fork the **`bring-your-own-data`** Starter Template (includes demo contracts) | -| Managing tokens across multiple chains | Fork the **`multi-chain-token-manager`** Starter Template (cross-chain patterns) | +```bash +cre whoami +``` -## Next steps +<Aside type="note" title="Verify authentication"> + Use `cre whoami` to verify you're logged in and check which account is currently active. This is useful before + deploying workflows or performing other authenticated operations. +</Aside> -Ready to explore templates? +## Authentication workflow -- **[Run the Custom Data Feed Template](/cre/templates/running-demo-workflow)** - Walk through this template with our step-by-step guide (available in Go and TypeScript) +The typical authentication flow: -- **[Browse all templates on GitHub](https://github.com/smartcontractkit/cre-templates)** - Explore the full collection of Building Blocks and Starter Templates +1. **`cre login`** — Authenticate with the CRE UI (browser-based) +2. **`cre whoami`** — Verify your authentication and account details +3. **Perform CLI operations** — Deploy, manage workflows, etc. +4. **`cre logout`** — (Optional) Revoke credentials when done -<Aside type="note" title="Contributing"> - The CRE Templates repository is open source under the MIT license. If you've built a useful workflow pattern and want - to share it with the community, consider contributing. -</Aside> +## Learn more + +- [Getting Started](/cre/getting-started) — Includes authentication setup in the initial steps +- [Account Management](/cre/reference/cli/account) — Link keys after authentication +- [Deploying Workflows](/cre/guides/operations/deploying-workflows) — Requires authentication --- -# AI-Powered Prediction Market -Source: https://docs.chain.link/cre/demos/prediction-market -Last Updated: 2025-11-21 +# Account Management +Source: https://docs.chain.link/cre/reference/cli/account +Last Updated: 2025-11-04 -This demo showcases a complete, end-to-end prediction market application that integrates CRE with external services. Unlike [templates](/cre/templates) that are meant to be copied and customized, this demo is designed to be explored and studied to understand what's possible with CRE. +The `cre account` commands manage your linked public key addresses for workflow operations. These commands allow you to link wallet addresses to your CRE account, list linked addresses, and unlink them when needed. -<Aside type="caution" title="Educational Example Disclaimer"> - This page includes educational examples to use a Chainlink system, product, or service and is provided to - demonstrate how to interact with Chainlink's systems, products, and services to integrate them into your own. This - template is provided "AS IS" and "AS AVAILABLE" without warranties of any kind, it has not been audited, and it may be - missing key checks or error handling to make the usage of the system, product or service more clear. Do not use the - code in this example in a production environment without completing your own audits and application of best practices. - Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs - that are generated due to errors in code. +<Aside type="note" title="Global flags"> + All `cre` commands support [global flags](/cre/reference/cli#global-flags) like `--env`, `--target`, `--project-root`, and `--verbose`. </Aside> -## GitHub Repository +## `cre account link-key` -The [repository](https://github.com/smartcontractkit/cre-gcp-prediction-market-demo) contains complete setup instructions, including quick start guides and full end-to-end deployment steps. +<Aside type="note" title="Authentication required"> + Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're + logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging + in with the CLI](/cre/account/cli-login) for further details. +</Aside> -## What this demo does +Links a public key address to your account for workflow operations. This command reads your private key from the `.env` file (for EOA) or uses your configuration (for multi-sig), derives the public address, and registers it onchain in the Workflow Registry contract. -This demo showcases a fully automated prediction market where: +For a complete step-by-step guide with examples, see [Linking Wallet Keys](/cre/organization/linking-keys). -1. **Users create markets** by asking binary (Yes/No) questions onchain -2. **Users stake ERC-20 tokens** (USDC) to make predictions -3. **After the market closes**, anyone can request settlement -4. **CRE automatically triggers** when it detects the settlement request event -5. **Gemini AI determines the outcome** using Google search grounding for factual verification -6. **CRE submits a cryptographically signed settlement** report back onchain -7. **Settlement data is stored in Firestore** for audit trails and frontend display -8. **Winners claim their proportional share** of the total pool -## Key integrations +<Aside type="caution" title="Prerequisites for link-key"> + - **Must run from a project directory** with a `project.yaml` file + - **`.env` must contain `CRE_ETH_PRIVATE_KEY`** — Your wallet's private key + - **Wallet must be funded** with ETH on Ethereum Mainnet to pay gas fees + - **RPC endpoint configured** — Add an `ethereum-mainnet` RPC URL in your `project.yaml` under the `rpcs` section for your target (e.g., `https://ethereum-rpc.publicnode.com` or your preferred provider) + - **For multi-sig wallets**: Also specify `workflow-owner-address` in your `project.yaml` under the `account` section. See [Linking Wallet Keys](/cre/organization/linking-keys#using-multi-sig-wallets) for details. +</Aside> -This demo demonstrates several important CRE integration patterns: -### Event-driven workflows +<Aside type="note" title="Transaction is sent to Ethereum Mainnet"> + This command always submits a transaction to **Ethereum Mainnet**, regardless of your workflow deployment environment. Ensure your wallet has sufficient ETH for gas fees and your `project.yaml` includes an RPC configuration for `ethereum-mainnet`: -The CRE workflow listens for `SettlementRequested` events onchain using CRE's [EVM log trigger capability](/cre/guides/workflow/using-triggers/evm-log-trigger). When a settlement is requested, the workflow automatically triggers and begins the settlement process. + ```yaml + rpcs: + - chain-name: ethereum-mainnet + url: https://ethereum-rpc.publicnode.com # Or your preferred RPC provider + ``` +</Aside> -### External AI service integration +**Usage:** -The workflow sends the market question to Google's Gemini AI with search grounding enabled. Gemini searches the web to determine the factual outcome and returns a result with a confidence score. +```bash +cre account link-key [flags] +``` -### Data persistence +**Flags:** -Settlement results, including the AI's response and confidence level, are stored in [Firebase Firestore](https://firebase.google.com/docs/firestore). This creates a trail and enables the frontend to display settlement history. +| Flag | Description | +| ------------------- | --------------------------------------------------------------- | +| `-l, --owner-label` | Label for the workflow owner | +| `--unsigned` | Return the raw transaction instead of sending it to the network | +| `--yes` | Skip the confirmation prompt and proceed with the operation | -### Cryptographic signing +**Interactive flow:** -The workflow generates cryptographically signed settlement reports that the smart contract can verify. This ensures only authorized, consensus-approved data reaches the contract. +When you run this command, the CLI will: -### Full-stack architecture +1. Extract your public address from the private key in your `.env` file +2. Prompt you to provide a label for this address (e.g., "Production Wallet") +3. Check if the address is already linked +4. Display transaction details (chain, contract, estimated gas cost) +5. Ask for confirmation to execute the transaction +6. Submit the transaction and provide a block explorer link -The demo includes: +**Examples:** -- **Smart contracts** (Solidity + Foundry): `SimpleMarket.sol` for managing prediction markets -- **CRE workflow** (TypeScript): Event-driven settlement logic with AI integration -- **Database** (Firebase/Firestore): Audit trail and data persistence -- **Frontend** (Next.js): User interface for viewing settlement history +- Interactive mode (recommended) -## What you'll learn + ```bash + cre account link-key + ``` -Exploring this demo will teach you: +- Non-interactive mode with label -1. **Event-driven workflow patterns**: How to use CRE's log trigger to react to onchain events in real-time -2. **External service integration**: Best practices for integrating AI services like Gemini with your workflows -3. **Error handling and validation**: How to validate external API responses before using them onchain -4. **Data persistence patterns**: Techniques for storing workflow results in external databases -5. **Full-stack dApp architecture**: How CRE fits into a complete application with smart contracts, workflows, and frontends -6. **Cryptographic signing**: How CRE generates and submits cryptographically signed reports + ```bash + cre account link-key --owner-label "My Production Wallet" --yes + ``` -## Getting started +## `cre account list-key` -The repository includes two quick start options: +<Aside type="note" title="Authentication required"> + Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're + logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging + in with the CLI](/cre/account/cli-login) for further details. +</Aside> -### Option 1: Test CRE Workflow Only (Fastest) +Lists all public key addresses linked to your organization. This shows the verification status, chain information, and contract addresses for each linked key. -Test the workflow using a pre-deployed contract and transaction. This lets you see the workflow in action without deploying anything yourself. +For a complete guide on linking and managing keys, see [Linking Wallet Keys](/cre/organization/linking-keys). -### Option 2: Full End-to-End Test +**Usage:** -Deploy your own contracts, create markets, request settlements, and run the workflow end-to-end. This gives you complete hands-on experience with all components. +```bash +cre account list-key +``` -See the [repository README](https://github.com/smartcontractkit/cre-gcp-prediction-market-demo) for detailed prerequisites and setup instructions. +**Example output:** -## Next steps +```bash +Workflow owners retrieved successfully: -- **[Explore the repository](https://github.com/smartcontractkit/cre-gcp-prediction-market-demo)** - Clone the demo and follow the setup instructions -- **[Learn about log triggers](/cre/guides/workflow/using-triggers/evm-log-trigger)** - Understand how to build event-driven workflows -- **[Explore HTTP capabilities](/cre/guides/workflow/using-http-client)** - Learn more about integrating external APIs -- **[Browse templates](/cre/templates)** - Check out workflow templates you can copy and customize +Linked Owners: ---- + 1. my-production-wallet + Owner Address: <your_public_address> + Status: VERIFICATION_STATUS_SUCCESSFULL + Verified At: <timestamp> + Chain Selector: <chain_selector> + Contract Address: <Workflow_Registry_address> +``` -# CLI Reference -Source: https://docs.chain.link/cre/reference/cli -Last Updated: 2025-11-20 +## `cre account unlink-key` -<Aside type="note" title="Required CLI Version: v1.0.2"> - To ensure compatibility with the guides and examples in this documentation, please use version `v1.0.2` of the CRE - CLI. You can check your installed version by running `cre version`. Refer to the [CLI - Installation](/cre/getting-started/cli-installation/macos-linux) guide for more information. +<Aside type="note" title="Authentication required"> + Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're + logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging + in with the CLI](/cre/account/cli-login) for further details. </Aside> -The CRE Command Line Interface (CLI) is your primary tool for developing, testing, deploying, and managing workflows. It handles project setup, contract binding generation (Go workflows only), local simulation, and workflow lifecycle management. +Unlinks a previously linked public key address from your account. This is a destructive operation that removes the address from the Workflow Registry contract and deletes all workflows registered under that address. -## Global flags +For a complete guide on linking and unlinking keys, see [Linking Wallet Keys](/cre/organization/linking-keys). -These flags can be used with any `cre` command. -| Flag | Description | -| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `-h, --help` | Displays help information for any command | -| `-e, --env` | Specifies the path to your `.env` file (default: `".env"`) | -| `-T, --target` | Sets the target environment from your configuration files | -| `-R, --project-root` | Specifies the path to the project root directory. By default, the CLI automatically finds the project root by searching for `project.yaml` in the current directory and parent directories | -| `-v, --verbose` | Enables verbose logging to print `DEBUG` level logs | - -## Commands overview - -### Authentication - -Manage your authentication and account credentials. +<Aside type="caution" title="Destructive operation"> + **Unlinking will delete all workflows registered under this address.** This action cannot be undone. Make sure you want to permanently remove all workflows associated with this address before proceeding. +</Aside> -- **`cre login`** — Authenticate with the CRE UI and save credentials locally -- **`cre logout`** — Revoke authentication tokens and remove local credentials -- **`cre whoami`** — Show your current account details -[View authentication commands →](/cre/reference/cli/authentication) +<Aside type="note" title="Prerequisites for unlink-key"> + - Must run from a project directory with a `project.yaml` file + - **`.env` must contain `CRE_ETH_PRIVATE_KEY`** — The private key of the address you want to unlink + - Wallet must be funded with ETH on Ethereum Mainnet to pay gas fees +</Aside> -*** +**Usage:** -### Project Setup +```bash +cre account unlink-key [flags] +``` -Initialize projects and generate contract bindings (Go only). +**Flags:** -- **`cre init`** — Initialize a new CRE project with an interactive setup guide -- **`cre generate-bindings`** (Go only) — Generate Go bindings from contract ABI files for type-safe contract interactions +| Flag | Description | +| ------------ | --------------------------------------------------------------- | +| `--unsigned` | Return the raw transaction instead of sending it to the network | +| `--yes` | Skip the confirmation prompt and proceed with the operation | -[View project setup commands →](/cre/reference/cli/project-setup) +**Interactive flow:** -*** +When you run this command, the CLI will: -### Account Management +1. Extract your public address from the private key in your `.env` file (for EOA) or use your configuration (for multi-sig) +2. **Display a destructive action warning** about deleting all workflows +3. Ask for first confirmation to proceed with unlinking +4. Display transaction details (chain, contract, estimated gas cost) +5. Ask for second confirmation to execute the transaction +6. Submit the transaction and provide a block explorer link -Manage your linked public key addresses for workflow operations. +--- -- **`cre account link-key`** — Link a public key address to your account -- **`cre account list-key`** — List workflow owners linked to your organization -- **`cre account unlink-key`** — Unlink a public key address from your account +# Workflow Commands +Source: https://docs.chain.link/cre/reference/cli/workflow +Last Updated: 2025-11-04 -[View account management commands →](/cre/reference/cli/account) +The `cre workflow` commands manage workflows throughout their entire lifecycle, from local testing to deployment and ongoing management. -*** +## `cre workflow simulate` -### Workflow Commands +<Aside type="note" title="Authentication required"> + Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're + logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging + in with the CLI](/cre/account/cli-login) for further details. +</Aside> -Manage workflows throughout their entire lifecycle. +Compiles your workflow to WASM and executes it in a local simulation environment. This is the core command for testing and debugging your workflow. -- **`cre workflow simulate`** — Compile and execute workflows in a local simulation environment -- **`cre workflow deploy`** — Deploy a workflow to the Workflow Registry contract -- **`cre workflow activate`** — Activate a workflow on the Workflow Registry contract -- **`cre workflow pause`** — Pause a workflow on the Workflow Registry contract -- **`cre workflow delete`** — Delete all versions of a workflow from the Workflow Registry +**Usage:** -[View workflow commands →](/cre/reference/cli/workflow) +```bash +cre workflow simulate <workflow-name-or-path> [flags] +``` -*** +**Arguments:** -### Secrets Management +- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`). When run from the project root, you can use just the folder name. The CLI looks for a `workflow.yaml` file in the workflow directory. -Manage secrets stored in the Vault DON for use in your workflows. +**Flags:** -- **`cre secrets create`** — Create new secrets from a YAML file -- **`cre secrets update`** — Update existing secrets -- **`cre secrets delete`** — Delete secrets -- **`cre secrets list`** — List secret identifiers in a namespace +| Flag | Description | +| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--broadcast` | Broadcast onchain write transactions (default: `false`). Without this flag, a dry run is performed | +| `-g, --engine-logs` | Enable non-fatal engine logging | +| `--non-interactive` | Run without prompts; requires `--trigger-index` (see the line below) and inputs for the selected trigger type | +| `--trigger-index <int>` | Selects which handler to run (0-based position). If your workflow has multiple handlers, `0` is the first, `1` is the second, etc. Required with `--non-interactive` | +| `--http-payload <string>` | HTTP trigger payload as JSON string or path to JSON file (with or without `@` prefix). For HTTP triggers only | +| `--evm-tx-hash <string>` | Transaction hash (`0x...`) containing the event that triggered your workflow. For EVM log triggers only | +| `--evm-event-index <int>` | Which log/event within the transaction to use (0-based position). If the transaction emitted multiple events, `0` is the first, `1` is the second, etc. For EVM log triggers only | -[View secrets management commands →](/cre/reference/cli/secrets) +**Examples:** -*** +- Basic simulation -### Utilities + ```bash + cre workflow simulate ./my-workflow --target local-simulation + ``` -Additional utility commands. +- Broadcast real onchain transactions -- **`cre update`** — Update the CRE CLI to the latest version -- **`cre version`** — Print the current version of the CRE CLI + ```bash + cre workflow simulate ./my-workflow --broadcast --target local-simulation + ``` -[View utility commands →](/cre/reference/cli/utilities) +- Non-interactive mode with HTTP trigger -## Typical development workflow + ```bash + # If your HTTP trigger handler is the first handler in your workflow, use --trigger-index 0 + cre workflow simulate my-workflow --non-interactive --trigger-index 0 --http-payload '{"key":"value"}' --target staging-settings + ``` -The typical workflow development process uses these commands in sequence: +- Non-interactive mode with EVM log trigger -1. **`cre init`** — Initialize your project -2. **`cre generate-bindings`** — Generate contract bindings from ABIs (Go workflows only, if interacting with contracts) -3. **`cre workflow simulate`** — Test your workflow locally -4. **`cre workflow deploy`** — Deploy your workflow to the registry -5. **`cre workflow activate`** / **`cre workflow pause`** — Control workflow execution + ```bash + # If your EVM log trigger handler is the second handler in your workflow, use --trigger-index 1 + # --evm-event-index 0 means you want the first event from that transaction + cre workflow simulate my-workflow --non-interactive --trigger-index 1 --evm-tx-hash 0x420721d7d00130a03c5b525b2dbfd42550906ddb3075e8377f9bb5d1a5992f8e --evm-event-index 0 --target staging-settings + ``` -## Learn more -- **[CLI Installation](/cre/getting-started/cli-installation)** — How to install and set up the CRE CLI -- **[Getting Started](/cre/getting-started)** — Step-by-step tutorials using the CLI -- **[Project Configuration](/cre/reference/project-configuration)** — Understanding project structure and configuration files +<Aside type="note" title="Dry run by default"> + By default, `cre workflow simulate` performs a **dry run** for onchain write operations. It simulates the transaction to confirm it would succeed, but does not broadcast it to the network. This results in a successful log with an empty transaction hash (`0x`). To send a real transaction, use the `--broadcast` flag. +</Aside> ---- +## `cre workflow deploy` -# Authentication Commands -Source: https://docs.chain.link/cre/reference/cli/authentication -Last Updated: 2025-11-04 -The authentication commands manage your CRE credentials and account information. +<Aside type="note" title="Deployment access required"> + Deploying workflows requires Early Access approval. If you don't have deployment access yet, <a href="https://cre.chain.link/request-access" target="_blank" rel="noopener noreferrer">request it here</a>. -<Aside type="note" title="Global flags"> - All `cre` commands support [global flags](/cre/reference/cli#global-flags) like `--env`, `--target`, `--project-root`, - and `--verbose`. + **While you wait:** Continue building and simulating workflows using [`cre workflow simulate`](/cre/guides/operations/simulating-workflows). </Aside> -## `cre login` +<Aside type="note" title="Authentication required"> + Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're + logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging + in with the CLI](/cre/account/cli-login) for further details. +</Aside> -Starts the authentication flow. This command opens your browser for user login and saves your credentials locally. +Deploys a workflow to the Workflow Registry contract. This command compiles your workflow, uploads the artifacts to the CRE Storage Service, and registers the workflow onchain. **Usage:** ```bash -cre login +cre workflow deploy <workflow-name-or-path> [flags] ``` -**Authentication steps:** +**Arguments:** -1. The CLI opens your default web browser to the login page -2. Enter your account email address -3. Enter your account password -4. Enter your one-time password (OTP) from your authenticator app -5. The CLI automatically captures and saves your credentials locally +- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`) -## `cre logout` +**Flags:** -Revokes authentication tokens and removes local credentials. This invalidates the current authentication tokens and deletes stored credentials from your machine. +| Flag | Description | +| -------------- | ---------------------------------------------------------------------------------------------- | +| `-o, --output` | Output file for the compiled WASM binary encoded in base64 (default: `"./binary.wasm.br.b64"`) | +| `--unsigned` | Return the raw transaction instead of sending it to the network | +| `--yes` | Skip the confirmation prompt and proceed with the operation | -**Usage:** +**Examples:** -```bash -cre logout -``` +- Deploy workflow -## `cre whoami` + ```bash + cre workflow deploy my-workflow --target production-settings + ``` -Shows your current account details. This command fetches and displays your account information, including your email and organization ID. +- Deploy and save the compiled binary to a custom location -**Usage:** + ```bash + cre workflow deploy my-workflow --output ./dist/workflow.wasm.br.b64 + ``` -```bash -cre whoami -``` +For more details, see [Deploying Workflows](/cre/guides/operations/deploying-workflows). -<Aside type="note" title="Verify authentication"> - Use `cre whoami` to verify you're logged in and check which account is currently active. This is useful before - deploying workflows or performing other authenticated operations. +## `cre workflow activate` + +<Aside type="note" title="Authentication required"> + Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're + logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging + in with the CLI](/cre/account/cli-login) for further details. </Aside> -## Authentication workflow +Changes the workflow status to active on the Workflow Registry contract. Active workflows can respond to their configured triggers. -The typical authentication flow: +**Usage:** -1. **`cre login`** — Authenticate with the CRE UI (browser-based) -2. **`cre whoami`** — Verify your authentication and account details -3. **Perform CLI operations** — Deploy, manage workflows, etc. -4. **`cre logout`** — (Optional) Revoke credentials when done +```bash +cre workflow activate <workflow-name-or-path> [flags] +``` -## Learn more +**Arguments:** -- [Getting Started](/cre/getting-started) — Includes authentication setup in the initial steps -- [Account Management](/cre/reference/cli/account) — Link keys after authentication -- [Deploying Workflows](/cre/guides/operations/deploying-workflows) — Requires authentication +- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`) ---- +**Flags:** -# Account Management -Source: https://docs.chain.link/cre/reference/cli/account -Last Updated: 2025-11-04 +| Flag | Description | +| ------------ | --------------------------------------------------------------- | +| `--unsigned` | Return the raw transaction instead of sending it to the network | +| `--yes` | Skip the confirmation prompt and proceed with the operation | -The `cre account` commands manage your linked public key addresses for workflow operations. These commands allow you to link wallet addresses to your CRE account, list linked addresses, and unlink them when needed. +**Example:** +```bash +cre workflow activate ./my-workflow --target production-settings +``` -<Aside type="note" title="Global flags"> - All `cre` commands support [global flags](/cre/reference/cli#global-flags) like `--env`, `--target`, `--project-root`, and `--verbose`. -</Aside> +For more details, see [Activating & Pausing Workflows](/cre/guides/operations/activating-pausing-workflows). -## `cre account link-key` +## `cre workflow pause` <Aside type="note" title="Authentication required"> Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're @@ -7525,70 +8211,39 @@ The `cre account` commands manage your linked public key addresses for workflow in with the CLI](/cre/account/cli-login) for further details. </Aside> -Links a public key address to your account for workflow operations. This command reads your private key from the `.env` file (for EOA) or uses your configuration (for multi-sig), derives the public address, and registers it onchain in the Workflow Registry contract. +Changes the workflow status to paused on the Workflow Registry contract. Paused workflows will not respond to triggers. -For a complete step-by-step guide with examples, see [Linking Wallet Keys](/cre/organization/linking-keys). +**Usage:** +```bash +cre workflow pause <workflow-name-or-path> [flags] +``` -<Aside type="caution" title="Prerequisites for link-key"> - - **Must run from a project directory** with a `project.yaml` file - - **`.env` must contain `CRE_ETH_PRIVATE_KEY`** — Your wallet's private key - - **Wallet must be funded** with ETH on Ethereum Mainnet to pay gas fees - - **RPC endpoint configured** — Add an `ethereum-mainnet` RPC URL in your `project.yaml` under the `rpcs` section for your target (e.g., `https://ethereum-rpc.publicnode.com` or your preferred provider) - - **For multi-sig wallets**: Also specify `workflow-owner-address` in your `project.yaml` under the `account` section. See [Linking Wallet Keys](/cre/organization/linking-keys#using-multi-sig-wallets) for details. -</Aside> +**Arguments:** +- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`) -<Aside type="note" title="Transaction is sent to Ethereum Mainnet"> - This command always submits a transaction to **Ethereum Mainnet**, regardless of your workflow deployment environment. Ensure your wallet has sufficient ETH for gas fees and your `project.yaml` includes an RPC configuration for `ethereum-mainnet`: +**Flags:** - ```yaml - rpcs: - - chain-name: ethereum-mainnet - url: https://ethereum-rpc.publicnode.com # Or your preferred RPC provider - ``` -</Aside> +| Flag | Description | +| ------------ | --------------------------------------------------------------- | +| `--unsigned` | Return the raw transaction instead of sending it to the network | +| `--yes` | Skip the confirmation prompt and proceed with the operation | -**Usage:** +**Example:** ```bash -cre account link-key [flags] +cre workflow pause ./my-workflow --target production-settings ``` -**Flags:** - -| Flag | Description | -| ------------------- | --------------------------------------------------------------- | -| `-l, --owner-label` | Label for the workflow owner | -| `--unsigned` | Return the raw transaction instead of sending it to the network | -| `--yes` | Skip the confirmation prompt and proceed with the operation | - -**Interactive flow:** - -When you run this command, the CLI will: - -1. Extract your public address from the private key in your `.env` file -2. Prompt you to provide a label for this address (e.g., "Production Wallet") -3. Check if the address is already linked -4. Display transaction details (chain, contract, estimated gas cost) -5. Ask for confirmation to execute the transaction -6. Submit the transaction and provide a block explorer link - -**Examples:** - -- Interactive mode (recommended) - - ```bash - cre account link-key - ``` -- Non-interactive mode with label +<Aside type="caution" title="Pausing stops trigger execution"> + When you pause a workflow, it will no longer respond to any triggers. Ensure this is intentional before pausing production workflows. +</Aside> - ```bash - cre account link-key --owner-label "My Production Wallet" --yes - ``` +For more details, see [Activating & Pausing Workflows](/cre/guides/operations/activating-pausing-workflows). -## `cre account list-key` +## `cre workflow delete` <Aside type="note" title="Authentication required"> Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're @@ -7596,645 +8251,604 @@ When you run this command, the CLI will: in with the CLI](/cre/account/cli-login) for further details. </Aside> -Lists all public key addresses linked to your organization. This shows the verification status, chain information, and contract addresses for each linked key. - -For a complete guide on linking and managing keys, see [Linking Wallet Keys](/cre/organization/linking-keys). +Deletes a workflow from the Workflow Registry. **Usage:** ```bash -cre account list-key +cre workflow delete <workflow-name-or-path> [flags] ``` -**Example output:** - -```bash -Workflow owners retrieved successfully: - -Linked Owners: +**Arguments:** - 1. my-production-wallet - Owner Address: <your_public_address> - Status: VERIFICATION_STATUS_SUCCESSFULL - Verified At: <timestamp> - Chain Selector: <chain_selector> - Contract Address: <Workflow_Registry_address> -``` +- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`) -## `cre account unlink-key` +**Flags:** -<Aside type="note" title="Authentication required"> - Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're - logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging - in with the CLI](/cre/account/cli-login) for further details. -</Aside> +| Flag | Description | +| ------------ | --------------------------------------------------------------- | +| `--unsigned` | Return the raw transaction instead of sending it to the network | +| `--yes` | Skip the confirmation prompt and proceed with the operation | -Unlinks a previously linked public key address from your account. This is a destructive operation that removes the address from the Workflow Registry contract and deletes all workflows registered under that address. +**Example:** -For a complete guide on linking and unlinking keys, see [Linking Wallet Keys](/cre/organization/linking-keys). +```bash +cre workflow delete ./my-workflow --target production-settings +``` <Aside type="caution" title="Destructive operation"> - **Unlinking will delete all workflows registered under this address.** This action cannot be undone. Make sure you want to permanently remove all workflows associated with this address before proceeding. + This command **permanently deletes the workflow**. The `--yes` flag bypasses the confirmation prompt for this destructive operation. Use with caution. </Aside> +For more details, see [Deleting Workflows](/cre/guides/operations/deleting-workflows). -<Aside type="note" title="Prerequisites for unlink-key"> - - Must run from a project directory with a `project.yaml` file - - **`.env` must contain `CRE_ETH_PRIVATE_KEY`** — The private key of the address you want to unlink - - Wallet must be funded with ETH on Ethereum Mainnet to pay gas fees -</Aside> +## Workflow lifecycle -**Usage:** +The typical workflow lifecycle uses these commands in sequence: -```bash -cre account unlink-key [flags] -``` +1. **Develop locally** — Write and iterate on your workflow code +2. **`cre workflow simulate`** — Test your workflow in a local simulation environment +3. **`cre workflow deploy`** — Deploy your workflow to the registry +4. **`cre workflow pause`** / **`cre workflow activate`** — Control workflow execution as needed +5. **`cre workflow deploy`** (again) — Deploy updates (replaces the existing workflow) +6. **`cre workflow delete`** — Remove the workflow when no longer needed -**Flags:** +## Learn more -| Flag | Description | -| ------------ | --------------------------------------------------------------- | -| `--unsigned` | Return the raw transaction instead of sending it to the network | -| `--yes` | Skip the confirmation prompt and proceed with the operation | +- [Deploying Workflows](/cre/guides/operations/deploying-workflows) — Detailed deployment guide +- [Activating & Pausing Workflows](/cre/guides/operations/activating-pausing-workflows) — Managing workflow state +- [Updating Deployed Workflows](/cre/guides/operations/updating-deployed-workflows) — Version management +- [Deleting Workflows](/cre/guides/operations/deleting-workflows) — Cleanup and removal -**Interactive flow:** +--- -When you run this command, the CLI will: +# Secrets Management Commands +Source: https://docs.chain.link/cre/reference/cli/secrets +Last Updated: 2025-11-04 -1. Extract your public address from the private key in your `.env` file (for EOA) or use your configuration (for multi-sig) -2. **Display a destructive action warning** about deleting all workflows -3. Ask for first confirmation to proceed with unlinking -4. Display transaction details (chain, contract, estimated gas cost) -5. Ask for second confirmation to execute the transaction -6. Submit the transaction and provide a block explorer link +<Aside type="note" title="Authentication required"> + Running the commands on this page requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to + verify you're logged in, or run `cre login` to authenticate. See [Creating Your + Account](/cre/account/creating-account) and [Logging in with the CLI](/cre/account/cli-login) for further details. +</Aside> ---- +The `cre secrets` commands manage secrets stored in the Vault DON (Decentralized Oracle Network) for deployed workflows. These commands allow you to create, update, delete, and list secrets that your workflows can access at runtime. -# Workflow Commands -Source: https://docs.chain.link/cre/reference/cli/workflow -Last Updated: 2025-11-04 +## Namespaces -The `cre workflow` commands manage workflows throughout their entire lifecycle, from local testing to deployment and ongoing management. +Secrets are organized into **namespaces**, which act as logical groupings (e.g., `"main"`, `"staging"`, `"production"`). All secrets are stored in the `"main"` namespace by default. Currently, `create`, `update`, and `delete` commands only support the default namespace. Custom namespace support may be added in future CLI versions. -## `cre workflow simulate` -<Aside type="note" title="Authentication required"> - Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're - logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging - in with the CLI](/cre/account/cli-login) for further details. +<Aside type="note" title="Prerequisites"> + - You must be logged in with `cre login` + - Your `workflow-owner-address` must be configured in your project + - For comprehensive guides on using secrets, see [Managing Secrets](/cre/guides/workflow/secrets) </Aside> -Compiles your workflow to WASM and executes it in a local simulation environment. This is the core command for testing and debugging your workflow. -**Usage:** +<Aside type="note" title="Global flags"> + All `cre` commands support [global flags](/cre/reference/cli#global-flags) like `--env`, `--target`, `--project-root`, and `--verbose`. +</Aside> + +## cre secrets create + +Creates new secrets in the Vault DON from a YAML file. + +### Usage ```bash -cre workflow simulate <workflow-name-or-path> [flags] +cre secrets create [SECRETS_FILE_PATH] [flags] ``` -**Arguments:** +### Arguments -- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`). When run from the project root, you can use just the folder name. The CLI looks for a `workflow.yaml` file in the workflow directory. +- `SECRETS_FILE_PATH` — (Required) Path to a YAML file containing the secrets to create -**Flags:** +### Flags -| Flag | Description | -| ------------------------- | -------------------------------------------------------------------------------------------------- | -| `--broadcast` | Broadcast onchain write transactions (default: `false`). Without this flag, a dry run is performed | -| `-g, --engine-logs` | Enable non-fatal engine logging | -| `--non-interactive` | Run without prompts; requires `--trigger-index` and inputs for the selected trigger type | -| `--trigger-index <int>` | Index of the trigger to run (0-based). Required when using `--non-interactive` | -| `--http-payload <string>` | HTTP trigger payload as JSON string or path to JSON file (with or without `@` prefix) | -| `--evm-tx-hash <string>` | EVM trigger transaction hash (`0x...`). For EVM log triggers | -| `--evm-event-index <int>` | EVM trigger log index (0-based). For EVM log triggers | +| Flag | Type | Default | Description | +| ------------ | -------- | ------- | --------------------------------------------------------------- | +| `--timeout` | duration | `48h` | Timeout for the operation (e.g., `30m`, `2h`, `48h`). Max: `7d` | +| `--unsigned` | boolean | `false` | Generate raw transaction data for multi-sig wallets | -**Examples:** +### Input file format -- Basic simulation +YAML file with `secretsNames` structure: - ```bash - cre workflow simulate ./my-workflow --target local-simulation - ``` +```yaml +secretsNames: + API_KEY: + - API_KEY_VALUE -- Broadcast real onchain transactions + DATABASE_URL: + - DATABASE_URL_VALUE +``` - ```bash - cre workflow simulate ./my-workflow --broadcast --target local-simulation - ``` +- `secretsNames` — Top-level key containing all secrets +- Each secret key (e.g., `API_KEY`) maps to an array containing an environment variable name +- Secret values are read from environment variables or `.env` file -<Aside type="note" title="Dry run by default"> - By default, `cre workflow simulate` performs a **dry run** for onchain write operations. It simulates the transaction to confirm it would succeed, but does not broadcast it to the network. This results in a successful log with an empty transaction hash (`0x`). To send a real transaction, use the `--broadcast` flag. +<Aside type="note" title="Default namespace"> + Secrets are stored in the `"main"` namespace automatically. Custom namespace support may be added in future CLI versions. </Aside> -## `cre workflow deploy` +### Examples +- Create secrets from YAML file -<Aside type="note" title="Deployment access required"> - Deploying workflows requires Early Access approval. If you don't have deployment access yet, <a href="https://cre.chain.link/request-access" target="_blank" rel="noopener noreferrer">request it here</a>. + ```bash + cre secrets create my-secrets.yaml --target production-settings + ``` - **While you wait:** Continue building and simulating workflows using [`cre workflow simulate`](/cre/guides/operations/simulating-workflows). -</Aside> +- Create secrets with custom timeout -<Aside type="note" title="Authentication required"> - Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're - logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging - in with the CLI](/cre/account/cli-login) for further details. -</Aside> + ```bash + cre secrets create my-secrets.yaml --timeout 1h + ``` -Deploys a workflow to the Workflow Registry contract. This command compiles your workflow, uploads the artifacts to the CRE Storage Service, and registers the workflow onchain. +- Create secrets for multi-sig wallets -**Usage:** + ```bash + cre secrets create my-secrets.yaml --unsigned + ``` + +## cre secrets update + +Updates existing secrets in the Vault DON from a YAML file. + +### Usage ```bash -cre workflow deploy <workflow-name-or-path> [flags] +cre secrets update [SECRETS_FILE_PATH] [flags] ``` -**Arguments:** +### Arguments -- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`) +- `SECRETS_FILE_PATH` — (Required) Path to a YAML file containing the secrets to update -**Flags:** +### Flags -| Flag | Description | -| -------------- | ---------------------------------------------------------------------------------------------- | -| `-o, --output` | Output file for the compiled WASM binary encoded in base64 (default: `"./binary.wasm.br.b64"`) | -| `--unsigned` | Return the raw transaction instead of sending it to the network | -| `--yes` | Skip the confirmation prompt and proceed with the operation | +| Flag | Type | Default | Description | +| ------------ | -------- | ------- | --------------------------------------------------------------- | +| `--timeout` | duration | `48h` | Timeout for the operation (e.g., `30m`, `2h`, `48h`). Max: `7d` | +| `--unsigned` | boolean | `false` | Generate raw transaction data for multi-sig wallets | -**Examples:** +### Input file format -- Deploy workflow +Same YAML format as `create`. + +### Examples + +- Update secrets ```bash - cre workflow deploy my-workflow --target production-settings + cre secrets update my-secrets.yaml --target production-settings ``` -- Deploy and save the compiled binary to a custom location +- Update secrets with custom timeout ```bash - cre workflow deploy my-workflow --output ./dist/workflow.wasm.br.b64 + cre secrets update my-secrets.yaml --timeout 6h ``` -For more details, see [Deploying Workflows](/cre/guides/operations/deploying-workflows). -## `cre workflow activate` +<Aside type="note" title="Update behavior"> + Only modifies secrets that already exist. To create new secrets, use `cre secrets create`. +</Aside> -<Aside type="note" title="Authentication required"> - Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're - logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging - in with the CLI](/cre/account/cli-login) for further details. -</Aside> +## cre secrets delete -Changes the workflow status to active on the Workflow Registry contract. Active workflows can respond to their configured triggers. +Deletes secrets from the Vault DON based on a YAML file. -**Usage:** +### Usage ```bash -cre workflow activate <workflow-name-or-path> [flags] +cre secrets delete [SECRETS_FILE_PATH] [flags] ``` -**Arguments:** +### Arguments -- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`) +- `SECRETS_FILE_PATH` — (Required) Path to a YAML file containing the secrets to delete -**Flags:** +### Flags -| Flag | Description | -| ------------ | --------------------------------------------------------------- | -| `--unsigned` | Return the raw transaction instead of sending it to the network | -| `--yes` | Skip the confirmation prompt and proceed with the operation | +| Flag | Type | Default | Description | +| ------------ | -------- | ------- | --------------------------------------------------------------- | +| `--timeout` | duration | `48h` | Timeout for the operation (e.g., `30m`, `2h`, `48h`). Max: `7d` | +| `--unsigned` | boolean | `false` | Generate raw transaction data for multi-sig wallets | -**Example:** +### Input file format -```bash -cre workflow activate ./my-workflow --target production-settings -``` +YAML file with a simple list of secret identifiers to delete: -For more details, see [Activating & Pausing Workflows](/cre/guides/operations/activating-pausing-workflows). +```yaml +secretsNames: + - API_KEY + - OLD_SECRET +``` -## `cre workflow pause` -<Aside type="note" title="Authentication required"> - Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're - logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging - in with the CLI](/cre/account/cli-login) for further details. +<Aside type="note" title="Deletion format"> + The `delete` command uses a simpler format than `create`/`update`: just a list of secret IDs. All secrets are deleted from the `"main"` namespace. </Aside> -Changes the workflow status to paused on the Workflow Registry contract. Paused workflows will not respond to triggers. - -**Usage:** +### Example ```bash -cre workflow pause <workflow-name-or-path> [flags] +cre secrets delete secrets-to-delete.yaml --target production-settings ``` -**Arguments:** -- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`) +<Aside type="caution" title="Permanent deletion"> + Deleting secrets is permanent and cannot be undone. +</Aside> -**Flags:** +## cre secrets list -| Flag | Description | -| ------------ | --------------------------------------------------------------- | -| `--unsigned` | Return the raw transaction instead of sending it to the network | -| `--yes` | Skip the confirmation prompt and proceed with the operation | +Lists all secret identifiers for your owner address in a specific namespace. -**Example:** +### Usage ```bash -cre workflow pause ./my-workflow --target production-settings +cre secrets list [flags] ``` +### Flags -<Aside type="caution" title="Pausing stops trigger execution"> - When you pause a workflow, it will no longer respond to any triggers. Ensure this is intentional before pausing production workflows. -</Aside> +| Flag | Type | Default | Description | +| ------------- | -------- | -------- | --------------------------------------------------------------- | +| `--namespace` | string | `"main"` | Namespace to list secrets from | +| `--timeout` | duration | `48h` | Timeout for the operation (e.g., `30m`, `2h`, `48h`). Max: `7d` | +| `--unsigned` | boolean | `false` | Generate raw transaction data for multi-sig wallets | -For more details, see [Activating & Pausing Workflows](/cre/guides/operations/activating-pausing-workflows). +### Example -## `cre workflow delete` +- List secrets in default namespace -<Aside type="note" title="Authentication required"> - Running this command requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to verify you're - logged in, or run `cre login` to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging - in with the CLI](/cre/account/cli-login) for further details. -</Aside> + ```bash + cre secrets list --target production-settings + ``` -Deletes a workflow from the Workflow Registry. +- List secrets in specific namespace -**Usage:** + ```bash + cre secrets list --namespace production + ``` -```bash -cre workflow delete <workflow-name-or-path> [flags] -``` +### Output -**Arguments:** +Returns secret identifiers (not values) for the specified namespace: -- `<workflow-name-or-path>` — (Required) Workflow folder name (e.g., `my-workflow`) or path (e.g., `./my-workflow`) +``` +Secret identifiers in namespace 'main': + - API_KEY + - DATABASE_URL + - WEBHOOK_SECRET +``` -**Flags:** -| Flag | Description | -| ------------ | --------------------------------------------------------------- | -| `--unsigned` | Return the raw transaction instead of sending it to the network | -| `--yes` | Skip the confirmation prompt and proceed with the operation | +<Aside type="note" title="Security"> + Only returns secret identifiers, never the actual values. Secret values are only accessible to workflows at runtime. +</Aside> -**Example:** +## Using with multi-sig wallets + +All commands support the `--unsigned` flag for multi-sig operations: ```bash -cre workflow delete ./my-workflow --target production-settings +cre secrets create my-secrets.yaml --unsigned ``` +When `--unsigned` is used: -<Aside type="caution" title="Destructive operation"> - This command **permanently deletes the workflow**. The `--yes` flag bypasses the confirmation prompt for this destructive operation. Use with caution. -</Aside> - -For more details, see [Deleting Workflows](/cre/guides/operations/deleting-workflows). - -## Workflow lifecycle - -The typical workflow lifecycle uses these commands in sequence: +1. CLI generates raw transaction data instead of broadcasting +2. Transaction payload is returned for submission through your multi-sig interface +3. After multi-sig confirmation, the secrets operation proceeds -1. **Develop locally** — Write and iterate on your workflow code -2. **`cre workflow simulate`** — Test your workflow in a local simulation environment -3. **`cre workflow deploy`** — Deploy your workflow to the registry -4. **`cre workflow pause`** / **`cre workflow activate`** — Control workflow execution as needed -5. **`cre workflow deploy`** (again) — Deploy updates (replaces the existing workflow) -6. **`cre workflow delete`** — Remove the workflow when no longer needed +For details, see [Using Multi-sig Wallets](/cre/guides/operations/using-multisig-wallets). ## Learn more -- [Deploying Workflows](/cre/guides/operations/deploying-workflows) — Detailed deployment guide -- [Activating & Pausing Workflows](/cre/guides/operations/activating-pausing-workflows) — Managing workflow state -- [Updating Deployed Workflows](/cre/guides/operations/updating-deployed-workflows) — Version management -- [Deleting Workflows](/cre/guides/operations/deleting-workflows) — Cleanup and removal +- [Managing Secrets](/cre/guides/workflow/secrets) — Overview and decision tree for secrets management +- [Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation) — For local development +- [Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed) — Complete guide with examples +- [Managing Secrets with 1Password](/cre/guides/workflow/secrets/managing-secrets-1password) — Best practice for secure management +- [Using Multi-sig Wallets](/cre/guides/operations/using-multisig-wallets) — Multi-sig configuration --- -# Secrets Management Commands -Source: https://docs.chain.link/cre/reference/cli/secrets -Last Updated: 2025-11-04 +# Utility Commands +Source: https://docs.chain.link/cre/reference/cli/utilities +Last Updated: 2026-02-03 -<Aside type="note" title="Authentication required"> - Running the commands on this page requires you to be logged in with the CRE CLI. Run `cre whoami` in your terminal to - verify you're logged in, or run `cre login` to authenticate. See [Creating Your - Account](/cre/account/creating-account) and [Logging in with the CLI](/cre/account/cli-login) for further details. +Utility commands provide helpful information and troubleshooting capabilities. + + +<Aside type="note" title="Global flags"> + All `cre` commands support [global flags](/cre/reference/cli#global-flags) like `--env`, `--target`, `--project-root`, and `--verbose`. </Aside> -The `cre secrets` commands manage secrets stored in the Vault DON (Decentralized Oracle Network) for deployed workflows. These commands allow you to create, update, delete, and list secrets that your workflows can access at runtime. +## `cre update` -## Namespaces +Updates the CRE CLI to the latest version. This command automatically downloads and installs the newest release, making it easy to stay up to date. -Secrets are organized into **namespaces**, which act as logical groupings (e.g., `"main"`, `"staging"`, `"production"`). All secrets are stored in the `"main"` namespace by default. Currently, `create`, `update`, and `delete` commands only support the default namespace. Custom namespace support may be added in future CLI versions. +**Usage:** +```bash +cre update +``` -<Aside type="note" title="Prerequisites"> - - You must be logged in with `cre login` - - Your `workflow-owner-address` must be configured in your project - - For comprehensive guides on using secrets, see [Managing Secrets](/cre/guides/workflow/secrets) +**Behavior:** + +- Checks for the latest available version on <a href="https://github.com/smartcontractkit/cre-cli" target="_blank" rel="noopener noreferrer">GitHub</a> +- Compares it with your currently installed version +- Automatically downloads and installs the update if a newer version is available +- Downloads the appropriate binary for your operating system and architecture +- Replaces the existing CLI binary with the new version + + +<Aside type="tip" title="Automatic version checks"> + The CLI automatically checks if your version is outdated when you run certain commands. If a newer version is available, you'll see a warning message encouraging you to run `cre update`. </Aside> -<Aside type="note" title="Global flags"> - All `cre` commands support [global flags](/cre/reference/cli#global-flags) like `--env`, `--target`, `--project-root`, and `--verbose`. +<Aside type="note" title="Updating existing projects"> + Running `cre update` updates the CLI itself. For existing projects, you may also need to update your SDK dependency to access new features. See [Updating Dependencies](/cre/reference/project-configuration#updating-dependencies) for instructions. </Aside> -## cre secrets create +## `cre version` -Creates new secrets in the Vault DON from a YAML file. +Prints the current version of the CRE CLI. -### Usage +**Usage:** ```bash -cre secrets create [SECRETS_FILE_PATH] [flags] +cre version ``` -### Arguments +**Example output:** -- `SECRETS_FILE_PATH` — (Required) Path to a YAML file containing the secrets to create +```bash +cre version v1.0.10 +``` -### Flags -| Flag | Type | Default | Description | -| ------------ | -------- | ------- | --------------------------------------------------------------- | -| `--timeout` | duration | `48h` | Timeout for the operation (e.g., `30m`, `2h`, `48h`). Max: `7d` | -| `--unsigned` | boolean | `false` | Generate raw transaction data for multi-sig wallets | +<Aside type="note" title="Version compatibility"> + Always check that your CLI version matches the version recommended in the documentation. The current recommended version is **v1.0.10**. See the [CLI Installation guide](/cre/getting-started/cli-installation) for more information. +</Aside> -### Input file format +## Learn more -YAML file with `secretsNames` structure: +- [CLI Installation](/cre/getting-started/cli-installation) — How to install and update the CRE CLI +- [CLI Reference](/cre/reference/cli) — Complete CLI command reference -```yaml -secretsNames: - API_KEY: - - API_KEY_VALUE +--- - DATABASE_URL: - - DATABASE_URL_VALUE -``` +# The Confidential HTTP Capability (Experimental) +Source: https://docs.chain.link/cre/capabilities/confidential-http-go +Last Updated: 2026-02-06 -- `secretsNames` — Top-level key containing all secrets -- Each secret key (e.g., `API_KEY`) maps to an array containing an environment variable name -- Secret values are read from environment variables or `.env` file +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> +The **Confidential HTTP** capability is a privacy-preserving HTTP service powered by the Chainlink Privacy Standard. It enables your workflow to interact with external APIs while keeping sensitive data—such as API credentials, request body fields, and response data—confidential. -<Aside type="note" title="Default namespace"> - Secrets are stored in the `"main"` namespace automatically. Custom namespace support may be added in future CLI versions. -</Aside> +## The problem it solves -### Examples +Traditional consensus mechanisms require all nodes to see and agree on the same data. While this provides strong reliability and tamper resistance, it creates challenges for use cases with strict privacy requirements: -- Create secrets from YAML file +- **Regulatory compliance:** Some industries require that sensitive data never be exposed to multiple parties. +- **Credential security:** High-risk API credentials could cause damage if compromised or exposed in node memory. +- **Response privacy:** API responses may contain sensitive fields that should not be visible to the decentralized network. - ```bash - cre secrets create my-secrets.yaml --target production-settings - ``` +Confidential HTTP addresses these challenges by executing requests inside a **secure enclave** and offering optional **response encryption**. -- Create secrets with custom timeout +## How it works - ```bash - cre secrets create my-secrets.yaml --timeout 1h - ``` +Confidential HTTP operates differently from the [regular HTTP capability](/cre/capabilities/http): -- Create secrets for multi-sig wallets +1. **Request consensus:** Nodes in the Confidential HTTP DON reach quorum on the request parameters (forwarded by each Workflow DON node). +2. **Secret retrieval:** The Confidential HTTP DON fetches encrypted secrets from the [Vault DON](/cre/guides/workflow/secrets/using-secrets-deployed). +3. **Enclave execution:** Secrets are decrypted and injected into the request inside a secure enclave. The HTTP request executes from the enclave—credentials never exist in accessible memory. +4. **Response:** The response is returned to your workflow. If `EncryptOutput` is enabled, the response body is encrypted before leaving the enclave. - ```bash - cre secrets create my-secrets.yaml --unsigned - ``` +This approach ensures: -## cre secrets update +- **Credential isolation:** Secrets are encrypted at rest and in transit, and are decrypted only inside the enclave—never in node memory. +- **Response privacy:** You can optionally encrypt the full response body so that it leaves the enclave encrypted and can be decrypted only in your own backend service. +- **Single execution:** Exactly one API call is made, not one per node. -Updates existing secrets in the Vault DON from a YAML file. +## What's kept confidential -### Usage +| Component | How it's protected | +| :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Secrets** (API keys, tokens) | Fully confidential. Stored in the Vault DON, decrypted only inside the enclave. | +| **Request body** | Template-based injection: secrets referenced in the request body (e.g., `{{.myApiKey}}`) are resolved inside the enclave, so sensitive values never appear in workflow memory. | +| **Response body** | Optionally encrypted. When `EncryptOutput` is enabled, the full response is [AES-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode) encrypted before leaving the enclave. | -```bash -cre secrets update [SECRETS_FILE_PATH] [flags] -``` +## Use cases -### Arguments +### Credential isolation -- `SECRETS_FILE_PATH` — (Required) Path to a YAML file containing the secrets to update +A SaaS service fetches user data from an e-commerce provider API. The same credential could also modify user data if misused. Confidential HTTP ensures the credential is decrypted only inside the enclave, never accessible in node memory. -### Flags +### Response encryption -| Flag | Type | Default | Description | -| ------------ | -------- | ------- | --------------------------------------------------------------- | -| `--timeout` | duration | `48h` | Timeout for the operation (e.g., `30m`, `2h`, `48h`). Max: `7d` | -| `--unsigned` | boolean | `false` | Generate raw transaction data for multi-sig wallets | +A workflow calls a payment processor API to execute a transaction. The API response includes the transaction ID and success status, but also returns sensitive data like the user's account balance and an internal risk score. With Confidential HTTP and `EncryptOutput` enabled, the full response is encrypted before leaving the enclave—it can only be decrypted using the encryption key, for example in your own backend service. -### Input file format - -Same YAML format as `create`. - -### Examples - -- Update secrets - - ```bash - cre secrets update my-secrets.yaml --target production-settings - ``` +### Processing sensitive request data -- Update secrets with custom timeout +A workflow processes card transactions where the request contains card details and the API key provides processor access. Confidential HTTP keeps both the credentials and card details private through template-based injection, returning only the encrypted response to the workflow. - ```bash - cre secrets update my-secrets.yaml --timeout 6h - ``` +### Guaranteed single execution +An API endpoint cannot tolerate duplicate requests (e.g., initiating a payment or creating a unique transaction). -<Aside type="note" title="Update behavior"> - Only modifies secrets that already exist. To create new secrets, use `cre secrets create`. -</Aside> +With the [regular HTTP capability](/cre/capabilities/http), each node in the DON executes the request independently to reach consensus on the response. For non-idempotent operations, [`cacheSettings` mitigates](/cre/guides/workflow/using-http-client/post-request-go#1-understanding-single-execution-with-cachesettings) this by enabling nodes to share cached responses, reducing duplicate calls in most cases. -## cre secrets delete +Confidential HTTP takes a different approach: by design, only one request is ever made from the enclave after quorum is reached on the request parameters. This provides an **architectural guarantee** of single execution. -Deletes secrets from the Vault DON based on a YAML file. +## When to use Confidential HTTP vs. regular HTTP -### Usage +### Use Confidential HTTP when: -```bash -cre secrets delete [SECRETS_FILE_PATH] [flags] -``` +- The API response contains sensitive data that should not be visible to the network +- API credentials must never be accessible in node memory (enclave-only access) +- You need exactly one API call with zero tolerance for duplicates +- Regulatory or compliance requirements mandate data confidentiality -### Arguments +### Use regular HTTP when: -- `SECRETS_FILE_PATH` — (Required) Path to a YAML file containing the secrets to delete +- **Querying multiple APIs and combining results**: For example, fetching prices from 3 different sources and computing a median. Each node calls all APIs, aggregates locally, then nodes reach consensus on the final value. -### Flags +- **Transforming data before consensus**: For example, parsing a complex API response, filtering fields, or performing calculations on the data before nodes agree on the result. -| Flag | Type | Default | Description | -| ------------ | -------- | ------- | --------------------------------------------------------------- | -| `--timeout` | duration | `48h` | Timeout for the operation (e.g., `30m`, `2h`, `48h`). Max: `7d` | -| `--unsigned` | boolean | `false` | Generate raw transaction data for multi-sig wallets | +- **Computing with a secret before the request**: For example, generating an HMAC signature for API authentication — use the [`runInNodeMode` pattern](/cre/guides/workflow/using-http-client/post-request-go#2-the-creruninnodemode-pattern-alternative) to access secrets and perform computations before making the request. -### Input file format +- **No confidentiality requirements**: The API response doesn't contain sensitive data, and you don't need enclave-level protection for credentials. -YAML file with a simple list of secret identifiers to delete: +## Key differences from regular HTTP -```yaml -secretsNames: - - API_KEY - - OLD_SECRET -``` +| Aspect | Regular HTTP | Confidential HTTP | +| :------------------------ | :------------------------------------ | :----------------------------- | +| **API calls** | One per node (multiple)\* | Exactly one (single) | +| **Consensus target** | Response data | Request parameters | +| **Execution environment** | Each node individually | Secure enclave | +| **Secrets exposure** | Decrypted in Workflow DON node memory | Decrypted only in the enclave | +| **Response handling** | Full response to all nodes | Optionally encrypted (AES-GCM) | +| **Data transformation** | Supported in workflow code | Not yet supported in enclave | +\*For non-idempotent operations (POST, PUT, PATCH, DELETE), [`cacheSettings`](/cre/guides/workflow/using-http-client/post-request#1-understanding-single-execution-with-cachesettings) enables nodes to share cached responses, reducing multiple calls to a single execution in most cases. -<Aside type="note" title="Deletion format"> - The `delete` command uses a simpler format than `create`/`update`: just a list of secret IDs. All secrets are deleted from the `"main"` namespace. +<Aside type="note" title="Confidential Compute"> + Confidential HTTP currently does not support complex data transformations within the enclave. A future **Confidential + Compute** capability will enable processing logic inside the enclave. </Aside> -### Example - -```bash -cre secrets delete secrets-to-delete.yaml --target production-settings -``` +## Learn more +- **[Confidential API Interactions Guide](/cre/guides/workflow/using-confidential-http-client)**: Learn how to use the SDK to invoke the Confidential HTTP capability. +- **[Confidential HTTP Client SDK Reference](/cre/reference/sdk/confidential-http-client)**: See the detailed API reference for the `confidentialhttp.Client`. -<Aside type="caution" title="Permanent deletion"> - Deleting secrets is permanent and cannot be undone. -</Aside> +--- -## cre secrets list +# Finality and Confidence Levels +Source: https://docs.chain.link/cre/concepts/finality-go +Last Updated: 2025-12-10 -Lists all secret identifiers for your owner address in a specific namespace. +Finality determines when a blockchain transaction is considered irreversible. Until a block is finalized, it could be reorganized (replaced by a different block if the chain temporarily forks), which means any data you read from it might change. -### Usage +Different blockchains achieve finality in different ways and at different speeds. CRE abstracts these differences through **confidence levels**, allowing you to specify your finality requirements without needing to know the underlying chain-specific implementation. -```bash -cre secrets list [flags] -``` +## Understanding CRE's finality model -### Flags +CRE provides three confidence levels for reading blockchain data and monitoring events. These levels work consistently across all supported chains. -| Flag | Type | Default | Description | -| ------------- | -------- | -------- | --------------------------------------------------------------- | -| `--namespace` | string | `"main"` | Namespace to list secrets from | -| `--timeout` | duration | `48h` | Timeout for the operation (e.g., `30m`, `2h`, `48h`). Max: `7d` | -| `--unsigned` | boolean | `false` | Generate raw transaction data for multi-sig wallets | +### The three confidence levels -### Example +| Confidence Level | Description | Use Case | +| ---------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| **`LATEST`** | The most recent block. No finality guarantees—the block could still be reorganized. | Non-critical, time-sensitive operations where speed matters more than certainty. | +| **`SAFE`** | A block that is unlikely to be reorganized, but not yet fully finalized. | A balance between speed and security for most operations. | +| **`FINALIZED`** | A block that is considered irreversible. This is the safest option. | Critical operations where you need absolute certainty the data won't change. | -- List secrets in default namespace +**Choosing the right level:** - ```bash - cre secrets list --target production-settings - ``` +- **`FINALIZED`** — Use for financial transactions, critical state updates, or when incorrect data could cause significant issues +- **`SAFE`** — Use when you need reasonable confidence without waiting for full finality (good for most monitoring/alerting) +- **`LATEST`** — Use for real-time dashboards or displays where speed matters more than guaranteed accuracy -- List secrets in specific namespace +### How confidence levels map to chains - ```bash - cre secrets list --namespace production - ``` +**SAFE and LATEST:** -### Output +CRE uses the chain's native `safe` and `latest` block tags respectively for all supported chains. -Returns secret identifiers (not values) for the specified namespace: +**FINALIZED:** -``` -Secret identifiers in namespace 'main': - - API_KEY - - DATABASE_URL - - WEBHOOK_SECRET -``` +When you specify `FINALIZED` in your workflow, CRE automatically maps this to a native finality tag or a block depth threshold depending on the chain. +| Chain | Finality Method | Block Depth | +| ------------------------------- | ---------------------------- | ----------- | +| Arbitrum One / Arbitrum Sepolia | Native `finalized` tag | — | +| Avalanche / Avalanche Fuji | Native `finalized` tag | — | +| Base / Base Sepolia | Native `finalized` tag | — | +| BNB Chain / BNB Testnet | Native `finalized` tag | — | +| Ethereum / Ethereum Sepolia | Native `finalized` tag | — | +| OP Mainnet / OP Sepolia | Native `finalized` tag | — | +| Polygon / Polygon Amoy | Block depth (500 blocks ago) | 500 | -<Aside type="note" title="Security"> - Only returns secret identifiers, never the actual values. Secret values are only accessible to workflows at runtime. -</Aside> +## Finality for chain reads -## Using with multi-sig wallets +Chain read operations ([`CallContract`](/cre/reference/sdk/evm-client-go#callcontract), [`BalanceAt`](/cre/reference/sdk/evm-client-go#balanceat), [`FilterLogs`](/cre/reference/sdk/evm-client-go#filterlogs), etc.) support confidence levels and custom block depths. -All commands support the `--unsigned` flag for multi-sig operations: +### Using confidence levels -```bash -cre secrets create my-secrets.yaml --unsigned -``` +For most read operations, use the standard confidence levels by passing `-2` (latest) or `-3` (finalized) as the `BlockNumber` parameter. If you don't specify a block number, CRE defaults to `LATEST`. -When `--unsigned` is used: +**Note:** The `SAFE` confidence level is not available for chain reads—only `LATEST` and `FINALIZED` are supported. -1. CLI generates raw transaction data instead of broadcasting -2. Transaction payload is returned for submission through your multi-sig interface -3. After multi-sig confirmation, the secrets operation proceeds +### Custom block depths -For details, see [Using Multi-sig Wallets](/cre/guides/operations/using-multisig-wallets). +For use cases requiring fixed confirmation thresholds or historical state verification, you can specify **any explicit block number** instead of using the predefined confidence levels. This enables you to: -## Learn more +- Implement custom finality rules tailored to your risk profile (e.g., "always wait 1,000 blocks") +- Meet regulatory requirements that mandate fixed, auditable confirmation thresholds +- Query historical state at specific past block heights for analysis or verification -- [Managing Secrets](/cre/guides/workflow/secrets) — Overview and decision tree for secrets management -- [Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation) — For local development -- [Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed) — Complete guide with examples -- [Managing Secrets with 1Password](/cre/guides/workflow/secrets/managing-secrets-1password) — Best practice for secure management -- [Using Multi-sig Wallets](/cre/guides/operations/using-multisig-wallets) — Multi-sig configuration +**When to use custom block depths:** ---- +- **Regulatory compliance** — Your interactions require provable, fixed confirmation thresholds for auditors +- **Changing chain parameters** — The chain's finality definition may change, but your security model must remain constant +- **Historical verification** — You need to verify state at a specific moment -# Utility Commands -Source: https://docs.chain.link/cre/reference/cli/utilities -Last Updated: 2025-11-20 +**Implementation:** -Utility commands provide helpful information and troubleshooting capabilities. +You can pass any `*big.Int` directly as the `BlockNumber` parameter. The SDK accepts both special values (like `-2` for latest, `-3` for finalized) and positive integers for explicit block heights. See [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read-go#custom-block-depths) for examples. +## Finality for chain writes -<Aside type="note" title="Global flags"> - All `cre` commands support [global flags](/cre/reference/cli#global-flags) like `--env`, `--target`, `--project-root`, and `--verbose`. -</Aside> +Chain write operations return a [`WriteReportReply`](/cre/reference/sdk/evm-client-go#evmwritereportreply) when the transaction is included in a block, not when it reaches finality. -## `cre update` +### What a successful response means -Updates the CRE CLI to the latest version. This command automatically downloads and installs the newest release, making it easy to stay up to date. +When [`WriteReportReply`](/cre/reference/sdk/evm-client-go#evmwritereportreply) returns with `TxStatus` equal to `SUCCESS`: -**Usage:** +- Your transaction was **included in a block** +- The transaction is **not necessarily finalized** yet -```bash -cre update -``` +The reply is returned as soon as the transaction appears in a block, not when the block reaches finality. This is important for time-sensitive workflows, but it means the transaction could still be reorganized. -**Behavior:** +### Reorg handling -- Checks for the latest available version on <a href="https://github.com/smartcontractkit/cre-cli" target="_blank" rel="noopener noreferrer">GitHub</a> -- Compares it with your currently installed version -- Automatically downloads and installs the update if a newer version is available -- Downloads the appropriate binary for your operating system and architecture -- Replaces the existing CLI binary with the new version +If a block containing your transaction is reorganized: +- CRE's Transaction Manager (TXM) automatically resubmits your transaction +- Gas bumping is applied as needed to ensure the transaction is included +- **Important:** The transaction hash may change during resubmission +- You are not automatically notified if the hash changes -<Aside type="tip" title="Automatic version checks"> - The CLI automatically checks if your version is outdated when you run certain commands. If a newer version is available, you'll see a warning message encouraging you to run `cre update`. +<Aside type="caution" title="For mission-critical applications"> + If you need absolute certainty that your write transaction reached finality, implement post-write verification by + reading the blockchain state after a custom number of confirmations. Do not rely solely on `WriteReportReply` for + finality confirmation. </Aside> -## `cre version` - -Prints the current version of the CRE CLI. - -**Usage:** - -```bash -cre version -``` - -**Example output:** - -```bash -cre version v1.0.2 -``` - - -<Aside type="note" title="Version compatibility"> - Always check that your CLI version matches the version recommended in the documentation. The current recommended version is **v1.0.2**. See the [CLI Installation guide](/cre/getting-started/cli-installation) for more information. -</Aside> +## Finality for event triggers -## Learn more +EVM Log Triggers must use the three confidence levels (`LATEST`, `SAFE`, or `FINALIZED`). Custom block depths are not supported for triggers. -- [CLI Installation](/cre/getting-started/cli-installation) — How to install and update the CRE CLI -- [CLI Reference](/cre/reference/cli) — Complete CLI command reference +By default, triggers use `SAFE` if no confidence level is specified. For details on configuring trigger confidence levels, see [EVM Log Trigger](/cre/reference/sdk/triggers/evm-log-trigger-go#evmfilterlogtriggerrequest). --- # Avoiding Non-Determinism in Workflows Source: https://docs.chain.link/cre/concepts/non-determinism-go -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 <Aside type="note" title="TL;DR"> In DON mode, all nodes must execute identical code paths to reach consensus. Non-deterministic code causes nodes to @@ -8295,7 +8909,7 @@ Never use Go's `time` package functions in DON mode. Nodes have different system **The problem:** Using `time.Now()` returns different values on each node. -**The solution:** Use `runtime.Now()` from the CRE SDK, which provides DON Time—a consensus-derived timestamp that all nodes agree on. See [Time in CRE](/cre/concepts/time-in-cre) for details. +**The solution:** Use `runtime.Now()` from the CRE SDK, which provides DON Time—a consensus-derived timestamp that all nodes agree on. See [Time in CRE](/cre/guides/workflow/time-in-workflows-go) for details. ## 5. Random number generation @@ -8303,7 +8917,7 @@ Go's built-in `rand` package generates different random sequences on each node, **The problem:** Each node generates different random values, breaking consensus. -**The solution:** Use `runtime.Rand()` from the CRE SDK, which provides consensus-safe random number generation. All nodes generate the same sequence of random values, enabling consensus. See [Random in CRE](/cre/concepts/random-in-cre) for details. +**The solution:** Use `runtime.Rand()` from the CRE SDK, which provides consensus-safe random number generation. All nodes generate the same sequence of random values, enabling consensus. See [Using Randomness in Workflows](/cre/guides/workflow/using-randomness) for details. ## 6. Working with LLMs @@ -8337,18 +8951,103 @@ Large Language Models (LLMs) generate different responses for the same prompt, e ## Related concepts -- **[Time in CRE](/cre/concepts/time-in-cre)**: Learn about DON Time and why `runtime.Now()` is required -- **[Random in CRE](/cre/concepts/random-in-cre)**: Understand consensus-safe random number generation +- **[Time in CRE](/cre/guides/workflow/time-in-workflows-go)**: Learn about DON Time and why `runtime.Now()` is required +- **[Using Randomness in Workflows](/cre/guides/workflow/using-randomness)**: Understand consensus-safe random number generation - **[Consensus Computing](/cre/concepts/consensus-computing)**: Deep dive into how nodes reach agreement --- +# Before You Build +Source: https://docs.chain.link/cre/getting-started/before-you-build-go +Last Updated: 2026-02-04 + +You've completed the Getting Started guide and built a workflow that fetches offchain data, reads from a smart contract, performs calculations, and writes results onchain. You're ready to build your own workflows. + +Before you do, take two minutes to understand how CRE differs from typical development. These tips will save you debugging time. + +## Working with time + +If your workflow uses timestamps (e.g., for API authentication or time-based queries), use `runtime.Now()` instead of `time.Now()`. This ensures all nodes in the DON use the same timestamp and can reach consensus. + + +<Aside type="tip" title="Learn more"> + See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details on DON time and best practices. +</Aside> + +## Working with randomness + +If your workflow needs random values (e.g., selecting a winner or generating nonces), use `runtime.Rand()` instead of Go's `rand` package. This ensures all nodes generate the same random sequence and can reach consensus. + + +<Aside type="tip" title="Learn more"> + See [Using Randomness in Workflows](/cre/guides/workflow/using-randomness) for usage examples and best practices. +</Aside> + + +<Aside type="note" title="Going deeper"> + Time and randomness are the most common cases. For a complete guide to non-determinism (map iteration, JSON serialization, channel selection, and more), see [Avoiding Non-Determinism in Workflows](/cre/concepts/non-determinism). +</Aside> + +## What's next? + +Here are resources to help you go from simulation to production. + +### Learn from examples + +- **[Run the Custom Data Feed Demo](/cre/templates/running-demo-workflow)** — A starter template you can run locally and customize +- **[Browse all Templates](/cre/templates)** — Building blocks for specific patterns (secrets, HTTP auth, streams) and starter templates +- **[AI-Powered Prediction Market](/cre/demos/prediction-market)** — Full end-to-end demo integrating CRE with Gemini AI and Firebase + +### Deploy to production + + +<Aside type="note" title="Deployment access required"> + Deploying requires Early Access approval. <a href="https://cre.chain.link/request-access" target="_blank" rel="noopener noreferrer">Request access here</a>. While you wait, continue building and simulating workflows. +</Aside> + +1. **[Link a Wallet Key](/cre/organization/linking-keys)** — Connect your wallet to your organization +2. **[Deploy Your Workflow](/cre/guides/operations/deploying-workflows)** — Push your workflow live +3. **[Monitor Your Workflow](/cre/guides/operations/monitoring-workflows)** — Watch it execute and debug issues + +### Explore different triggers + +You used a Cron trigger. Most production workflows react to events: + +- **[HTTP Trigger](/cre/guides/workflow/using-triggers/http-trigger/overview)** — Trigger via API calls +- **[EVM Log Trigger](/cre/guides/workflow/using-triggers/evm-log-trigger)** — React to onchain events + +### Add secrets + +Real workflows need API keys and sensitive data: + +- **[Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation)** — Local development +- **[Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed)** — Store secrets in the Vault DON for production +- **[Managing Secrets with 1Password](/cre/guides/workflow/secrets/managing-secrets-1password)** — Best practice: inject secrets at runtime + +### Build your own consumer contract + +- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)** — Create contracts that receive CRE data + +## Reference + +Dive deeper into concepts from this guide: + +| Topic | Resources | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Workflow structure** | [Core SDK](/cre/reference/sdk/core), [Triggers Overview](/cre/guides/workflow/using-triggers/overview) | +| **HTTP & offchain data** | [API Interactions](/cre/guides/workflow/using-http-client), [Consensus & Aggregation](/cre/reference/sdk/consensus) | +| **EVM interactions** | [EVM Client Overview](/cre/guides/workflow/using-evm-client/overview), [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read), [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview) | +| **Configuration** | [Project Configuration](/cre/reference/project-configuration), [Secrets Guide](/cre/guides/workflow/secrets) | +| **All capabilities** | [Capabilities Overview](/cre/capabilities) | + +--- + # Part 1: Project Setup & Simulation Source: https://docs.chain.link/cre/getting-started/part-1-project-setup-go -Last Updated: 2025-11-04 +Last Updated: 2026-01-14 <Aside type="note" title="SDK Language: Go"> - You're viewing the **Go** version of this guide. If you prefer TypeScript, use the language selector in the right + You're viewing the **Go** version of this guide. If you prefer TypeScript, use the language selector in the left sidebar to switch to the TypeScript version. </Aside> @@ -9110,7 +9809,7 @@ func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) ( } logger.Info("Successfully fetched offchain value", "result", offchainValue) - + // Get the first EVM configuration from the list. evmConfig := config.Evms[0] @@ -9146,7 +9845,7 @@ func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) ( return &MyResult{ FinalResult: finalResult, }, nil - + } func main() { @@ -9206,7 +9905,7 @@ You have successfully read a value from a smart contract and combined it with of # Part 4: Writing Onchain Source: https://docs.chain.link/cre/getting-started/part-4-writing-onchain-go -Last Updated: 2025-11-04 +Last Updated: 2025-12-09 In the previous parts, you successfully fetched offchain data and read from a smart contract. Now, you'll complete the "Onchain Calculator" by writing your computed result back to the blockchain. @@ -9229,20 +9928,20 @@ Here is the source code for the contract so you can see how it works: of how this works in a later guide. </Aside> -```solidity +```sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import { IReceiverTemplate } from "./keystone/IReceiverTemplate.sol"; +import {ReceiverTemplate} from "./ReceiverTemplate.sol"; /** * @title CalculatorConsumer (Testing Version) * @notice This contract receives reports from a CRE workflow and stores the results of a calculation onchain. - * @dev This version uses IReceiverTemplate without configuring any security checks, making it compatible - * with the mock Forwarder used during simulation. All permission fields remain at their default zero - * values (disabled). + * @dev Inherits from ReceiverTemplate which provides security checks. The forwarder address must be + * configured at deployment. Additional security checks (workflowId, workflowName, author) can be enabled via setter + * functions. */ -contract CalculatorConsumer is IReceiverTemplate { +contract CalculatorConsumer is ReceiverTemplate { // Struct to hold the data sent in a report from the workflow struct CalculatorResult { uint256 offchainValue; @@ -9259,16 +9958,22 @@ contract CalculatorConsumer is IReceiverTemplate { event ResultUpdated(uint256 indexed resultId, uint256 finalResult); /** - * @dev The constructor doesn't set any security checks. - * The IReceiverTemplate parent constructor will initialize all permission fields to zero (disabled). + * @notice Constructor requires the forwarder address for security + * @param _forwarderAddress The address of the Chainlink Forwarder contract (for testing: MockForwarder) + * @dev The forwarder address enables the first layer of security - only the forwarder can call onReport. + * Additional security checks can be configured after deployment using setter functions. */ - constructor() {} + constructor( + address _forwarderAddress + ) ReceiverTemplate(_forwarderAddress) {} /** * @notice Implements the core business logic for processing reports. - * @dev This is called automatically by IReceiverTemplate's onReport function after security checks. + * @dev This is called automatically by ReceiverTemplate's onReport function after security checks. */ - function _processReport(bytes calldata report) internal override { + function _processReport( + bytes calldata report + ) internal override { // Decode the report bytes into our CalculatorResult struct CalculatorResult memory calculatorResult = abi.decode(report, (CalculatorResult)); @@ -9284,7 +9989,9 @@ contract CalculatorConsumer is IReceiverTemplate { // This function is a "dry-run" utility. It allows an offchain system to check // if a prospective result is an outlier before submitting it for a real onchain update. // It is also used to guide the binding generator to create a method that accepts the CalculatorResult struct. - function isResultAnomalous(CalculatorResult memory _prospectiveResult) public view returns (bool) { + function isResultAnomalous( + CalculatorResult memory _prospectiveResult + ) public view returns (bool) { // A result is not considered anomalous if it's the first one. if (resultCount == 0) { return false; @@ -9297,7 +10004,7 @@ contract CalculatorConsumer is IReceiverTemplate { } ``` -The contract is already deployed for you on Sepolia at the following address: <a href="https://sepolia.etherscan.io/address/0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54#code" target="_blank" rel="noopener noreferrer">`0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54`</a>. You will use this address in your configuration file. +The contract is already deployed for you on Sepolia at the following address: <a href="https://sepolia.etherscan.io/address/0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb#code" target="_blank" rel="noopener noreferrer">`0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb`</a>. You will use this address in your configuration file. ## Step 2: Generate the consumer contract binding @@ -9313,7 +10020,7 @@ You need to create a binding for the consumer contract so your workflow can inte ```json - [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"received","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"InvalidAuthor","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"InvalidSender","type":"error"},{"inputs":[{"internalType":"bytes32","name":"received","type":"bytes32"},{"internalType":"bytes32","name":"expected","type":"bytes32"}],"name":"InvalidWorkflowId","type":"error"},{"inputs":[{"internalType":"bytes10","name":"received","type":"bytes10"},{"internalType":"bytes10","name":"expected","type":"bytes10"}],"name":"InvalidWorkflowName","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"resultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalResult","type":"uint256"}],"name":"ResultUpdated","type":"event"},{"inputs":[],"name":"expectedAuthor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expectedWorkflowId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expectedWorkflowName","outputs":[{"internalType":"bytes10","name":"","type":"bytes10"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forwarderAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"internalType":"struct CalculatorConsumer.CalculatorResult","name":"_prospectiveResult","type":"tuple"}],"name":"isResultAnomalous","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestResult","outputs":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"bytes","name":"report","type":"bytes"}],"name":"onReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resultCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"results","outputs":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_author","type":"address"}],"name":"setExpectedAuthor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"setExpectedWorkflowId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes10","name":"_name","type":"bytes10"}],"name":"setExpectedWorkflowName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_forwarder","type":"address"}],"name":"setForwarderAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}] + [{"inputs":[{"internalType":"address","name":"_forwarderAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"received","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"InvalidAuthor","type":"error"},{"inputs":[],"name":"InvalidForwarderAddress","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"InvalidSender","type":"error"},{"inputs":[{"internalType":"bytes32","name":"received","type":"bytes32"},{"internalType":"bytes32","name":"expected","type":"bytes32"}],"name":"InvalidWorkflowId","type":"error"},{"inputs":[{"internalType":"bytes10","name":"received","type":"bytes10"},{"internalType":"bytes10","name":"expected","type":"bytes10"}],"name":"InvalidWorkflowName","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"WorkflowNameRequiresAuthorValidation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousAuthor","type":"address"},{"indexed":true,"internalType":"address","name":"newAuthor","type":"address"}],"name":"ExpectedAuthorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"previousId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newId","type":"bytes32"}],"name":"ExpectedWorkflowIdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes10","name":"previousName","type":"bytes10"},{"indexed":true,"internalType":"bytes10","name":"newName","type":"bytes10"}],"name":"ExpectedWorkflowNameUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousForwarder","type":"address"},{"indexed":true,"internalType":"address","name":"newForwarder","type":"address"}],"name":"ForwarderAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"resultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalResult","type":"uint256"}],"name":"ResultUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"SecurityWarning","type":"event"},{"inputs":[],"name":"getExpectedAuthor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExpectedWorkflowId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExpectedWorkflowName","outputs":[{"internalType":"bytes10","name":"","type":"bytes10"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getForwarderAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"internalType":"struct CalculatorConsumer.CalculatorResult","name":"_prospectiveResult","type":"tuple"}],"name":"isResultAnomalous","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestResult","outputs":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"bytes","name":"report","type":"bytes"}],"name":"onReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resultCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"results","outputs":[{"internalType":"uint256","name":"offchainValue","type":"uint256"},{"internalType":"int256","name":"onchainValue","type":"int256"},{"internalType":"uint256","name":"finalResult","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_author","type":"address"}],"name":"setExpectedAuthor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"setExpectedWorkflowId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"setExpectedWorkflowName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_forwarder","type":"address"}],"name":"setForwarderAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}] ``` 3. **Generate the bindings**: Run the binding generator to create Go bindings for all ABI files in your project. From your project root (`onchain-calculator/`), run: @@ -9337,7 +10044,7 @@ Add the `CalculatorConsumer` contract address to your `config.staging.json`: "evms": [ { "storageAddress": "0xa17CF997C28FF154eDBae1422e6a50BeF23927F4", - "calculatorConsumerAddress": "0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54", + "calculatorConsumerAddress": "0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb", "chainName": "ethereum-testnet-sepolia", "gasLimit": 500000 } @@ -9451,7 +10158,7 @@ func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) ( } logger.Info("Successfully read onchain value", "result", onchainValue) - + // Step 3: Calculate the final result finalResultInt := new(big.Int).Add(onchainValue, offchainValue) @@ -9474,7 +10181,7 @@ func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) ( logger.Info("Workflow finished successfully!", "result", finalWorkflowResult) return finalWorkflowResult, nil - + } func fetchMathResult(config *Config, logger *slog.Logger, sendRequester *http.SendRequester) (*big.Int, error) { @@ -9522,417 +10229,1029 @@ func updateCalculatorResult(config *Config, runtime cre.Runtime, chainSelector u FinalResult: finalResult, }, gasConfig) - logger.Info("Waiting for write report response") - resp, err := writeReportPromise.Await() - if err != nil { - logger.Error("WriteReport await failed", "error", err) - return "", fmt.Errorf("failed to await write report: %w", err) - } - txHash := fmt.Sprintf("0x%x", resp.TxHash) - logger.Info("Write report transaction succeeded", "txHash", txHash) - logger.Info("View transaction at", "url", fmt.Sprintf("https://sepolia.etherscan.io/tx/%s", txHash)) - return txHash, nil -} + logger.Info("Waiting for write report response") + resp, err := writeReportPromise.Await() + if err != nil { + logger.Error("WriteReport await failed", "error", err) + return "", fmt.Errorf("failed to await write report: %w", err) + } + txHash := fmt.Sprintf("0x%x", resp.TxHash) + logger.Info("Write report transaction succeeded", "txHash", txHash) + logger.Info("View transaction at", "url", fmt.Sprintf("https://sepolia.etherscan.io/tx/%s", txHash)) + return txHash, nil +} + + +func main() { + wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow) +} +``` + +## Step 5: Sync your dependencies + +Because the `main.go` file has been updated to import new packages for the `CalculatorConsumer` binding, you must sync your dependencies. + +Run `go mod tidy` to automatically download the new dependencies and update your `go.mod` and `go.sum` files. + +```bash +go mod tidy +``` + +## Step 6: Run the simulation and review the output + + +<Aside type="note" title="Funding Your Account"> + This step submits an onchain transaction, which requires gas. Before running the simulation, verify that the account + associated with the private key from [Part + 1](/cre/getting-started/part-1-project-setup-go#set-up-your-private-key) is funded with sufficient Sepolia ETH. + An unfunded account will cause the transaction to fail, often with an error message like `gas required exceeds + allowance`. + + If you need more Sepolia ETH, go to <a href="https://faucets.chain.link" target="blank">faucets.chain.link</a> to get some Sepolia ETH. +</Aside> + +<Aside type="caution" title="Broadcasting Your Transaction"> + By default, `cre workflow simulate` performs a **dry run** for onchain write operations. It will simulate the transaction and return a successful response, but will **not** broadcast it to the network, resulting in an empty transaction hash (`0x`). + + To execute a real transaction, you must add the `--broadcast` flag to the command. +</Aside> + +Run the simulation from your project root directory (the `onchain-calculator/` folder). Because there is only one trigger, the simulator runs it automatically. + +```bash +cre workflow simulate my-calculator-workflow --target staging-settings --broadcast +``` + +Your workflow will now show the complete end-to-end execution, including the final log of the `MyResult` struct containing the transaction hash. + +```bash +Workflow compiled +2026-01-09T17:56:29Z [SIMULATION] Simulator Initialized + +2026-01-09T17:56:29Z [SIMULATION] Running trigger trigger=cron-trigger@1.0.0 +2026-01-09T17:56:29Z [USER LOG] msg="Successfully fetched offchain value" result=29 +2026-01-09T17:56:30Z [USER LOG] msg="Successfully read onchain value" result=22 +2026-01-09T17:56:30Z [USER LOG] msg="Final calculated result" result=51 +2026-01-09T17:56:30Z [USER LOG] msg="Updating calculator result" consumerAddress=0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb +2026-01-09T17:56:30Z [USER LOG] msg="Writing report to consumer contract" offchainValue=29 onchainValue=22 finalResult=51 +2026-01-09T17:56:30Z [USER LOG] msg="Waiting for write report response" +2026-01-09T17:56:36Z [USER LOG] msg="Write report transaction succeeded" txHash=0xa9f69bdf80329d16e175e19bb007fdbbd4d8f028aacb67d43a2832d6618d8a24 +2026-01-09T17:56:36Z [USER LOG] msg="View transaction at" url=https://sepolia.etherscan.io/tx/0xa9f69bdf80329d16e175e19bb007fdbbd4d8f028aacb67d43a2832d6618d8a24 +2026-01-09T17:56:36Z [USER LOG] msg="Workflow finished successfully!" result="&{OffchainValue:+29 OnchainValue:+22 FinalResult:+51 TxHash:0xa9f69bdf80329d16e175e19bb007fdbbd4d8f028aacb67d43a2832d6618d8a24}" + +Workflow Simulation Result: + { + "FinalResult": 51, + "OffchainValue": 29, + "OnchainValue": 22, + "TxHash": "0xa9f69bdf80329d16e175e19bb007fdbbd4d8f028aacb67d43a2832d6618d8a24" +} + +2026-01-09T17:56:36Z [SIMULATION] Execution finished signal received +2026-01-09T17:56:36Z [SIMULATION] Skipping WorkflowEngineV2 +``` + +- **`[USER LOG]`**: You can see all of your `logger.Info()` calls showing the complete workflow execution, including the offchain value (`result=29`), onchain value (`result=22`), final calculation (`result=51`), and the transaction hash. +- **`[SIMULATION]`**: These are system-level messages from the simulator showing its internal state. +- **`Workflow Simulation Result`**: This is the final return value of your workflow. The `MyResult` struct contains all the values (29 + 22 = 51) and the transaction hash confirming the write operation succeeded. + +## Step 7: Verify the result onchain + +### **1. Check the Transaction** + +In your terminal output, you'll see a clickable URL to view the transaction on Sepolia Etherscan: + +``` +[USER LOG] msg="View transaction at" url=https://sepolia.etherscan.io/tx/0x... +``` + +Click the URL (or copy and paste it into your browser) to see the full details of the transaction your workflow submitted. + +**What are you seeing on a blockchain explorer?** + +You'll notice the transaction's `to` address is not the `CalculatorConsumer` contract you intended to call. Instead, it's to a **Forwarder** contract. Your workflow sends a secure report to the Forwarder, which then verifies the request and makes the final call to the `CalculatorConsumer` on your workflow's behalf. To learn more, see the [Onchain Write guide](/cre/guides/workflow/using-evm-client/onchain-write/overview). + +### **2. Check the contract state** + +While your wallet interacted with the Forwarder, the `CalculatorConsumer` contract's state was still updated. You can verify this change directly on Etherscan: + +- Navigate to the `CalculatorConsumer` contract address: <a href="https://sepolia.etherscan.io/address/0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb#readContract" target="_blank" rel="noopener noreferrer">`0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb`</a>. +- Expand the `latestResult` function and click **Query**. The values should match the `finalResult`, `offchainValue`, and `onchainValue` from your workflow logs. + +This completes the end-to-end loop: triggering a workflow, fetching data, reading onchain state, and verifiably writing the result back to a public blockchain. + +To learn more about implementing consumer contracts and the secure write process, see these guides: + +- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Learn how to create your own secure consumer contracts with proper validation. +- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write/overview-go)**: Dive deeper into the write patterns. + +## Next steps + +You've now mastered the complete CRE development workflow! + +- **[Before You Build](/cre/getting-started/before-you-build-go)**: Don't skip this — critical tips before building your own workflows. + +--- + +# Using Secrets in Simulation +Source: https://docs.chain.link/cre/guides/workflow/secrets/using-secrets-simulation-go +Last Updated: 2025-11-04 + +This guide explains how to use secrets during **local development and simulation**. When you're simulating a workflow on your local machine with `cre workflow simulate`, secrets are provided via environment variables or a `.env` file. + + +<Aside type="note" title="For deployed workflows"> + If you're deploying workflows, you'll need to store secrets in the **Vault DON** instead. See [Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed) for details. +</Aside> + +At a high level, the process follows a simple, three-step pattern: + +1. **Declare**: You declare the logical names of your secrets in a `secrets.yaml` file. +2. **Provide**: You provide the actual secret values in a `.env` file or as environment variables. +3. **Use**: You access the secrets in your workflow code using the SDK's secret management API. + +This separation of concerns ensures that your workflow code is portable and your secrets are never hard-coded. + +<Aside type="note" title="Best Practices for Storing Secrets"> + While this guide shows secrets being provided via a plaintext `.env` file and environment variables, the recommended + best practice for security is to use a dedicated secrets manager. See our guide on [Managing Secrets with 1Password + CLI](/cre/guides/workflow/secrets/managing-secrets-1password) to learn how to inject secrets securely at runtime. +</Aside> + +## Step-by-step guide + +### Step 1: Declare your secrets (`secrets.yaml`) + +The first step is to create a `secrets.yaml` file in the root of your project. This file acts as a manifest, defining the "logical names" or "IDs" for the secrets your workflow will use. + +In this file, you map a logical name (which you'll use in your workflow code) to one environment variable name that will hold the actual secret value. + +**Example `secrets.yaml`:** + +```yaml +# in project-root/secrets.yaml +secretsNames: + # This is the logical ID you will use in your workflow code + SECRET_ADDRESS: + # This is the environment variable the CLI will look for + - SECRET_ADDRESS_ALL +``` + +### Step 2: Provide the secret values + +Next, you need to provide the actual values for the secrets. The `cre` CLI can read these values in two primary ways. + +#### Method 1: Using shell environment variables (Recommended) + +You can provide secrets as standard environment variables directly in your shell. + +For example, in your terminal: + +```bash +export SECRET_ADDRESS_ALL="0x1234567890abcdef1234567890abcdef12345678" +``` + +When you run the `cre workflow simulate` command in the same terminal session, the CLI will have access to this variable. + +#### Method 2: Using a `.env` file + +Create a `.env` file in your project's root directory. The `cre` CLI automatically finds this file and loads the variables defined within it into the environment for your simulation. The variable names here must match those you declared in `secrets.yaml`. + +**Example `.env` file:** + +```bash +# in project-root/.env + +# The variable name matches the one in secrets.yaml +SECRET_ADDRESS_ALL="0x1234567890abcdef1234567890abcdef12345678" +``` + +<Aside type="caution" title="Never Commit Your Secrets"> + The project's `.gitignore` file is already configured to ignore `.env` files. **Never** commit this file to version + control. +</Aside> + +### Step 3: Use the secret in your workflow + +Now you can access the secret in your workflow code. The SDK provides a method to retrieve secrets using the logical ID you defined in `secrets.yaml`. + +The following code shows a complete, runnable workflow that triggers on a schedule, fetches a secret, and logs its value. + +**Example workflow:** + +Code snippet for Fetching Single Secret (Go): + +```go +//go:build wasip1 + +package main + +import ( + "log/slog" + + protos "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" + "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" + "github.com/smartcontractkit/cre-sdk-go/cre" + "github.com/smartcontractkit/cre-sdk-go/cre/wasm" +) + +// Config can be an empty struct if you don't need any parameters from config.json. +type Config struct{} + +// MyResult can be an empty struct if your workflow doesn't need to return a result. +type MyResult struct{} + +// Define the logical name of the secret as a constant for clarity. +const SecretName = "SECRET_ADDRESS" + +// onCronTrigger is the callback function that gets executed when the cron trigger fires. +// This is where you use the secret. +func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) { + logger := runtime.Logger() + // Build the request with the secret's logical ID. + secretReq := &protos.SecretRequest{ + Id: SecretName, + } + + // Call runtime.GetSecret and await the promise. + secret, err := runtime.GetSecret(secretReq).Await() + if err != nil { + logger.Error("Failed to get secret", "name", SecretName, "err", err) + return nil, err + } + + // Use the secret's value. + secretAddress := secret.Value + logger.Info("Successfully fetched a secret!", "address", secretAddress) + + // ... now you can use the secretAddress in your logic ... + return &MyResult{}, nil +} + +// InitWorkflow is the required entry point for a CRE workflow. +func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { + return cre.Workflow[*Config]{ + cre.Handler( + cron.Trigger(&cron.Config{Schedule: "0 */10 * * * *"}), + onCronTrigger, + ), + }, nil +} + +// main is the entry point for the WASM binary. +func main() { + wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow) +} +``` + +### Step 4: Configure secrets path in `workflow.yaml` + +Before simulating, you need to tell the CLI where to find your secrets file. This is configured in your `workflow.yaml` file under `workflow-artifacts.secrets-path`. + +Open your `workflow.yaml` file and set the `secrets-path`: + +```yaml +local-simulation: + user-workflow: + workflow-name: "my-workflow" + workflow-artifacts: + workflow-path: "./main.go" + config-path: "./config.json" + secrets-path: "../secrets.yaml" # Path to your secrets file +``` + +Notice the path `../secrets.yaml`. Because the workflow artifacts are relative to the workflow directory, you need to point to the `secrets.yaml` file located one level up in the project root. + +### Step 5: Run the simulation + +Now you can simulate your workflow: + +```bash +cre workflow simulate my-workflow --target staging-settings +``` + +The CLI will automatically read the `secrets-path` from your `workflow.yaml` and load the secrets from your `.env` file or environment variables you provided in your terminal session. + +## Fetching multiple secrets + +You can fetch multiple secrets by calling the secret retrieval method multiple times within your workflow. + + +<Aside type="caution" title="Fetch secrets sequentially"> + The WASM host for the CRE runtime does not support parallel `runtime.GetSecret()` requests. Always fetch secrets **sequentially**: call `GetSecret()`, await the promise with `.Await()`, then call `GetSecret()` again for the next secret. Do not attempt to fetch multiple secrets in parallel. +</Aside> + +The following example builds on the previous one. First, update your `secrets.yaml` to declare two secrets: + +```yaml +secretsNames: + SECRET_ADDRESS: + - SECRET_ADDRESS_ALL + API_KEY: + - API_KEY_ALL +``` + +Then provide the values in your `.env` file or export them as environment variables in your terminal session: + +```bash +export SECRET_ADDRESS_ALL="0x1234567890abcdef1234567890abcdef12345678" +export API_KEY_ALL="your-api-key-here" +``` + +Now you can fetch both secrets in your workflow code: + +Code snippet for Fetching Multiple Secrets (Go): + +```go +//go:build wasip1 + +package main + +import ( + "log/slog" + + protos "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" + "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" + "github.com/smartcontractkit/cre-sdk-go/cre" + "github.com/smartcontractkit/cre-sdk-go/cre/wasm" +) + +// Config can be an empty struct if you don't need any parameters from config.json. +type Config struct{} + +// MyResult can be an empty struct if your workflow doesn't need to return a result. +type MyResult struct{} + +const ( + SecretAddressName = "SECRET_ADDRESS" + ApiKeyName = "API_KEY" +) + +func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) { + logger := runtime.Logger() + + // Important: Fetch secrets sequentially, not in parallel. + // The WASM host for CRE runtime does not support parallel runtime.GetSecret() requests. + // Always call GetSecret(), then Await() before making the next GetSecret() call. + + // 1. Fetch the first secret + addressPromise := runtime.GetSecret(&protos.SecretRequest{Id: SecretAddressName}) + secretAddress, err := addressPromise.Await() + if err != nil { + logger.Error("Failed to get SECRET_ADDRESS", "err", err) + return nil, err + } + + // 2. Fetch the second secret (only after the first is complete) + apiKeyPromise := runtime.GetSecret(&protos.SecretRequest{Id: ApiKeyName}) + apiKey, err := apiKeyPromise.Await() + if err != nil { + logger.Error("Failed to get API_KEY", "err", err) + return nil, err + } + + // 3. Use your secrets + logger.Info("Successfully fetched secrets!", + "address", secretAddress.Value, + "apiKey", apiKey.Value, + ) + + return &MyResult{}, nil +} + +// InitWorkflow is the required entry point for a CRE workflow. +func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { + return cre.Workflow[*Config]{ + cre.Handler( + cron.Trigger(&cron.Config{Schedule: "0 */10 * * * *"}), + onCronTrigger, + ), + }, nil +} + +// main is the entry point for the WASM binary. +func main() { + wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow) +} +``` + +--- + +# Using Time in Workflows +Source: https://docs.chain.link/cre/guides/workflow/time-in-workflows-go +Last Updated: 2026-02-03 + +<Aside type="note" title="TL;DR"> + CRE provides **DON Time**: a consensus-derived timestamp so different nodes see the *same time*. Use the SDK's runtime + call, `runtime.Now()`, whenever your workflow logic depends on time. Do **not** read local system clocks or other + ad-hoc time sources in DON Mode — they introduce non-determinism. +</Aside> + +## The problem: Why time needs consensus + +Workflows often rely on time for decisions (market-hours checks), scheduling (retries/backoffs), and observability (log timestamps). In a decentralized network, nodes do not share an identical clock—clock drift, resource contention, and OS scheduling can skew each node's local time. If each node consults its own clock: + +- Different nodes may take **different branches** of your logic (e.g., one thinks the market is open, another does not). +- Logs across nodes become **hard to correlate**. +- Data fetched using time (e.g., "fetch price at timestamp N") can be **inconsistent**. + +**DON Time** removes these divergences by making time **deterministic in the DON**. + +## The solution: DON time + +**DON Time** is a timestamp computed by an <a href="https://docs.chain.link/architecture-overview/off-chain-reporting" target="_blank" rel="noopener noreferrer">OCR (Off-Chain Reporting)</a> plugin and agreed upon by the nodes participating in CRE. You access it through the SDK's runtime call, `runtime.Now()`, not via an OS/System clock. The `runtime.Now()` function returns a standard Go `time.Time` object. + +**Key properties:** + +- **Deterministic across nodes**: nodes see the same timestamp. +- **Sequenced per workflow**: time responses are associated with a **time-call sequence number** inside each workflow execution (1st call, 2nd call, …). Node execution timing might be slightly off, but a given call will resolve to the **same DON timestamp**. +- **Low latency**: the plugin runs continuously with **delta round = 0**, and each node **transmits** results back to outstanding requests at the end of every round. +- **Tamper-resistant**: workflows don't expose host machine time, reducing timing-attack surface. + +<Aside type="note" title="A Note on Accuracy"> + DON Time is computed as the **median of nodes' local observations** in each round. It is designed for **consistency** + across the DON rather than exact alignment to an external UTC source. Think of it as a highly reliable clock for your + workflows. Do not treat it as a high-precision clock. +</Aside> + +## How it works: A high-level view + +1. Your workflow calls **`runtime.Now()`**. +2. **The Chainlink network takes this request**: The Workflow Engine's **TimeProvider** assigns that call a **sequence number** and enqueues it in the **DON Time Store**. +3. **All the nodes agree on a single time (the DON Time)**: The **OCR Time Plugin** on each node reaches consensus on a new DON timestamp (the median of observed times). +4. Each node **returns** the newest DON timestamp to every pending request and updates its **last observed DON time** cache. +5. The result is written back into the WebAssembly execution, and your workflow continues. + +Because requests are sequenced, *Call 1* for a workflow instance will always return the same DON timestamp on every node. If Node A hits *Call 2* before Node B, A will block until the DON timestamp for *Call 2* is produced; when B reaches *Call 2*, it immediately reuses that value. + +## Execution modes: DON mode vs. Node mode + +### DON mode (default for workflows) + +- Time is **consensus-based** and **deterministic**. +- Use for **any** logic where different outcomes across nodes would be a bug. Examples: + - Market-hours gates + - Time-windowed queries ("last 15 minutes") + - Retry/backoff logic that must align across nodes + - Timestamps used for cross-node correlation (logging, audit trails) + +### Node mode (advanced / special cases) + +- Workflow authors handle consensus themselves. +- `runtime.Now()` in Node Mode is a non-blocking call that returns the **last generated DON timestamp** from the local node's cache. This is the same mechanism used by standard Go `time.Now()` calls within the Wasm environment. +- Useful in situation where you already expect non-determinism (e.g., inherently variable HTTP responses). + +<Aside type="caution" title="Use DON Mode"> + Unless you have a specific reason and understand the trade-offs, **always use DON Mode** for time-dependent logic. +</Aside> + +## Best practices: Avoiding non-determinism in DON mode +When running in DON Mode, you get determinism **if and only if** you base time-dependent logic on DON Time. -func main() { - wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow) -} -``` +**Avoid** these patterns: -## Step 5: Sync your dependencies +- **Reading host/system time** (`time.Now()`, etc.). Always use `runtime.Now()` from the CRE SDK. +- **Mixing time sources** in the same control path. +- **Per-node "sleeps" based on local time** that gate deterministic decisions. -Because the `main.go` file has been updated to import new packages for the `CalculatorConsumer` binding, you must sync your dependencies. +**Deterministic patterns:** -Run `go mod tidy` to automatically download the new dependencies and update your `go.mod` and `go.sum` files. +- ✅ Gate behavior with: + ```go + now := runtime.Now() + if market.IsOpenAt(now): + // proceed + ``` +- ✅ Compute windows from DON Time: + ```go + now := runtime.Now() + windowStart := now.Add(-15 * time.Minute) + fetchData(windowStart, now) + ``` -```bash -go mod tidy -``` +## FAQ -## Step 6: Run the simulation and review the output +**Is DON Time "real UTC time"?** +It's the **median of node observations** per round. It closely tracks real time but prioritizes **consistency** over absolute accuracy. -<Aside type="note" title="Funding Your Account"> - This step submits an onchain transaction, which requires gas. Before running the simulation, verify that the account - associated with the private key from [Part - 1](/cre/getting-started/part-1-project-setup#step-3-configure-the-environment) is funded with sufficient Sepolia ETH. - An unfunded account will cause the transaction to fail, often with an error message like `gas required exceeds - allowance`. +**What is the resolution?** - If you need more Sepolia ETH, go to <a href="https://faucets.chain.link" target="blank">faucets.chain.link</a> to get some Sepolia ETH. -</Aside> +New DON timestamps are produced continuously (multiple per second). Treat it as coarse-grained real time suitable for gating and logging, not sub-millisecond measurement. -<Aside type="caution" title="Broadcasting Your Transaction"> - By default, `cre workflow simulate` performs a **dry run** for onchain write operations. It will simulate the transaction and return a successful response, but will **not** broadcast it to the network, resulting in an empty transaction hash (`0x`). +--- - To execute a real transaction, you must add the `--broadcast` flag to the command. +# Making Confidential Requests +Source: https://docs.chain.link/cre/guides/workflow/using-confidential-http-client/making-requests-go +Last Updated: 2026-02-10 + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. </Aside> -Run the simulation from your project root directory (the `onchain-calculator/` folder). Because there is only one trigger, the simulator runs it automatically. +The `confidentialhttp.Client` is the SDK's interface for the underlying [Confidential HTTP Capability](/cre/capabilities/confidential-http). It allows your workflow to make privacy-preserving API calls where secrets are injected inside a secure enclave and responses can be optionally encrypted. -```bash -cre workflow simulate my-calculator-workflow --target staging-settings --broadcast -``` +Unlike the regular [`http.Client`](/cre/reference/sdk/http-client), the Confidential HTTP client: -Your workflow will now show the complete end-to-end execution, including the final log of the `MyResult` struct containing the transaction hash. +- Executes the request in a secure **enclave** (not on each node individually) +- Injects secrets from the **Vault DON** using template syntax +- Optionally **encrypts the response** before returning it to your workflow -```bash -Workflow compiled -2025-11-03T22:48:41Z [SIMULATION] Simulator Initialized - -2025-11-03T22:48:41Z [SIMULATION] Running trigger trigger=cron-trigger@1.0.0 -2025-11-03T22:48:41Z [USER LOG] msg="Successfully fetched offchain value" result=56 -2025-11-03T22:48:41Z [USER LOG] msg="Successfully read onchain value" result=22 -2025-11-03T22:48:41Z [USER LOG] msg="Final calculated result" result=78 -2025-11-03T22:48:41Z [USER LOG] msg="Updating calculator result" consumerAddress=0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54 -2025-11-03T22:48:41Z [USER LOG] msg="Writing report to consumer contract" offchainValue=56 onchainValue=22 finalResult=78 -2025-11-03T22:48:41Z [USER LOG] msg="Waiting for write report response" -2025-11-03T22:48:48Z [USER LOG] msg="Write report transaction succeeded" txHash=0x86a26f848c83f37b8eace8123ec275a0af9d21b23b1fbba9cc7664b7e474314f -2025-11-03T22:48:48Z [USER LOG] msg="View transaction at" url=https://sepolia.etherscan.io/tx/0x86a26f848c83f37b8eace8123ec275a0af9d21b23b1fbba9cc7664b7e474314f -2025-11-03T22:48:48Z [USER LOG] msg="Workflow finished successfully!" result="&{OffchainValue:+56 OnchainValue:+22 FinalResult:+78 TxHash:0x86a26f848c83f37b8eace8123ec275a0af9d21b23b1fbba9cc7664b7e474314f}" +## Prerequisites -Workflow Simulation Result: - { - "FinalResult": 78, - "OffchainValue": 56, - "OnchainValue": 22, - "TxHash": "0x86a26f848c83f37b8eace8123ec275a0af9d21b23b1fbba9cc7664b7e474314f" -} +This guide assumes you have: -2025-11-03T22:48:48Z [SIMULATION] Execution finished signal received -2025-11-03T22:48:48Z [SIMULATION] Skipping WorkflowEngineV2 -``` +- A basic understanding of CRE. If you are new, complete the [Getting Started tutorial](/cre/getting-started/overview) first. +- Familiarity with [secrets management](/cre/guides/workflow/secrets) in CRE. -- **`[USER LOG]`**: You can see all of your `logger.Info()` calls showing the complete workflow execution, including the offchain value (`result=56`), onchain value (`result=22`), final calculation (`result=78`), and the transaction hash. -- **`[SIMULATION]`**: These are system-level messages from the simulator showing its internal state. -- **`Workflow Simulation Result`**: This is the final return value of your workflow. The `MyResult` struct contains all the values (56 + 22 = 78) and the transaction hash confirming the write operation succeeded. +## Step-by-step example -## Step 7: Verify the result onchain +This example shows a workflow that makes a confidential POST request to an API, injecting an API secret into both the request body and headers using template syntax. -### **1. Check the Transaction** +### Step 1: Configure your workflow -In your terminal output, you'll see a clickable URL to view the transaction on Sepolia Etherscan: +Add the API URL to your `config.json` file. -``` -[USER LOG] msg="View transaction at" url=https://sepolia.etherscan.io/tx/0x... +```json +{ + "schedule": "0 */5 * * * *", + "url": "https://api.example.com/data" +} ``` -Click the URL (or copy and paste it into your browser) to see the full details of the transaction your workflow submitted. +### Step 2: Set up secrets for simulation -**What are you seeing on a blockchain explorer?** +Confidential HTTP uses the `secrets.yaml` file. If you've already set up secrets for your project, you can reuse the same file. For a full walkthrough, see [Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation). -You'll notice the transaction's `to` address is not the `CalculatorConsumer` contract you intended to call. Instead, it's to a **Forwarder** contract. Your workflow sends a secure report to the Forwarder, which then verifies the request and makes the final call to the `CalculatorConsumer` on your workflow's behalf. To learn more, see the [Onchain Write guide](/cre/guides/workflow/using-evm-client/onchain-write). +Add the secrets your confidential request needs to your `secrets.yaml`: -### **2. Check the contract state** +```yaml +# secrets.yaml +secretsNames: + myApiKey: + - MY_API_KEY_ALL +``` -While your wallet interacted with the Forwarder, the `CalculatorConsumer` contract's state was still updated. You can verify this change directly on Etherscan: +Provide the actual value via an environment variable or `.env` file: -- Navigate to the `CalculatorConsumer` contract address: <a href="https://sepolia.etherscan.io/address/0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54#readContract" target="_blank" rel="noopener noreferrer">`0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54`</a>. -- Expand the `latestResult` function and click **Query**. The values should match the `finalResult`, `offchainValue`, and `onchainValue` from your workflow logs. +```bash +export MY_API_KEY_ALL="your-secret-api-key" +``` -This completes the end-to-end loop: triggering a workflow, fetching data, reading onchain state, and verifiably writing the result back to a public blockchain. +<Aside type="note" title="Verify secrets-path in workflow.yaml"> + Make sure the `secrets-path` field in your `workflow.yaml` points to your `secrets.yaml` file (for example, + `"../secrets.yaml"` if it is at the project root). New projects created with the CLI may have this field empty by + default. +</Aside> -To learn more about implementing consumer contracts and the secure write process, see these guides: +### Step 3: Build the confidential request -- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Learn how to create your own secure consumer contracts with proper validation. -- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write)**: Dive deeper into the write patterns. +The key difference from regular HTTP is how you construct the request. You provide: -## Next steps +- An `HTTPRequest` with template placeholders (`{{.secretName}}`) in the body and/or headers +- A list of `VaultDonSecrets` identifying which secrets to fetch from the Vault DON +- An optional `EncryptOutput` flag to encrypt the response -You've now mastered the complete CRE development workflow! +```go +import ( + "github.com/smartcontractkit/cre-sdk-go/capabilities/networking/confidentialhttp" + "github.com/smartcontractkit/cre-sdk-go/cre" +) -- **[Conclusion & Next Steps](/cre/getting-started/conclusion)**: Review what you've learned and find resources for advanced topics. +type Config struct { + Schedule string `json:"schedule"` + URL string `json:"url"` +} ---- +type Result struct { + TransactionID string `json:"transactionId" consensus:"identical"` + Status string `json:"status" consensus:"identical"` +} +``` -# Using Secrets in Simulation -Source: https://docs.chain.link/cre/guides/workflow/secrets/using-secrets-simulation-go -Last Updated: 2025-11-04 +### Step 4: Implement the request logic -This guide explains how to use secrets during **local development and simulation**. When you're simulating a workflow on your local machine with `cre workflow simulate`, secrets are provided via environment variables or a `.env` file. +Use `cre.RunInNodeMode` to make the confidential request. The `confidentialhttp.Client` requires a `NodeRuntime`: +```go +func makeConfidentialRequest(config Config, nodeRuntime cre.NodeRuntime) (Result, error) { + // 1. Define the request body with secret template placeholders + payload := `{"auth": "{{.myApiKey}}", "action": "getTransaction", "id": "tx-123"}` -<Aside type="note" title="For deployed workflows"> - If you're deploying workflows, you'll need to store secrets in the **Vault DON** instead. See [Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed) for details. -</Aside> + // 2. Define headers with secret template placeholders + headers := map[string]*confidentialhttp.HeaderValues{ + "Content-Type": { + Values: []string{"application/json"}, + }, + "Authorization": { + Values: []string{"Basic {{.myApiKey}}"}, + }, + } -At a high level, the process follows a simple, three-step pattern: + // 3. Create the client and send the request + client := confidentialhttp.Client{} + resp, err := client.SendRequest(nodeRuntime, &confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: payload}, + MultiHeaders: headers, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "myApiKey"}, + }, + EncryptOutput: false, + }).Await() + if err != nil { + return Result{}, fmt.Errorf("confidential HTTP request failed: %w", err) + } -1. **Declare**: You declare the logical names of your secrets in a `secrets.yaml` file. -2. **Provide**: You provide the actual secret values in a `.env` file or as environment variables. -3. **Use**: You access the secrets in your workflow code using the SDK's secret management API. + // 4. Parse the response + var result Result + if err := json.Unmarshal(resp.Body, &result); err != nil { + return Result{}, fmt.Errorf("failed to parse response: %w", err) + } -This separation of concerns ensures that your workflow code is portable and your secrets are never hard-coded. + return result, nil +} +``` -<Aside type="note" title="Best Practices for Storing Secrets"> - While this guide shows secrets being provided via a plaintext `.env` file and environment variables, the recommended - best practice for security is to use a dedicated secrets manager. See our guide on [Managing Secrets with 1Password - CLI](/cre/guides/workflow/secrets/managing-secrets-1password) to learn how to inject secrets securely at runtime. -</Aside> +### Step 5: Wire it into your workflow -## Step-by-step guide +Call the request function from your trigger handler using `cre.RunInNodeMode`: -### Step 1: Declare your secrets (`secrets.yaml`) +```go +func onCronTrigger(config *Config, runtime cre.Runtime, outputs *cron.Payload) (string, error) { + result, err := cre.RunInNodeMode(*config, runtime, + makeConfidentialRequest, + cre.ConsensusIdenticalAggregation[Result](), + ).Await() + if err != nil { + return "", fmt.Errorf("failed to get result: %w", err) + } -The first step is to create a `secrets.yaml` file in the root of your project. This file acts as a manifest, defining the "logical names" or "IDs" for the secrets your workflow will use. + runtime.Logger().Info("Transaction result", "id", result.TransactionID, "status", result.Status) + return result.TransactionID, nil +} +``` -In this file, you map a logical name (which you'll use in your workflow code) to one environment variable name that will hold the actual secret value. +### Step 6: Simulate -**Example `secrets.yaml`:** +Run the simulation: -```yaml -# in project-root/secrets.yaml -secretsNames: - # This is the logical ID you will use in your workflow code - SECRET_ADDRESS: - # This is the environment variable the CLI will look for - - SECRET_ADDRESS_ALL +```bash +cre workflow simulate ``` -### Step 2: Provide the secret values +## Template syntax for secrets -Next, you need to provide the actual values for the secrets. The `cre` CLI can read these values in two primary ways. +Secrets are injected into request bodies and headers using Go template syntax: `{{.secretName}}`. The placeholder name must match the `Key` in your `VaultDonSecrets` list. -#### Method 1: Using shell environment variables (Recommended) +**In the request body:** -You can provide secrets as standard environment variables directly in your shell. +```json +{ "auth": "{{.myApiKey}}", "data": "public-data" } +``` -For example, in your terminal: +**In headers:** -```bash -export SECRET_ADDRESS_ALL="0x1234567890abcdef1234567890abcdef12345678" +```go +headers := map[string]*confidentialhttp.HeaderValues{ + "Authorization": { + Values: []string{"Basic {{.myCredential}}"}, + }, +} ``` -When you run the `cre workflow simulate` command in the same terminal session, the CLI will have access to this variable. +The template placeholders are resolved inside the enclave. The actual secret values never appear in your workflow code or in node memory. -#### Method 2: Using a `.env` file +## Response encryption -Create a `.env` file in your project's root directory. The `cre` CLI automatically finds this file and loads the variables defined within it into the environment for your simulation. The variable names here must match those you declared in `secrets.yaml`. +By default, the API response is returned unencrypted (`EncryptOutput: false`). To encrypt the response body before it leaves the enclave, set `EncryptOutput: true` and provide an AES-256 encryption key as a Vault DON secret. -**Example `.env` file:** +### Setting up response encryption -```bash -# in project-root/.env +1. **Store an AES-256 key** as a Vault DON secret with the identifier `san_marino_aes_gcm_encryption_key`: -# The variable name matches the one in secrets.yaml -SECRET_ADDRESS_ALL="0x1234567890abcdef1234567890abcdef12345678" -``` + ```yaml + # secrets.yaml + secretsNames: + san_marino_aes_gcm_encryption_key: + - AES_KEY_ALL + ``` -<Aside type="caution" title="Never Commit Your Secrets"> - The project's `.gitignore` file is already configured to ignore `.env` files. **Never** commit this file to version - control. -</Aside> + The key must be a 256-bit (32 bytes) hex-encoded string: -### Step 3: Use the secret in your workflow + ```bash + export AES_KEY_ALL="your-256-bit-hex-encoded-key" + ``` -Now you can access the secret in your workflow code. The SDK provides a method to retrieve secrets using the logical ID you defined in `secrets.yaml`. +2. **Include the key in your `VaultDonSecrets`** and set `EncryptOutput: true`: -The following code shows a complete, runnable workflow that triggers on a schedule, fetches a secret, and logs its value. + ```go + resp, err := client.SendRequest(nodeRuntime, &confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: payload}, + MultiHeaders: headers, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "myApiKey"}, + {Key: "san_marino_aes_gcm_encryption_key"}, + }, + EncryptOutput: true, + }).Await() + ``` -**Example workflow:** +3. **Decrypt the response** in your own secure backend using AES-GCM. The encrypted response body is structured as `nonce || ciphertext || tag`: -Code snippet for Fetching Single Secret (Go): + ```go + import ( + "crypto/aes" + "crypto/cipher" + "encoding/hex" + ) + + func AESGCMDecrypt(blob []byte, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonceSize := gcm.NonceSize() + if len(blob) < nonceSize { + return nil, fmt.Errorf("ciphertext too short") + } + + nonce, ciphertext := blob[:nonceSize], blob[nonceSize:] + return gcm.Open(nil, nonce, ciphertext, nil) + } + ``` -```go -//go:build wasip1 + <Aside type="tip" title="Do not decrypt inside the workflow"> + The purpose of response encryption is to keep the response confidential even within the decentralized network. Decrypt the response in your own secure backend service, not inside the workflow itself. + </Aside> + +## Complete example + +Here's the full workflow code for a confidential HTTP request with response encryption: + +```go package main import ( + "crypto/aes" + "crypto/cipher" + "encoding/hex" + "encoding/json" + "fmt" "log/slog" + "os" - protos "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" + "github.com/smartcontractkit/cre-sdk-go/capabilities/networking/confidentialhttp" "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" "github.com/smartcontractkit/cre-sdk-go/cre" - "github.com/smartcontractkit/cre-sdk-go/cre/wasm" ) -// Config can be an empty struct if you don't need any parameters from config.json. -type Config struct{} - -// MyResult can be an empty struct if your workflow doesn't need to return a result. -type MyResult struct{} - -// Define the logical name of the secret as a constant for clarity. -const SecretName = "SECRET_ADDRESS" - -// onCronTrigger is the callback function that gets executed when the cron trigger fires. -// This is where you use the secret. -func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) { - logger := runtime.Logger() - // Build the request with the secret's logical ID. - secretReq := &protos.SecretRequest{ - Id: SecretName, - } - - // Call runtime.GetSecret and await the promise. - secret, err := runtime.GetSecret(secretReq).Await() - if err != nil { - logger.Error("Failed to get secret", "name", SecretName, "err", err) - return nil, err - } - - // Use the secret's value. - secretAddress := secret.Value - logger.Info("Successfully fetched a secret!", "address", secretAddress) +type Config struct { + Schedule string `json:"schedule"` + URL string `json:"url"` +} - // ... now you can use the secretAddress in your logic ... - return &MyResult{}, nil +type Result struct { + TransactionID string `json:"transactionId" consensus:"identical"` + Status string `json:"status" consensus:"identical"` } -// InitWorkflow is the required entry point for a CRE workflow. func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { - return cre.Workflow[*Config]{ + cronTriggerCfg := &cron.Config{ + Schedule: config.Schedule, + } + + workflow := cre.Workflow[*Config]{ cre.Handler( - cron.Trigger(&cron.Config{Schedule: "0 */10 * * * *"}), + cron.Trigger(cronTriggerCfg), onCronTrigger, ), - }, nil + } + + return workflow, nil } -// main is the entry point for the WASM binary. -func main() { - wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow) +func onCronTrigger(config *Config, runtime cre.Runtime, outputs *cron.Payload) (string, error) { + result, err := cre.RunInNodeMode(*config, runtime, + makeConfidentialRequest, + cre.ConsensusIdenticalAggregation[Result](), + ).Await() + if err != nil { + return "", fmt.Errorf("failed to get result: %w", err) + } + + runtime.Logger().Info("Transaction result", "id", result.TransactionID, "status", result.Status) + return result.TransactionID, nil } -``` -### Step 4: Configure secrets path in `workflow.yaml` +func makeConfidentialRequest(config Config, nodeRuntime cre.NodeRuntime) (Result, error) { + payload := `{"auth": "{{.myApiKey}}", "action": "getTransaction", "id": "tx-123"}` -Before simulating, you need to tell the CLI where to find your secrets file. This is configured in your `workflow.yaml` file under `workflow-artifacts.secrets-path`. + headers := map[string]*confidentialhttp.HeaderValues{ + "Content-Type": { + Values: []string{"application/json"}, + }, + "Authorization": { + Values: []string{"Basic {{.myApiKey}}"}, + }, + } -Open your `workflow.yaml` file and set the `secrets-path`: + client := confidentialhttp.Client{} + resp, err := client.SendRequest(nodeRuntime, &confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: payload}, + MultiHeaders: headers, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "myApiKey"}, + {Key: "san_marino_aes_gcm_encryption_key"}, + }, + EncryptOutput: true, + }).Await() + if err != nil { + return Result{}, fmt.Errorf("confidential HTTP request failed: %w", err) + } -```yaml -local-simulation: - user-workflow: - workflow-name: "my-workflow" - workflow-artifacts: - workflow-path: "./main.go" - config-path: "./config.json" - secrets-path: "../secrets.yaml" # Path to your secrets file -``` + // In a real workflow, you would forward the encrypted body to your + // secure backend for decryption. This inline decryption is shown + // for demonstration purposes only. + keyHex := os.Getenv("AES_KEY_ALL") // your 256-bit hex-encoded key + keyBytes, _ := hex.DecodeString(keyHex) + decrypted, err := AESGCMDecrypt(resp.Body, keyBytes) + if err != nil { + return Result{}, fmt.Errorf("failed to decrypt response: %w", err) + } -Notice the path `../secrets.yaml`. Because the workflow artifacts are relative to the workflow directory, you need to point to the `secrets.yaml` file located one level up in the project root. + var result Result + if err := json.Unmarshal(decrypted, &result); err != nil { + return Result{}, fmt.Errorf("failed to parse response: %w", err) + } -### Step 5: Run the simulation + return result, nil +} -Now you can simulate your workflow: +func AESGCMDecrypt(blob []byte, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } -```bash -cre workflow simulate my-workflow --target staging-settings + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonceSize := gcm.NonceSize() + if len(blob) < nonceSize { + return nil, fmt.Errorf("ciphertext too short") + } + + nonce, ciphertext := blob[:nonceSize], blob[nonceSize:] + return gcm.Open(nil, nonce, ciphertext, nil) +} ``` -The CLI will automatically read the `secrets-path` from your `workflow.yaml` and load the secrets from your `.env` file or environment variables you provided in your terminal session. +## API reference -## Fetching multiple secrets +For the full list of types and methods available on the Confidential HTTP client, see the [Confidential HTTP Client SDK Reference](/cre/reference/sdk/confidential-http-client-go). -You can fetch multiple secrets by calling the secret retrieval method multiple times within your workflow. +--- +# Forwarder Directory +Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/forwarder-directory-go +Last Updated: 2026-02-03 -<Aside type="caution" title="Fetch secrets sequentially"> - The WASM host for the CRE runtime does not support parallel `runtime.GetSecret()` requests. Always fetch secrets **sequentially**: call `GetSecret()`, await the promise with `.Await()`, then call `GetSecret()` again for the next secret. Do not attempt to fetch multiple secrets in parallel. +<Aside type="note" title="Looking for supported networks?"> + For a complete list of supported networks and version requirements, see [Supported Networks](/cre/supported-networks). </Aside> -The following example builds on the previous one. First, update your `secrets.yaml` to declare two secrets: +This page lists forwarder contract addresses for CRE workflows, organized by network. -```yaml -secretsNames: - SECRET_ADDRESS: - - SECRET_ADDRESS_ALL - API_KEY: - - API_KEY_ALL -``` +## How to Use This Page -Then provide the values in your `.env` file or export them as environment variables in your terminal session: +This reference provides three key pieces of information for each network: -```bash -export SECRET_ADDRESS_ALL="0x1234567890abcdef1234567890abcdef12345678" -export API_KEY_ALL="your-api-key-here" -``` +1. **Network Name**: The human-readable network identifier +2. **Chain Name**: The value to use in your [`project.yaml`](/cre/reference/project-configuration-go#31-global-configuration-projectyaml) configuration and [EVM Client code](/cre/reference/sdk/evm-client-go#chain-selectors) +3. **Forwarder Address**: The contract address for optional consumer contract validation -Now you can fetch both secrets in your workflow code: +## Understanding Forwarder Addresses -Code snippet for Fetching Multiple Secrets (Go): +Forwarder addresses identify the trusted Chainlink Forwarder contract that delivers verified workflow reports to your consumer contract. Your workflow code does not interact with forwarders directly—the EVM capability handles report delivery automatically. Learn more: [Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview-go). -```go -//go:build wasip1 +**Using the [ReceiverTemplate](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#3-using-receivertemplate) (recommended)**: If you use the [`ReceiverTemplate`](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#receivertemplate), the forwarder address is **required** in the constructor. This ensures your contract only accepts reports from the trusted Chainlink Forwarder. -package main +**Custom implementations**: If you implement the `IReceiver` interface directly without using `ReceiverTemplate`, you control your own security checks. See [Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts) for details. -import ( - "log/slog" +### Simulation vs Production Addresses - protos "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" - "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" - "github.com/smartcontractkit/cre-sdk-go/cre" - "github.com/smartcontractkit/cre-sdk-go/cre/wasm" -) +**Important**: Forwarder contracts differ between local simulation and production: -// Config can be an empty struct if you don't need any parameters from config.json. -type Config struct{} +| Environment | Contract Type | Section | +| ---------------- | ----------------------- | ----------------------------------------------- | +| Local simulation | `MockKeystoneForwarder` | [Simulation Forwarders](#simulation-forwarders) | +| Production | `KeystoneForwarder` | [Production Forwarders](#production-forwarders) | -// MyResult can be an empty struct if your workflow doesn't need to return a result. -type MyResult struct{} +If you configure forwarder validation in your consumer contract, **remember to update the forwarder address** when deploying to production. Learn more: [Working with Simulation](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#4-working-with-simulation). -const ( - SecretAddressName = "SECRET_ADDRESS" - ApiKeyName = "API_KEY" -) +## Simulation Forwarders -func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) { - logger := runtime.Logger() +These `MockKeystoneForwarder` addresses are used when running `cre workflow simulate` with the `--broadcast` flag. Use these addresses **only** during local development and testing. - // Important: Fetch secrets sequentially, not in parallel. - // The WASM host for CRE runtime does not support parallel runtime.GetSecret() requests. - // Always call GetSecret(), then Await() before making the next GetSecret() call. +### Simulation Mainnets - // 1. Fetch the first secret - addressPromise := runtime.GetSecret(&protos.SecretRequest{Id: SecretAddressName}) - secretAddress, err := addressPromise.Await() - if err != nil { - logger.Error("Failed to get SECRET_ADDRESS", "err", err) - return nil, err - } +| Network | Chain Name | Mock Forwarder Address | +| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------------------ | +| <a href="https://arbiscan.io/address/0xd770499057619c9a76205fd4168161cf94abc532" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | ethereum-mainnet-arbitrum-1 | 0xd770499057619c9a76205fd4168161cf94abc532 | +| <a href="https://snowscan.xyz/address/0xdc21e279934ff6721cadfdd112dafb3261f09a2c" target="_blank" rel="noopener noreferrer">Avalanche</a> | avalanche-mainnet | 0xdc21e279934ff6721cadfdd112dafb3261f09a2c | +| <a href="https://basescan.org/address/0x5e342a8438b4f5d39e72875fcee6f76b39cce548" target="_blank" rel="noopener noreferrer">Base</a> | ethereum-mainnet-base-1 | 0x5e342a8438b4f5d39e72875fcee6f76b39cce548 | +| <a href="https://bscscan.com/address/0x6f3239bbb26e98961e1115aba83f8a282e5508c8" target="_blank" rel="noopener noreferrer">BNB Chain</a> | binance_smart_chain-mainnet | 0x6f3239bbb26e98961e1115aba83f8a282e5508c8 | +| <a href="https://etherscan.io/address/0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | ethereum-mainnet | 0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9 | +| <a href="https://optimistic.etherscan.io/address/0x9119a1501550ed94a3f2794038ed9258337afa18" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | ethereum-mainnet-optimism-1 | 0x9119a1501550ed94a3f2794038ed9258337afa18 | +| <a href="https://polygonscan.com/address/0xf458d621885e29a5003ea9bbba5280d54e19b1ce" target="_blank" rel="noopener noreferrer">Polygon</a> | polygon-mainnet | 0xf458d621885e29a5003ea9bbba5280d54e19b1ce | +| <a href="https://explorer.zksync.io/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">ZKSync Era</a> | ethereum-mainnet-zksync-1 | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | - // 2. Fetch the second secret (only after the first is complete) - apiKeyPromise := runtime.GetSecret(&protos.SecretRequest{Id: ApiKeyName}) - apiKey, err := apiKeyPromise.Await() - if err != nil { - logger.Error("Failed to get API_KEY", "err", err) - return nil, err - } +### Simulation Testnets - // 3. Use your secrets - logger.Info("Successfully fetched secrets!", - "address", secretAddress.Value, - "apiKey", apiKey.Value, - ) +| Network | Chain Name | Mock Forwarder Address | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------ | +| <a href="https://explorer.curtis.apechain.com/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Apechain Curtis</a> | apechain-testnet-curtis | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://testnet.arcscan.app/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Arc Testnet</a> | arc-testnet | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia.arbiscan.io/address/0xd41263567ddfead91504199b8c6c87371e83ca5d" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | ethereum-testnet-sepolia-arbitrum-1 | 0xd41263567ddfead91504199b8c6c87371e83ca5d | +| <a href="https://testnet.snowscan.xyz/address/0x2e7371a5d032489e4f60216d8d898a4c10805963" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | avalanche-testnet-fuji | 0x2e7371a5d032489e4f60216d8d898a4c10805963 | +| <a href="https://sepolia.basescan.org/address/0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | ethereum-testnet-sepolia-base-1 | 0x82300bd7c3958625581cc2f77bc6464dcecdf3e5 | +| <a href="https://testnet.bscscan.com/address/0xa238e42cb8782808dbb2f37e19859244ec4779b0" target="_blank" rel="noopener noreferrer">BNB Chain Testnet</a> | binance_smart_chain-testnet | 0xa238e42cb8782808dbb2f37e19859244ec4779b0 | +| <a href="https://sepolia.etherscan.io/address/0x15fC6ae953E024d975e77382eEeC56A9101f9F88" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | ethereum-testnet-sepolia | 0x15fC6ae953E024d975e77382eEeC56A9101f9F88 | +| <a href="https://testnet.purrsec.com/address/0xB27fA1c28288c50542527F64BCda22C9FbAc24CB" target="_blank" rel="noopener noreferrer">Hyperliquid Testnet</a> | hyperliquid-testnet | 0xB27fA1c28288c50542527F64BCda22C9FbAc24CB | +| <a href="https://explorer-sepolia.inkonchain.com/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Ink Sepolia</a> | ink-testnet-sepolia | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia-explorer.jovay.io/l2/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Jovay Testnet</a> | jovay-testnet | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia.lineascan.build/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Linea Sepolia</a> | ethereum-testnet-sepolia-linea-1 | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia-optimism.etherscan.io/address/0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | ethereum-testnet-sepolia-optimism-1 | 0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3 | +| <a href="https://testnet.plasmascan.to/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Plasma Testnet</a> | plasma-testnet | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://amoy.polygonscan.com/address/0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | polygon-testnet-amoy | 0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74 | +| <a href="https://sepolia.worldscan.org/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">World Chain Sepolia</a> | ethereum-testnet-sepolia-worldchain-1 | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia.explorer.zksync.io/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">ZKSync Era Sepolia</a> | ethereum-testnet-sepolia-zksync-1 | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | - return &MyResult{}, nil -} +## Production Forwarders -// InitWorkflow is the required entry point for a CRE workflow. -func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { - return cre.Workflow[*Config]{ - cre.Handler( - cron.Trigger(&cron.Config{Schedule: "0 */10 * * * *"}), - onCronTrigger, - ), - }, nil -} +These `KeystoneForwarder` addresses are used by deployed workflows. Use these addresses when configuring your consumer contracts for production. -// main is the entry point for the WASM binary. -func main() { - wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow) -} -``` +### Mainnets + +| Network | Chain Name | Forwarder Address | +| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------------------ | +| <a href="https://arbiscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | ethereum-mainnet-arbitrum-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche</a> | avalanche-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base</a> | ethereum-mainnet-base-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Chain</a> | binance_smart_chain-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://etherscan.io/address/0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | ethereum-mainnet | 0x0b93082D9b3C7C97fAcd250082899BAcf3af3885 | +| <a href="https://optimistic.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | ethereum-mainnet-optimism-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon</a> | polygon-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://explorer.zksync.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">ZKSync Era</a> | ethereum-mainnet-zksync-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | + +### Testnets + +| Network | Chain Name | Forwarder Address | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------ | +| <a href="https://explorer.curtis.apechain.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Apechain Curtis</a> | apechain-testnet-curtis | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.arbiscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | ethereum-testnet-sepolia-arbitrum-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://testnet.snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | avalanche-testnet-fuji | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | ethereum-testnet-sepolia-base-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://testnet.bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Chain Testnet</a> | binance_smart_chain-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | ethereum-testnet-sepolia | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://testnet.purrsec.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Hyperliquid Testnet</a> | hyperliquid-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://explorer-sepolia.inkonchain.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Ink Sepolia</a> | ink-testnet-sepolia | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia-explorer.jovay.io/l2/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Jovay Testnet</a> | jovay-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.lineascan.build/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Linea Sepolia</a> | ethereum-testnet-sepolia-linea-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia-optimism.etherscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | ethereum-testnet-sepolia-optimism-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://testnet.plasmascan.to/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Plasma Testnet</a> | plasma-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://amoy.polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | polygon-testnet-amoy | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.worldscan.org/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">World Chain Sepolia</a> | ethereum-testnet-sepolia-worldchain-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.explorer.zksync.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">ZKSync Era Sepolia</a> | ethereum-testnet-sepolia-zksync-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | --- # Onchain Read Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-read-go -Last Updated: 2025-11-04 +Last Updated: 2025-12-10 This guide explains how to read data from a smart contract from within your CRE workflow. The process uses [generated bindings](/cre/guides/workflow/using-evm-client/generating-bindings) and the SDK's [`evm.Client`](/cre/reference/sdk/evm-client) to create a simple, type-safe developer experience. @@ -10075,28 +11394,73 @@ When calling contract read methods, you must specify a block number. There are t ### Using magic numbers -- **Finalized block**: Use `big.NewInt(-3)` to read from the latest finalized block +- **Finalized block**: Use `big.NewInt(-3)` to read from the latest finalized block (recommended for production) - **Latest block**: Use `big.NewInt(-2)` to read from the latest block -- **Specific block**: Use `big.NewInt(blockNumber)` to read from a specific block -### Using rpc constants (alternative) +For explicit block numbers, see [Custom block depths](#custom-block-depths) below. + +### Custom block depths + +For use cases requiring fixed confirmation thresholds (e.g., regulatory compliance) or historical state verification, you can specify an exact block number. + +**Example 1 - Read from a specific historical block**: + +```go +// Read from block 12345678 +specificBlock := big.NewInt(12345678) +value, err := storageContract.Get(runtime, specificBlock).Await() +if err != nil { + return nil, fmt.Errorf("failed to read from specific block: %w", err) +} +``` -You can also use constants from the `go-ethereum/rpc` package for better readability: +**Example 2 - Read from 500 blocks ago from latest block**: ```go import ( - "math/big" - "github.com/ethereum/go-ethereum/rpc" + pb "github.com/smartcontractkit/chainlink-protos/cre/go/values/pb" ) -// For latest block -reqBlockNumber := big.NewInt(rpc.LatestBlockNumber.Int64()) +// Helper to convert protobuf BigInt to standard library big.Int +func pbBigIntToBigInt(pb *pb.BigInt) *big.Int { + if pb == nil { + return nil + } + result := new(big.Int).SetBytes(pb.AbsVal) + if pb.Sign < 0 { + result.Neg(result) + } + return result +} + +// Get the latest block number +latestHeader, err := evmClient.HeaderByNumber(runtime, &evm.HeaderByNumberRequest{}).Await() +if err != nil { + return nil, fmt.Errorf("failed to get latest block: %w", err) +} + +// Convert protobuf BigInt to standard library big.Int +latestBlockNum := pbBigIntToBigInt(latestHeader.Header.BlockNumber) +customDepth := big.NewInt(500) +customBlock := new(big.Int).Sub(latestBlockNum, customDepth) -// For finalized block -reqBlockNumber := big.NewInt(rpc.FinalizedBlockNumber.Int64()) +// Use the custom block number with the contract binding +value, err := storageContract.Get(runtime, customBlock).Await() +if err != nil { + return nil, fmt.Errorf("failed to read from custom block: %w", err) +} ``` -Both approaches are equivalent - use whichever you find more readable in your code. +**Understanding the conversion:** + +The `pbBigIntToBigInt` helper converts the SDK's protobuf `*pb.BigInt` type (which stores the value as `AbsVal []byte` and `Sign int64`) to Go's standard library `*big.Int`. This allows you to perform arithmetic operations like subtracting 500 blocks. + +<Aside type="note" title="SDK enhancement planned"> + The SDK team is working on a built-in helper to simplify this conversion. Until then, use the `pbBigIntToBigInt` + helper shown above. +</Aside> + +See [Finality and Confidence Levels](/cre/concepts/finality-go) for more details on when to use custom block depths. ## Complete example @@ -10357,7 +11721,7 @@ max := big.NewInt(1000) randomValue := new(big.Int).Rand(rnd, max) ``` -**Note**: For a complete understanding of how randomness works in CRE, including the difference between DON mode and Node mode randomness, see [Random in CRE](/cre/concepts/random-in-cre). +**Note**: For a complete understanding of how randomness works in CRE, including the difference between DON mode and Node mode randomness, see [Using Randomness in Workflows](/cre/guides/workflow/using-randomness). ### Constructing input structs @@ -10383,140 +11747,61 @@ Solidity types like `bytes` and `bytes32` map to `[]byte` in Go. - **[Generating Bindings](/cre/guides/workflow/using-evm-client/generating-bindings)**: How to create type-safe contract bindings - **[Using WriteReportFrom Helpers](/cre/guides/workflow/using-evm-client/onchain-write/using-write-report-helpers)**: Implementation guide for the most common approach - **[EVM Client Reference](/cre/reference/sdk/evm-client)**: Complete API documentation for the `evm.Client` -- **[Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read)**: Reading data from smart contracts - ---- - -# EVM Chain Interactions -Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/overview-go -Last Updated: 2025-11-04 - -The `evm.Client` is the Go SDK's interface for interacting with EVM-compatible blockchains. It provides a simple, powerful, and type-safe way to read data from and write data to your onchain contracts through the underlying **[EVM Read & Write Capabilities](/cre/capabilities/evm-read-write)**. - -## How it works - -The Go SDK uses **auto-generated contract bindings** created by the CRE CLI. These bindings provide: - -- Type-safe Go structs for contract functions and events -- Automatic ABI encoding/decoding -- Promise-based async operations with `.Await()` -- Built-in helper methods for common operations - -This approach gives you IDE autocompletion, compile-time type checking, and eliminates manual ABI handling. - -## Guides - -- **[Generating Contract Bindings](/cre/guides/workflow/using-evm-client/generating-bindings)**: Learn how to generate type-safe Go bindings from contract ABIs using the CRE CLI -- **[Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read)**: Learn how to call `view` and `pure` functions on your smart contracts to read onchain state -- **[Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write)**: Learn how to call state-changing functions on your smart contracts to write data to the blockchain - - **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Learn how to write your own consumer contracts that can receive reports from your workflow - ---- - -# Supported Networks -Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/supported-networks-go -Last Updated: 2025-11-20 - -This page lists the EVM-compatible networks supported by CRE workflows, along with their chain names (for configuration) and forwarder contract addresses (for consumer contract validation). - -## How to Use This Page - -This reference provides three key pieces of information for each network: - -1. **Network Name**: The human-readable network identifier -2. **Chain Name**: The value to use in your [`project.yaml`](/cre/reference/project-configuration-go#31-global-configuration-projectyaml) configuration and [EVM Client code](/cre/reference/sdk/evm-client-go#chain-selectors) -3. **Forwarder Address**: The contract address for optional consumer contract validation - -## Understanding Forwarder Addresses - -Forwarder addresses are relevant **only if you want to add security validation to your consumer contracts**. Your workflow code does not interact with forwarders directly—the EVM capability handles report delivery automatically. Learn more: [Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview-go). - -**Optional security layer**: You can configure your consumer contract's `onReport()` function to accept calls only from the trusted forwarder address. See [Configuring Permissions](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#34-configuring-permissions) for implementation details. - -### Simulation vs Production Addresses - -**Important**: Forwarder contracts differ between local simulation and production: - -| Environment | Contract Type | Section | -| ---------------- | ----------------------- | ----------------------------------------------- | -| Local simulation | `MockKeystoneForwarder` | [Simulation Forwarders](#simulation-forwarders) | -| Production | `KeystoneForwarder` | [Production Forwarders](#production-forwarders) | - -If you configure forwarder validation in your consumer contract, **remember to update the forwarder address** when deploying to production. Learn more: [Working with Simulation](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#4-working-with-simulation). - -## Simulation Forwarders - -These `MockKeystoneForwarder` addresses are used when running `cre workflow simulate` with the `--broadcast` flag. Use these addresses **only** during local development and testing. - -### Simulation Mainnets - -| Network | Chain Name | Mock Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------------------ | -| <a href="https://arbiscan.io/address/0xd770499057619c9a76205fd4168161cf94abc532" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | ethereum-mainnet-arbitrum-1 | 0xd770499057619c9a76205fd4168161cf94abc532 | -| <a href="https://snowscan.xyz/address/0xdc21e279934ff6721cadfdd112dafb3261f09a2c" target="_blank" rel="noopener noreferrer">Avalanche</a> | avalanche-mainnet | 0xdc21e279934ff6721cadfdd112dafb3261f09a2c | -| <a href="https://basescan.org/address/0x5e342a8438b4f5d39e72875fcee6f76b39cce548" target="_blank" rel="noopener noreferrer">Base</a> | ethereum-mainnet-base-1 | 0x5e342a8438b4f5d39e72875fcee6f76b39cce548 | -| <a href="https://bscscan.com/address/0x6f3239bbb26e98961e1115aba83f8a282e5508c8" target="_blank" rel="noopener noreferrer">BNB Chain</a> | binance_smart_chain-mainnet | 0x6f3239bbb26e98961e1115aba83f8a282e5508c8 | -| <a href="https://etherscan.io/address/0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | ethereum-mainnet | 0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9 | -| <a href="https://optimistic.etherscan.io/address/0x9119a1501550ed94a3f2794038ed9258337afa18" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | ethereum-mainnet-optimism-1 | 0x9119a1501550ed94a3f2794038ed9258337afa18 | -| <a href="https://polygonscan.com/address/0xf458d621885e29a5003ea9bbba5280d54e19b1ce" target="_blank" rel="noopener noreferrer">Polygon</a> | polygon-mainnet | 0xf458d621885e29a5003ea9bbba5280d54e19b1ce | +- **[Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read)**: Reading data from smart contracts -### Simulation Testnets +--- -| Network | Chain Name | Mock Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------------------------------------------ | -| <a href="https://sepolia.arbiscan.io/address/0xd41263567ddfead91504199b8c6c87371e83ca5d" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | ethereum-testnet-sepolia-arbitrum-1 | 0xd41263567ddfead91504199b8c6c87371e83ca5d | -| <a href="https://testnet.snowscan.xyz/address/0x2e7371a5d032489e4f60216d8d898a4c10805963" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | avalanche-testnet-fuji | 0x2e7371a5d032489e4f60216d8d898a4c10805963 | -| <a href="https://sepolia.basescan.org/address/0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | ethereum-testnet-sepolia-base-1 | 0x82300bd7c3958625581cc2f77bc6464dcecdf3e5 | -| <a href="https://testnet.bscscan.com/address/0xa238e42cb8782808dbb2f37e19859244ec4779b0" target="_blank" rel="noopener noreferrer">BNB Chain Testnet</a> | binance_smart_chain-testnet | 0xa238e42cb8782808dbb2f37e19859244ec4779b0 | -| <a href="https://sepolia.etherscan.io/address/0x15fC6ae953E024d975e77382eEeC56A9101f9F88" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | ethereum-testnet-sepolia | 0x15fC6ae953E024d975e77382eEeC56A9101f9F88 | -| <a href="https://sepolia-optimism.etherscan.io/address/0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | ethereum-testnet-sepolia-optimism-1 | 0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3 | -| <a href="https://amoy.polygonscan.com/address/0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | polygon-testnet-amoy | 0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74 | +# EVM Chain Interactions +Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/overview-go +Last Updated: 2025-11-04 -## Production Forwarders +The `evm.Client` is the Go SDK's interface for interacting with EVM-compatible blockchains. It provides a simple, powerful, and type-safe way to read data from and write data to your onchain contracts through the underlying **[EVM Read & Write Capabilities](/cre/capabilities/evm-read-write)**. -These `KeystoneForwarder` addresses are used by deployed workflows. Use these addresses when configuring your consumer contracts for production. +## How it works -### Mainnets +The Go SDK uses **auto-generated contract bindings** created by the CRE CLI. These bindings provide: -| Network | Chain Name | Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------------------ | -| <a href="https://arbiscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | ethereum-mainnet-arbitrum-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche</a> | avalanche-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base</a> | ethereum-mainnet-base-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Chain</a> | binance_smart_chain-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://etherscan.io/address/0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | ethereum-mainnet | 0x0b93082D9b3C7C97fAcd250082899BAcf3af3885 | -| <a href="https://optimistic.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | ethereum-mainnet-optimism-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon</a> | polygon-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +- Type-safe Go structs for contract functions and events +- Automatic ABI encoding/decoding +- Promise-based async operations with `.Await()` +- Built-in helper methods for common operations -### Testnets +This approach gives you IDE autocompletion, compile-time type checking, and eliminates manual ABI handling. + +## Guides -| Network | Chain Name | Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------------------------------------------ | -| <a href="https://sepolia.arbiscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | ethereum-testnet-sepolia-arbitrum-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://testnet.snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | avalanche-testnet-fuji | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://sepolia.basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | ethereum-testnet-sepolia-base-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://testnet.bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Chain Testnet</a> | binance_smart_chain-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://sepolia.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | ethereum-testnet-sepolia | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://sepolia-optimism.etherscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | ethereum-testnet-sepolia-optimism-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://amoy.polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | polygon-testnet-amoy | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +- **[Generating Contract Bindings](/cre/guides/workflow/using-evm-client/generating-bindings)**: Learn how to generate type-safe Go bindings from contract ABIs using the CRE CLI +- **[Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read)**: Learn how to call `view` and `pure` functions on your smart contracts to read onchain state +- **[Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview)**: Learn how to call state-changing functions on your smart contracts to write data to the blockchain + - **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Learn how to write your own consumer contracts that can receive reports from your workflow --- # Making GET Requests Source: https://docs.chain.link/cre/guides/workflow/using-http-client/get-request-go -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 The `http.Client` is the SDK's interface for the underlying [HTTP Capability](/cre/capabilities/http). It allows your workflow to fetch data from any external API. All HTTP requests are wrapped in a consensus mechanism to provide a single, reliable result. The SDK provides two ways to do this: - **[`http.SendRequest`](#1-the-httpsendrequest-pattern-recommended):** (Recommended) A high-level helper function that simplifies making requests. -- **[`cre.RunInNodeMode`](#2-the-cre-runinnodemode-pattern-low-level):** The lower-level pattern for more complex scenarios. +- **[`cre.RunInNodeMode`](#2-the-creruninnodemode-pattern-low-level):** The lower-level pattern for more complex scenarios. ## Prerequisites This guide assumes you have a basic understanding of CRE. If you are new, we strongly recommend completing the [Getting Started tutorial](/cre/getting-started/overview) first. + +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + + +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.Now()` instead of `time.Now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + ## Choosing your approach ### Use `http.SendRequest` (Section 1) when: @@ -10710,7 +11995,7 @@ The `http.Request` struct provides several fields to customize your request. See # Making POST Requests Source: https://docs.chain.link/cre/guides/workflow/using-http-client/post-request-go -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 This guide explains how to use the HTTP Client to send data to an external API using a `POST` request. Because POST requests typically create resources or trigger actions, this guide shows you how to ensure your request executes only once, even though multiple nodes in the DON run your workflow. @@ -10726,6 +12011,11 @@ All HTTP requests are wrapped in a consensus mechanism. The SDK provides two way - **[`http.SendRequest`](#1-the-httpsendrequest-pattern-recommended):** A high-level helper function that simplifies making requests. This is the recommended approach for most use cases. - **[`cre.RunInNodeMode`](#2-the-cre-runinnodemode-pattern-low-level):** The lower-level pattern for more complex scenarios. + +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.Now()` instead of `time.Now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + ## Choosing your approach ### Use `http.SendRequest` (Section 1) when: @@ -10752,6 +12042,11 @@ For this example, we will use <a href="https://webhook.site/" target="_blank">** This guide assumes you have a basic understanding of CRE. If you are new, we strongly recommend completing the [Getting Started tutorial](/cre/getting-started/overview) first. + +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + ## 1. The `http.SendRequest` Pattern (recommended) The `http.SendRequest` helper function is the simplest and recommended way to make `POST` requests. It automatically handles the `cre.RunInNodeMode` pattern for you. @@ -11285,6 +12580,11 @@ This guide shows how to send a cryptographically signed report (generated by you - Understanding of [generating reports](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) - A generated report from `runtime.GenerateReport()` + +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + ## Quick start: Minimal example Here's the simplest possible workflow that generates and submits a report via HTTP: @@ -11378,7 +12678,7 @@ Here are common patterns for formatting reports. Choose the one that matches you | Pattern | When to use | | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | | [**Pattern 1: Report in body**](#pattern-1-report-in-body-simplest) | Your API accepts raw binary data and handles decoding | -| [**Pattern 2: Report + signatures in body**](#pattern-2-report-signatures-in-body) | Your API needs everything concatenated in one binary blob | +| [**Pattern 2: Report + signatures in body**](#pattern-2-report--signatures-in-body) | Your API needs everything concatenated in one binary blob | | [**Pattern 3: Report in body, signatures in headers**](#pattern-3-report-in-body-signatures-in-headers) | Your API needs signatures separated for easier parsing | | [**Pattern 4: JSON-formatted report**](#pattern-4-json-formatted-report) | Your API only accepts JSON payloads | @@ -12401,7 +13701,7 @@ func onHttpTrigger(config *Config, runtime cre.Runtime, payload *http.Payload) ( logger := runtime.Logger() // Unmarshal the JSON input from bytes - var requestData map[string]interface{} + var requestData map[string]any if err := json.Unmarshal(payload.Input, &requestData); err != nil { return nil, fmt.Errorf("failed to unmarshal input: %w", err) } @@ -12449,7 +13749,7 @@ func onHttpTrigger(config *Config, runtime cre.Runtime, payload *http.Payload) ( // The payload.Input is []byte containing JSON data. // Unmarshal it into a map or a custom struct. - var requestData map[string]interface{} + var requestData map[string]any if err := json.Unmarshal(payload.Input, &requestData); err != nil { return nil, fmt.Errorf("failed to unmarshal input: %w", err) } @@ -12719,7 +14019,7 @@ The typical project setup flow for Go workflows: # Project Configuration Source: https://docs.chain.link/cre/reference/project-configuration-go -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 This page explains how to manage configuration within Chainlink Runtime Environment (CRE) projects. It covers the standard project structure, the roles and usage of the configuration files (`project.yaml` and `workflow.yaml`), and the concept of **targets** for handling environment-specific settings. @@ -12803,9 +14103,9 @@ production-settings: ``` <Aside type="note" title="Available chain names"> - For a complete list of supported networks and their chain names, see [Supported - Networks](/cre/guides/workflow/using-evm-client/supported-networks). For details on using chain selectors in your - workflow code, see [Chain Selectors](/cre/reference/sdk/evm-client-go#chain-selectors). + For a complete list of supported networks and their chain names, see [Supported Networks](/cre/supported-networks). + For details on using chain selectors in your workflow code, see [Chain + Selectors](/cre/reference/sdk/evm-client-go#chain-selectors). </Aside> #### Configuration fields @@ -12935,6 +14235,314 @@ When you run a CLI command with a target, e.g., `--target staging-settings`: `workflow.yaml`. A mismatch causes the CLI to abort with a clear error message. </Aside> +## 5. Updating dependencies + +When new networks or SDK features are released, you may need to update your project dependencies. + +### Updating the CLI + +Run [cre update](/cre/reference/cli/utilities#cre-update) to download and install the latest CLI version: + +```bash +cre update +``` + +New projects created with an updated CLI automatically use compatible SDK versions. + +### Updating the SDK (existing projects) + +If you created your project with an older CLI version, update the SDK in your `go.mod`: + +```bash +go get github.com/smartcontractkit/cre-sdk-go@v1.1.4 +``` + +Then run `go mod tidy` to clean up dependencies. + +### Checking your versions + +- **CLI version:** Run `cre version` +- **SDK version:** Check `go.mod` for the `cre-sdk-go` dependency version + +For a list of which versions support which networks, see [Supported Networks](/cre/supported-networks). + +--- + +# SDK Reference: Confidential HTTP Client +Source: https://docs.chain.link/cre/reference/sdk/confidential-http-client-go +Last Updated: 2026-02-10 + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The [Confidential HTTP](/cre/capabilities/confidential-http-go) Client lets you make privacy-preserving requests to external APIs from your workflow. Unlike the regular [`http.Client`](/cre/reference/sdk/http-client), the request executes inside a secure enclave, secrets are injected via templates, and responses can be optionally encrypted. + +- For use cases and a conceptual overview, see [The Confidential HTTP Capability](/cre/capabilities/confidential-http-go) +- **Guide:** [Making Confidential Requests](/cre/guides/workflow/using-confidential-http-client/making-requests-go) + +## Quick reference + +| Method | Description | +| -------------------------------------------------------------- | ---------------------------------------------------------- | +| [`confidentialhttp.SendRequest`](#confidentialhttpsendrequest) | High-level helper with automatic `RunInNodeMode` wrapping | +| [`client.SendRequest`](#clientsendrequest) | Low-level method requiring manual `RunInNodeMode` wrapping | + +## Core types + +### `confidentialhttp.ConfidentialHTTPRequest` + +The top-level request type that combines an HTTP request with Vault DON secrets and encryption settings. + +| Field | Type | Description | +| ----------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `Request` | `*HTTPRequest` | The HTTP request to execute inside the enclave. See [`HTTPRequest`](#confidentialhttphttprequest). | +| `VaultDonSecrets` | `[]*SecretIdentifier` | List of secrets to fetch from the Vault DON and make available in the enclave. See [`SecretIdentifier`](#confidentialhttpsecretidentifier). | +| `EncryptOutput` | `bool` | If `true`, encrypts the response body before it leaves the enclave. See [Response encryption](#response-encryption). Default: `false`. | + +### `confidentialhttp.HTTPRequest` + +Defines the HTTP request that will be executed inside the enclave. + +| Field | Type | Description | +| ---------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------- | +| `Url` | `string` | The URL of the API endpoint. | +| `Method` | `string` | The HTTP method (e.g., `"GET"`, `"POST"`). | +| `Body` | `isHTTPRequest_Body` | The request body. Use `HTTPRequest_BodyString` for string templates or `HTTPRequest_BodyBytes` for raw bytes. | +| `MultiHeaders` | `map[string]*HeaderValues` | Request headers. Supports multiple values per key and template syntax for secret injection. | +| `TemplatePublicValues` | `map[string]string` | Public (non-secret) values used to fill template placeholders in the body and headers. | +| `CustomRootCaCertPem` | `[]byte` | Optional custom root CA certificate (PEM format) for verifying the external server's TLS certificate. | +| `Timeout` | `*durationpb.Duration` | Optional request timeout. | + +#### Setting the request body + +The `Body` field is a `oneof` type with two options: + +**String template (recommended for secret injection):** + +```go +Body: &confidentialhttp.HTTPRequest_BodyString{ + BodyString: `{"auth": "{{.myApiKey}}", "action": "getData"}`, +}, +``` + +**Raw bytes:** + +```go +Body: &confidentialhttp.HTTPRequest_BodyBytes{ + BodyBytes: []byte(`{"action": "getData"}`), +}, +``` + +### `confidentialhttp.HTTPResponse` + +The response returned from the enclave after the HTTP request completes. + +| Field | Type | Description | +| -------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `StatusCode` | `uint32` | The HTTP status code. | +| `Body` | `[]byte` | The response body. If `EncryptOutput` is `true`, this contains the encrypted body (see [Response encryption](#response-encryption)). | +| `MultiHeaders` | `map[string]*HeaderValues` | The HTTP response headers. | + +### `confidentialhttp.SecretIdentifier` + +Identifies a secret stored in the Vault DON. + +| Field | Type | Description | +| ----------- | --------- | ----------------------------------------------------------------------------------------------------------------- | +| `Key` | `string` | The logical name of the secret. Must match the template placeholder (e.g., `"myApiKey"` matches `{{.myApiKey}}`). | +| `Namespace` | `string` | The secret namespace. | +| `Owner` | `*string` | Optional. The owner address for the secret. | + +### `confidentialhttp.HeaderValues` + +Represents multiple values for a single HTTP header key. + +| Field | Type | Description | +| -------- | ---------- | ------------------------------------------------------------------------------------------------ | +| `Values` | `[]string` | The header values. Supports template syntax for secret injection (e.g., `"Basic {{.myToken}}"`). | + +## Making requests + +### `confidentialhttp.SendRequest` + +The high-level helper function for making confidential HTTP requests. Automatically handles the `cre.RunInNodeMode` pattern. + +**Signature:** + +```go +func SendRequest[C, T any]( + config C, + runtime cre.Runtime, + client *Client, + fn func(config C, logger *slog.Logger, sendRequester *SendRequester) (T, error), + ca cre.ConsensusAggregation[T], +) cre.Promise[T] +``` + +**Parameters:** + +- `config`: Your workflow's configuration struct, passed to `fn`. +- `runtime`: The top-level `cre.Runtime` from your trigger callback. +- `client`: An initialized `*confidentialhttp.Client`. +- `fn`: Your request logic function that receives `config`, `logger`, and `sendRequester`. +- `ca`: The [consensus aggregation method](/cre/reference/sdk/consensus). + +**Example:** + +```go +func fetchData(config *Config, logger *slog.Logger, sendRequester *confidentialhttp.SendRequester) (*Result, error) { + resp, err := sendRequester.SendRequest(&confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "GET", + MultiHeaders: map[string]*confidentialhttp.HeaderValues{ + "Authorization": {Values: []string{"Basic {{.apiKey}}"}}, + }, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "apiKey"}, + }, + }).Await() + if err != nil { + return nil, err + } + // Parse resp.Body... + return &Result{}, nil +} + +// In your trigger callback +client := &confidentialhttp.Client{} +result, err := confidentialhttp.SendRequest(config, runtime, client, + fetchData, + cre.ConsensusIdenticalAggregation[*Result](), +).Await() +``` + +### `client.SendRequest` + +The lower-level method for making confidential HTTP requests. Must be manually wrapped in `cre.RunInNodeMode`. + +**Signature:** + +```go +func (c *Client) SendRequest(runtime cre.NodeRuntime, input *ConfidentialHTTPRequest) cre.Promise[*HTTPResponse] +``` + +**Parameters:** + +- `runtime`: A `cre.NodeRuntime` provided by `cre.RunInNodeMode`. +- `input`: A `*ConfidentialHTTPRequest` containing the request, secrets, and encryption settings. + +**Returns:** + +- `cre.Promise[*HTTPResponse]` + +**Example:** + +```go +result, err := cre.RunInNodeMode(config, runtime, + func(config Config, nodeRuntime cre.NodeRuntime) (Result, error) { + client := confidentialhttp.Client{} + resp, err := client.SendRequest(nodeRuntime, &confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"auth": "{{.apiKey}}"}`}, + MultiHeaders: map[string]*confidentialhttp.HeaderValues{ + "Content-Type": {Values: []string{"application/json"}}, + }, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "apiKey"}, + }, + }).Await() + if err != nil { + return Result{}, err + } + // Parse and return... + return Result{}, nil + }, + cre.ConsensusIdenticalAggregation[Result](), +).Await() +``` + +**Guide:** [Making Confidential Requests](/cre/guides/workflow/using-confidential-http-client/making-requests-go) + +## Template syntax + +Secrets are injected into the request body and headers using Go template syntax: `{{.secretName}}`. The placeholder name must match the `Key` field in the corresponding `SecretIdentifier`. + +**Body template:** + +```go +Body: &confidentialhttp.HTTPRequest_BodyString{ + BodyString: `{"apiKey": "{{.myApiKey}}", "method": "{{.method}}", "params": []}`, +}, +``` + +**Header template:** + +```go +MultiHeaders: map[string]*confidentialhttp.HeaderValues{ + "Authorization": {Values: []string{"Basic {{.myCredential}}"}}, +}, +``` + +### `TemplatePublicValues` (optional) + +Every `{{.placeholder}}` in your body or headers is resolved inside the enclave. By default, placeholders are filled with **secrets** from `VaultDonSecrets`. But sometimes you have a placeholder value that isn't secret — for example, an RPC method name or a public parameter. That's what `TemplatePublicValues` is for: it lets you inject **non-secret** values into the same template. + +This is purely a convenience. You could always hardcode the value directly in the body string instead: + +```go +// These two are equivalent: + +// Option 1: hardcoded in the body string +Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"method": "eth_blockNumber", "auth": "{{.apiKey}}"}`} + +// Option 2: using TemplatePublicValues +Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"method": "{{.method}}", "auth": "{{.apiKey}}"}`} +TemplatePublicValues: map[string]string{"method": "eth_blockNumber"} +``` + +`TemplatePublicValues` is useful when you want to keep the template generic and pass in dynamic values (e.g., from config) without string concatenation. + +**Example with both secret and public values:** + +```go +Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"method": "{{.rpcMethod}}", "auth": "{{.apiKey}}"}`}, + TemplatePublicValues: map[string]string{ + "rpcMethod": config.RPCMethod, // dynamic value from config, not a secret + }, +}, +VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "apiKey"}, // secret, from Vault DON +}, +``` + +In this example, `{{.rpcMethod}}` is resolved from `TemplatePublicValues` (a dynamic, non-secret value from your workflow config) and `{{.apiKey}}` is resolved from the Vault DON (a secret). Both are resolved inside the enclave. + +## Response encryption + +The `EncryptOutput` field controls whether the response body is encrypted before leaving the enclave. + +| `EncryptOutput` | Secret key provided | Behavior | +| ----------------- | -------------------------------------------------------- | ------------------------------------------------------------- | +| `false` (default) | — | Response returned unencrypted. | +| `true` | `san_marino_aes_gcm_encryption_key` in `VaultDonSecrets` | Response AES-GCM encrypted with your symmetric key. | +| `true` | No key provided | Response TDH2 encrypted with the Vault DON master public key. | + +**AES-GCM encryption** is the recommended approach. Store a 256-bit (32-byte) AES key as a Vault DON secret with the identifier `san_marino_aes_gcm_encryption_key`, then decrypt the response in your own secure backend. + +The encrypted response body is structured as `nonce || ciphertext || tag`. + +For a complete decryption example, see the [Making Confidential Requests guide](/cre/guides/workflow/using-confidential-http-client/making-requests-go#response-encryption). + --- # SDK Reference: Consensus & Aggregation @@ -12949,8 +14557,8 @@ This is a generic interface passed as the final argument to `cre.RunInNodeMode`. There are two primary ways to specify an aggregation method: -1. [**Using Built-in Functions**](/cre/reference/sdk/consensus-go/#1-built-in-aggregation-functions): For simple types, you can use functions like [`ConsensusMedianAggregation`](/cre/reference/sdk/consensus/#consensusmedianaggregationt). -2. [**Using Struct Tags**](/cre/reference/sdk/consensus-go/#2-aggregation-via-struct-tags): For complex types (structs), you can use [`ConsensusAggregationFromTags`](/cre/reference/sdk/consensus/#aggregation-via-struct-tags). +1. [**Using Built-in Functions**](/cre/reference/sdk/consensus-go/#1-built-in-aggregation-functions): For simple types, you can use functions like [`ConsensusMedianAggregation`](/cre/reference/sdk/consensus-go#consensusmedianaggregationt). +2. [**Using Struct Tags**](/cre/reference/sdk/consensus-go/#2-aggregation-via-struct-tags): For complex types (structs), you can use [`ConsensusAggregationFromTags`](/cre/reference/sdk/consensus-go#2-aggregation-via-struct-tags). ## 1. Built-in aggregation functions @@ -13106,7 +14714,7 @@ These interfaces provide access to capabilities and manage the execution context - **`cre.Runtime` ("Easy Mode")**: Passed to your main trigger callback, this represents the **DON's (Decentralized Oracle Network) execution context**. It is used for operations that are already guaranteed to be Byzantine Fault Tolerant (BFT). When you use the `Runtime`, you ask the network to execute something, and CRE handles the underlying complexity to ensure you get back one final, secure, and trustworthy result. A common use case is writing a transaction to a blockchain with the EVM client. -- **`cre.NodeRuntime` ("Manual Mode")**: Represents an **individual node's execution context**. This is used when a BFT guarantee cannot be provided automatically (e.g., calling a third-party API). You tell each node to perform a task on its own, and each node returns its own individual answer. You are then responsible for telling the SDK how to combine them into a single, trusted result by providing a consensus and aggregation algorithm. It is used exclusively inside a [`RunInNodeMode`](#sdkruninnodemode) block and is provided by that function—you do not get this type directly in your handler's callback. +- **`cre.NodeRuntime` ("Manual Mode")**: Represents an **individual node's execution context**. This is used when a BFT guarantee cannot be provided automatically (e.g., calling a third-party API). You tell each node to perform a task on its own, and each node returns its own individual answer. You are then responsible for telling the SDK how to combine them into a single, trusted result by providing a consensus and aggregation algorithm. It is used exclusively inside a [`RunInNodeMode`](#creruninnodemode) block and is provided by that function—you do not get this type directly in your handler's callback. To learn more about how to aggregate results from `NodeRuntime`, see the [Consensus & Aggregation](/cre/reference/sdk/consensus) reference. @@ -13312,7 +14920,7 @@ func onTrigger(config *Config, runtime cre.Runtime, ...) (string, error) { # SDK Reference: EVM Client Source: https://docs.chain.link/cre/reference/sdk/evm-client-go -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 This page provides a reference for the `evm.Client`, the low-level tool for all interactions with EVM-compatible blockchains. The client includes a comprehensive set of read, write, and utility methods for building chain-aware workflows. @@ -13371,10 +14979,10 @@ func (c *Client) CallContract(runtime cre.Runtime, input *CallContractRequest) c This is the main input object for the `CallContract` function. It acts as a wrapper for the call message and an optional block number. -| Field | Type | Description | -| ------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Call` | `*evm.CallMsg` | Contains the actual details of the function call you want to make. | -| `BlockNumber` | `*pb.BigInt` | Optional. The block number to query. Defaults to `latest`. Use `-2` for `latest` (the most recent block, which may be subject to re-orgs) or `-3` for `finalized` (a block that is considered immutable and safe from re-orgs). | +| Field | Type | Description | +| ------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Call` | `*evm.CallMsg` | Contains the actual details of the function call you want to make. | +| `BlockNumber` | `*pb.BigInt` | Optional. The block number to query. Accepts:<br />• `nil` or `-2` (default): `latest` — the most recent block<br />• `-3`: `finalized` — an immutable block<br />• **Any positive integer**: an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-go#custom-block-depths) for examples)<br /><br />See [Finality and Confidence Levels](/cre/concepts/finality-go) for finality strategies. | #### `evm.CallMsg` @@ -13406,10 +15014,10 @@ func (c *Client) BalanceAt(runtime cre.Runtime, input *BalanceAtRequest) cre.Pro #### `evm.BalanceAtRequest` -| Field | Type | Description | -| ------------- | ------------ | ---------------------------------------------------------- | -| `Account` | `[]byte` | The 20-byte address of the account to query. | -| `BlockNumber` | `*pb.BigInt` | Optional. The block number to query. Defaults to `latest`. | +| Field | Type | Description | +| ------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Account` | `[]byte` | The 20-byte address of the account to query. | +| `BlockNumber` | `*pb.BigInt` | Optional. The block number to query. Accepts `nil` or `-2` for `latest` (default), `-3` for `finalized`, or any positive integer for an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-go#custom-block-depths)). See [Finality and Confidence Levels](/cre/concepts/finality-go). | #### `evm.BalanceAtReply` @@ -13495,9 +15103,9 @@ func (c *Client) HeaderByNumber(runtime cre.Runtime, input *HeaderByNumberReques #### `evm.HeaderByNumberRequest` -| Field | Type | Description | -| ------------- | ------------ | -------------------------------------------------------------------------- | -| `BlockNumber` | `*pb.BigInt` | The number of the block to retrieve. If `nil`, retrieves the latest block. | +| Field | Type | Description | +| ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `BlockNumber` | `*pb.BigInt` | The number of the block to retrieve. Accepts `nil` for `latest` (default), `-2` for `latest`, `-3` for `finalized`, or any positive integer for an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-go#custom-block-depths)). See [Finality and Confidence Levels](/cre/concepts/finality-go). | #### `evm.HeaderByNumberReply` @@ -13561,10 +15169,10 @@ func (c *Client) WriteReport(runtime cre.Runtime, input *WriteCreReportRequest) A **chain selector** is a unique identifier for a blockchain network used throughout the CRE platform. The same chain can be referenced in three different ways depending on the context. All three formats are equivalent and refer to the same blockchain. + <Aside type="note" title="Related resources"> - - **Forwarder addresses**: For network-specific forwarder contract addresses, see [Supported - Networks](/cre/guides/workflow/using-evm-client/supported-networks) - **RPC configuration**: For configuring RPC - endpoints in `project.yaml`, see [Project Configuration](/cre/reference/project-configuration) + - **Forwarder addresses**: For network-specific forwarder contract addresses, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) + - **RPC configuration**: For configuring RPC endpoints in `project.yaml`, see [Project Configuration](/cre/reference/project-configuration) </Aside> ### Understanding the three formats @@ -13585,22 +15193,32 @@ A **chain selector** is a unique identifier for a blockchain network used throug This table shows all three equivalent formats for each supported chain: -| Chain | String Name | Go Constant | Numeric ID | -| ----------------- | ----------------------------------- | ----------------------------------- | -------------------- | -| Arbitrum One | ethereum-mainnet-arbitrum-1 | evm.EthereumMainnetArbitrum1 | 4949039107694359620 | -| Arbitrum Sepolia | ethereum-testnet-sepolia-arbitrum-1 | evm.EthereumTestnetSepoliaArbitrum1 | 3478487238524512106 | -| Avalanche Mainnet | avalanche-mainnet | evm.AvalancheMainnet | 6433500567565415381 | -| Avalanche Fuji | avalanche-testnet-fuji | evm.AvalancheTestnetFuji | 14767482510784806043 | -| Base Mainnet | ethereum-mainnet-base-1 | evm.EthereumMainnetBase1 | 15971525489660198786 | -| Base Sepolia | ethereum-testnet-sepolia-base-1 | evm.EthereumTestnetSepoliaBase1 | 10344971235874465080 | -| BNB Chain Mainnet | binance_smart_chain-mainnet | evm.BinanceSmartChainMainnet | 11344663589394136015 | -| BNB Chain Testnet | binance_smart_chain-testnet | evm.BinanceSmartChainTestnet | 5142893604156789321 | -| Ethereum Mainnet | ethereum-mainnet | evm.EthereumMainnet | 5009297550715157269 | -| Ethereum Sepolia | ethereum-testnet-sepolia | evm.EthereumTestnetSepolia | 16015286601757825753 | -| OP Mainnet | ethereum-mainnet-optimism-1 | evm.EthereumMainnetOptimism1 | 3734403246176062136 | -| OP Sepolia | ethereum-testnet-sepolia-optimism-1 | evm.EthereumTestnetSepoliaOptimism1 | 5224473277236331295 | -| Polygon Mainnet | polygon-mainnet | evm.PolygonMainnet | 4051577828743386545 | -| Polygon Amoy | polygon-testnet-amoy | evm.PolygonTestnetAmoy | 16281711391670634445 | +| Chain | String Name | Go Constant | Numeric ID | +| ------------------- | ------------------------------------- | ------------------------------------- | -------------------- | +| Apechain Curtis | apechain-testnet-curtis | evm.ApechainTestnetCurtis | 9900119385908781505 | +| Arc Testnet | arc-testnet | evm.ArcTestnet | 3034092155422581607 | +| Arbitrum One | ethereum-mainnet-arbitrum-1 | evm.EthereumMainnetArbitrum1 | 4949039107694359620 | +| Arbitrum Sepolia | ethereum-testnet-sepolia-arbitrum-1 | evm.EthereumTestnetSepoliaArbitrum1 | 3478487238524512106 | +| Avalanche Mainnet | avalanche-mainnet | evm.AvalancheMainnet | 6433500567565415381 | +| Avalanche Fuji | avalanche-testnet-fuji | evm.AvalancheTestnetFuji | 14767482510784806043 | +| Base Mainnet | ethereum-mainnet-base-1 | evm.EthereumMainnetBase1 | 15971525489660198786 | +| Base Sepolia | ethereum-testnet-sepolia-base-1 | evm.EthereumTestnetSepoliaBase1 | 10344971235874465080 | +| BNB Chain Mainnet | binance_smart_chain-mainnet | evm.BinanceSmartChainMainnet | 11344663589394136015 | +| BNB Chain Testnet | binance_smart_chain-testnet | evm.BinanceSmartChainTestnet | 13264668187771770619 | +| Ethereum Mainnet | ethereum-mainnet | evm.EthereumMainnet | 5009297550715157269 | +| Ethereum Sepolia | ethereum-testnet-sepolia | evm.EthereumTestnetSepolia | 16015286601757825753 | +| Hyperliquid Testnet | hyperliquid-testnet | evm.HyperliquidTestnet | 4286062357653186312 | +| Ink Sepolia | ink-testnet-sepolia | evm.InkTestnetSepolia | 9763904284804119144 | +| Jovay Testnet | jovay-testnet | evm.JovayTestnet | 945045181441419236 | +| Linea Sepolia | ethereum-testnet-sepolia-linea-1 | evm.EthereumTestnetSepoliaLinea1 | 5719461335882077547 | +| OP Mainnet | ethereum-mainnet-optimism-1 | evm.EthereumMainnetOptimism1 | 3734403246176062136 | +| OP Sepolia | ethereum-testnet-sepolia-optimism-1 | evm.EthereumTestnetSepoliaOptimism1 | 5224473277236331295 | +| Plasma Testnet | plasma-testnet | evm.PlasmaTestnet | 3967220077692964309 | +| Polygon Mainnet | polygon-mainnet | evm.PolygonMainnet | 4051577828743386545 | +| Polygon Amoy | polygon-testnet-amoy | evm.PolygonTestnetAmoy | 16281711391670634445 | +| World Chain Sepolia | ethereum-testnet-sepolia-worldchain-1 | evm.EthereumTestnetSepoliaWorldchain1 | 5299555114858065850 | +| ZKSync Era | ethereum-mainnet-zksync-1 | evm.EthereumMainnetZksync1 | 1562403441176082196 | +| ZKSync Era Sepolia | ethereum-testnet-sepolia-zksync-1 | evm.EthereumTestnetSepoliaZksync1 | 6898391096552792247 | ### Usage examples @@ -13683,7 +15301,7 @@ if err != nil { # SDK Reference: HTTP Client Source: https://docs.chain.link/cre/reference/sdk/http-client-go -Last Updated: 2025-11-04 +Last Updated: 2026-01-26 The HTTP Client lets you make requests to external APIs from your workflow. Each node in the DON executes the request independently, and the SDK uses consensus to provide a single, reliable result. @@ -13708,14 +15326,100 @@ The HTTP Client lets you make requests to external APIs from your workflow. Each Defines the parameters for an outgoing HTTP request. -| Field | Type | Description | -| --------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------- | -| `Url` | `string` | The URL of the API endpoint. | -| `Method` | `string` | The HTTP method (e.g., `"GET"`, `"POST"`). | -| `Headers` | `map[string]string` | Optional HTTP headers. | -| `Body` | `[]byte` | Optional raw request body. | -| `Timeout` | `*durationpb.Duration` | Optional request timeout duration. Set using `durationpb.New()`, e.g., `durationpb.New(30 * time.Second)` for 30 seconds. | -| `CacheSettings` | `*CacheSettings` | Optional caching behavior for the request. | + +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + +| Field | Type | Description | +| --------------- | ---------------------- | -------------------------------------------------------------------------------------------------------- | +| `Url` | `string` | The URL of the API endpoint. | +| `Method` | `string` | The HTTP method (e.g., `"GET"`, `"POST"`). | +| `Headers` | `map[string]string` | Optional HTTP headers. | +| `Body` | `[]byte` | Optional raw request body. | +| `Timeout` | `*durationpb.Duration` | Optional request timeout. See [Request Timeout](#request-timeout) below for usage, defaults, and limits. | +| `CacheSettings` | `*CacheSettings` | Optional caching behavior for the request. | + +### Request Timeout + +The `Timeout` field specifies how long to wait for an HTTP request to complete before cancelling it. + +**Format:** + +- Use `*durationpb.Duration` from the [`google.golang.org/protobuf/types/known/durationpb` package](https://pkg.go.dev/google.golang.org/protobuf/types/known/durationpb) +- Create using `durationpb.New()` with a `time.Duration` value +- Or manually construct with `&durationpb.Duration{Seconds: int64}` + +**Default and Limits:** + +- **Default**: If not specified, a default timeout of **5 seconds** is applied. +- **Maximum**: Default maximum is **10 seconds**. Requests exceeding this limit will error. + +**Pattern 1: Using `durationpb.New()`:** + +```go +import ( + "time" + "google.golang.org/protobuf/types/known/durationpb" +) + +resp, err := sendRequester.SendRequest(&http.Request{ + Url: config.ApiUrl, + Method: "GET", + Timeout: durationpb.New(8 * time.Second), // 8 second timeout +}).Await() +``` + +**Pattern 2: Parsing from config:** + +```go +import ( + "time" + "fmt" + "google.golang.org/protobuf/types/known/durationpb" +) + +type Config struct { + ApiUrl string `yaml:"apiUrl"` + TimeoutMs string `yaml:"timeout"` // e.g., "5s", "10s" +} + +func fetchData(config *Config, logger *slog.Logger, sendRequester *http.SendRequester) (string, error) { + // Parse duration string from config + t, err := time.ParseDuration(config.TimeoutMs) + if err != nil { + return "", fmt.Errorf("failed to parse duration (%s): %w", config.TimeoutMs, err) + } + + logger.Info("parsed timeout", "seconds", t.Seconds(), "raw", config.TimeoutMs) + + // Create Duration from parsed time + timeout := &durationpb.Duration{ + Seconds: int64(t.Seconds()), + } + + resp, err := sendRequester.SendRequest(&http.Request{ + Url: config.ApiUrl, + Method: "GET", + Timeout: timeout, + }).Await() + + if err != nil { + logger.Info("http request failed", "error", err) + return "", err + } + + return string(resp.Body), nil +} +``` + +**Example configuration:** + +```yaml +# config.yaml +apiUrl: "https://api.example.com/data" +timeout: "8s" # Go's time.ParseDuration format (max: 10s) +``` ### `http.Response` @@ -13990,16 +15694,7 @@ For complete examples of including signatures in different formats (body, header # SDK Reference Source: https://docs.chain.link/cre/reference/sdk/overview-go -Last Updated: 2025-11-04 - -<Aside type="note" title="Required SDK Version: v1.0.0"> - To ensure compatibility, please use version `v1.0.0` for the core `cre-sdk-go` package and `v1.0.0-beta.0` for capability packages. - - Always use `go get` with an explicit version tag to add dependencies:<br /> - - - Core SDK: `go get github.com/smartcontractkit/cre-sdk-go@v1.0.0`<br /> - - Capabilities: `go get github.com/smartcontractkit/cre-sdk-go/capabilities/networking/http@v1.0.0-beta.0` -</Aside> +Last Updated: 2026-02-03 This section provides a detailed technical reference for the public interfaces of the CRE Go SDK. Use this reference for quick lookups of specific functions, types, and method signatures. @@ -14011,6 +15706,7 @@ The SDK Reference is broken down into several pages, each corresponding to a cor - **[Triggers](/cre/reference/sdk/triggers)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). - **[EVM Client](/cre/reference/sdk/evm-client)**: Provides a reference for the `evm.Client`, the primary tool for all EVM interactions, including reads and writes. - **[HTTP Client](/cre/reference/sdk/http-client)**: Provides a reference for the `http.Client`, used for making offchain API requests from individual nodes. +- **[Confidential HTTP Client](/cre/reference/sdk/confidential-http-client)** *(Experimental)*: Provides a reference for the `confidentialhttp.Client`, used for privacy-preserving API requests with enclave execution and optional response encryption. - **[Consensus & Aggregation](/cre/reference/sdk/consensus)**: Describes how to use aggregators like `ConsensusMedianAggregation` and `ConsensusAggregationFromTags` with `RunInNodeMode` to process and consolidate data from multiple nodes. ## Contract Bindings @@ -14122,9 +15818,9 @@ The configuration struct for the EVM log trigger. | `Topics` | `[]*evm.TopicValues` | A fixed 4-element array to filter event topics. The first element contains event signatures, and the next three elements contain indexed argument values. An empty array element acts as a wildcard. | | `Confidence` | `ConfidenceLevel` | The block confirmation level to monitor. Can be: <ul><li>**`evm.ConfidenceLevel_CONFIDENCE_LEVEL_SAFE` (default):** A block that is considered unlikely to be reorged but is not yet irreversible.</li><li>**`evm.ConfidenceLevel_CONFIDENCE_LEVEL_LATEST`:** The most recent block. This is the fastest but least secure, as the block could be orphaned. Best for non-critical, time-sensitive actions.</li><li>**`evm.ConfidenceLevel_CONFIDENCE_LEVEL_FINALIZED`:** A block that is considered irreversible. This is the safest option, as the event is guaranteed to be on the canonical chain, but it requires waiting longer for finality.</li></ul> | - -<Aside type="caution" title="SAFE block tag fallback"> - **Some chains do not support the SAFE block tag** (e.g., Shibarium). When you specify `CONFIDENCE_LEVEL_SAFE` on chains that don't support it, CRE automatically falls back to `CONFIDENCE_LEVEL_FINALIZED` for safety. Users are responsible for knowing which chains support the SAFE tag. If you need consistent behavior across all chains, explicitly use `CONFIDENCE_LEVEL_FINALIZED` or `CONFIDENCE_LEVEL_LATEST`. +<Aside type="note" title="Finality details"> + For details on how each confidence level maps to specific chains and estimated wait times, see [Finality and + Confidence Levels](/cre/concepts/finality). </Aside> ### `evm.Log` @@ -14246,6 +15942,59 @@ This section provides a reference for the built-in trigger capabilities of the C --- +# Supported Networks +Source: https://docs.chain.link/cre/supported-networks-go +Last Updated: 2026-02-03 + +This page lists all EVM-compatible networks supported by CRE workflows, along with the minimum CLI and SDK versions required for each network. + +## Version Requirements + +Network support depends on your CLI and SDK versions. The tables below show the minimum versions required for each network. + +- **New projects:** Run `cre update` to get the latest CLI, which includes compatible SDK versions. +- **Existing projects:** You may need to update your SDK dependency. See [Updating Dependencies](/cre/reference/project-configuration-go#5-updating-dependencies) for instructions. + +## Mainnets + +| Network | CLI | Go SDK | TS SDK | +| ------------ | ------ | ------ | ------ | +| Arbitrum One | v1.0.0 | v1.0.0 | v1.0.1 | +| Avalanche | v1.0.0 | v1.0.0 | v1.0.1 | +| Base | v1.0.0 | v1.0.0 | v1.0.1 | +| BNB Chain | v1.0.0 | v1.0.0 | v1.0.1 | +| Ethereum | v1.0.0 | v1.0.0 | v1.0.1 | +| OP Mainnet | v1.0.0 | v1.0.0 | v1.0.1 | +| Polygon | v1.0.0 | v1.0.0 | v1.0.1 | +| ZKSync Era | v1.0.6 | v1.1.3 | v1.0.7 | + +## Testnets + +| Network | CLI | Go SDK | TS SDK | +| ------------------- | ------ | ------ | ------ | +| Apechain Curtis | v1.0.7 | v1.1.4 | v1.0.7 | +| Arc Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Arbitrum Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Avalanche Fuji | v1.0.0 | v1.0.0 | v1.0.1 | +| Base Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| BNB Chain Testnet | v1.0.0 | v1.0.0 | v1.0.1 | +| Ethereum Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Hyperliquid Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Ink Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| Jovay Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Linea Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| OP Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Plasma Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Polygon Amoy | v1.0.0 | v1.0.0 | v1.0.1 | +| World Chain Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| ZKSync Era Sepolia | v1.0.6 | v1.1.2 | v1.0.7 | + +## Forwarder Addresses + +For forwarder contract addresses and chain names, see the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). Forwarder addresses are used when building consumer contracts that receive workflow reports onchain. Learn more about [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview). + +--- + # Running a Demo Workflow Source: https://docs.chain.link/cre/templates/running-demo-workflow-go Last Updated: 2025-11-04 @@ -14370,7 +16119,7 @@ Now you are ready to compile and run the workflow. The workflow code (`workflow. <Aside type="note" title="Onchain Writes are Dry Runs by Default"> The `--broadcast` flag is included here because this workflow performs an onchain write. By default, the `simulate` command performs a dry run and will not broadcast the transaction without this flag. For more details, see the `cre - workflow simulate` [reference](/cre/reference/cli#cre-workflow-simulate). + workflow simulate` [reference](/cre/reference/cli/workflow#cre-workflow-simulate). </Aside> You will first see a `Workflow compiled` message, followed by the trigger selection menu. diff --git a/src/content/cre/llms-full-ts.txt b/src/content/cre/llms-full-ts.txt index 4281a43711e..2483f6292b0 100644 --- a/src/content/cre/llms-full-ts.txt +++ b/src/content/cre/llms-full-ts.txt @@ -1,6 +1,6 @@ # Chainlink Runtime Environment (CRE) Source: https://docs.chain.link/cre -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 ## What is CRE? @@ -51,14 +51,14 @@ Workflows use a **trigger-and-callback model** to provide a code-first developer 1. **A Trigger**: An event source that starts a workflow execution (e.g., `cron.Trigger`). This is the "when" of your workflow. 2. **A Callback**: A function that contains your business logic. It is inside this function that you will use the SDK's clients to invoke capabilities. This is the "what" of your workflow. -3. **The `cre.handler()`**: The glue that connects a single trigger to a single callback. +3. **The `handler()`**: The glue that connects a single trigger to a single callback. You can define multiple trigger and callback combinations in your workflow. You can also attach the same callback to multiple triggers for reusability. Here's what the trigger-and-callback pattern looks like: ```ts -cre.handler( +handler( cronTrigger.trigger({ schedule: "0 */10 * * * *" }), // trigger fires every 10 minutes onCronTrigger // your callback function ) @@ -102,7 +102,7 @@ Learn more about [Consensus Computing in CRE](/cre/concepts/consensus-computing) | Concept | One-liner | | ------------------ | ----------------------------------------------------------------- | | **Workflow** | Compiled WebAssembly (WASM) binary. | -| **Handler** | `cre.handler(trigger, callback)` pair; the atom of execution. | +| **Handler** | `handler(trigger, callback)` pair; the atom of execution. | | **Trigger** | Event that starts an execution (cron, HTTP, EVM log, …). | | **Callback** | Function that runs when its trigger fires; contains your logic. | | **Runtime** | Object passed to a callback; used to invoke capabilities. | @@ -249,7 +249,7 @@ The mechanism by which a DON comes to a single, reliable, and tamper-proof resul # Service Quotas Source: https://docs.chain.link/cre/service-quotas -Last Updated: 2025-11-04 +Last Updated: 2025-12-18 This page documents the service quotas for Chainlink Runtime Environment (CRE) workflows. @@ -261,15 +261,10 @@ This page documents the service quotas for Chainlink Runtime Environment (CRE) w These quotas apply to each workflow owner (user account) within an organization. -| Quota | Description | Value | -| ------------------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------- | -| Workflow Deployment Rate | Maximum rate at which an organization can deploy new workflows | Rate: 1 per minute <br /> Burst: 1 | -| Concurrent Workflow Executions | Maximum number of workflows that can execute simultaneously | 5 | -| Workflow Trigger Rate | Maximum rate at which triggers can fire for all workflows owned by a single owner (user account) | Rate: 5 per second <br /> Burst: 5 | -| Workflow Binary Size | Maximum size of the compiled WASM binary | 100 MB | -| Workflow Compressed Binary Size | Maximum size of the compressed WASM binary | 20 MB | -| Workflow Configuration Size | Maximum size of the workflow configuration | 1 MB | -| Secrets Size | Maximum total size of secrets accessible to a workflow | 1 MB | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | ----- | +| <a href="#perowner-workflowexecutionconcurrencylimit" id="perowner-workflowexecutionconcurrencylimit">`PerOwner.WorkflowExecutionConcurrencyLimit`</a> | Maximum number of workflows that can execute simultaneously | 5 | +| <a href="#perowner-vaultsecretslimit" id="perowner-vaultsecretslimit">`PerOwner.VaultSecretsLimit`</a> | Maximum number of secrets that can be stored per owner | 100 | <Aside type="note" title="Quota enforcement"> When workflow executions exceed the quotas defined above, they are queued and automatically retried for up to 10 @@ -280,57 +275,64 @@ These quotas apply to each workflow owner (user account) within an organization. These quotas apply to each individual workflow. +### Workflow deployment quotas + +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------ | +| <a href="#perworkflow-wasmbinarysizelimit" id="perworkflow-wasmbinarysizelimit">`PerWorkflow.WASMBinarySizeLimit`</a> | Maximum size of the compiled WASM binary | 100 MB | +| <a href="#perworkflow-wasmcompressedbinarysizelimit" id="perworkflow-wasmcompressedbinarysizelimit">`PerWorkflow.WASMCompressedBinarySizeLimit`</a> | Maximum size of the compressed WASM binary | 20 MB | +| <a href="#perworkflow-wasmconfigsizelimit" id="perworkflow-wasmconfigsizelimit">`PerWorkflow.WASMConfigSizeLimit`</a> | Maximum size of the workflow configuration | 1 MB | + ### Trigger quotas -| Quota | Description | Value | -| ----------------------------- | ---------------------------------------------------------------------- | -------------------------------------- | -| Trigger Rate | Maximum rate at which a workflow's triggers can fire | Rate: 1 per 30 seconds <br /> Burst: 3 | -| Maximum Triggers per Workflow | Maximum number of triggers that can be registered to a single workflow | 10 | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | ----- | +| <a href="#perworkflow-triggersubscriptionlimit" id="perworkflow-triggersubscriptionlimit">`PerWorkflow.TriggerSubscriptionLimit`</a> | Maximum number of triggers that can be registered to a single workflow | 10 | ### Execution quotas -| Quota | Description | Value | -| ----------------------------- | --------------------------------------------------------------- | ----------------- | -| Concurrent Workflow Instances | Maximum number of concurrent executions for a specific workflow | 5 <br /> Burst: 5 | -| Workflow Timeout | Maximum total execution time for a single workflow run | 5 minutes | -| Workflow Memory Allocation | Maximum memory allocated to a workflow | 100 MB | -| Response Size | Maximum size of the data a workflow can return | 100 KB | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | --------- | +| <a href="#perworkflow-executionconcurrencylimit" id="perworkflow-executionconcurrencylimit">`PerWorkflow.ExecutionConcurrencyLimit`</a> | Maximum number of concurrent executions for a specific workflow | 5 | +| <a href="#perworkflow-executiontimeout" id="perworkflow-executiontimeout">`PerWorkflow.ExecutionTimeout`</a> | Maximum total execution time for a single workflow run | 5 minutes | +| <a href="#perworkflow-wasmmemorylimit" id="perworkflow-wasmmemorylimit">`PerWorkflow.WASMMemoryLimit`</a> | Maximum memory allocated to a workflow | 100 MB | +| <a href="#perworkflow-executionresponselimit" id="perworkflow-executionresponselimit">`PerWorkflow.ExecutionResponseLimit`</a> | Maximum size of the data a workflow can return | 100 KB | -### Capability call quotas +### General capability quotas -| Quota | Description | Value | -| --------------------------- | ------------------------------------------------------------------------------------------------------ | --------- | -| Concurrent Capability Calls | Maximum concurrent capability calls (HTTP, EVM read/write, secrets) that can execute within a workflow | 3 | -| Capability Call Timeout | Maximum time a single capability call can take to complete | 3 minutes | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | --------- | +| <a href="#perworkflow-capabilityconcurrencylimit" id="perworkflow-capabilityconcurrencylimit">`PerWorkflow.CapabilityConcurrencyLimit`</a> | Maximum concurrent capability calls (HTTP, EVM read/write, secrets) that can execute within a workflow | 3 | +| <a href="#perworkflow-capabilitycalltimeout" id="perworkflow-capabilitycalltimeout">`PerWorkflow.CapabilityCallTimeout`</a> | Maximum time a single capability call can take to complete | 3 minutes | ### Secrets quotas -| Quota | Description | Value | -| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----- | -| Secrets Size | Maximum total size of secrets accessible to a workflow | 1 MB | -| Concurrent Secrets Fetches | Maximum number of secrets that can be fetched concurrently. [Learn how to fetch multiple secrets](/cre/guides/workflow/secrets). | 5 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----- | +| <a href="#perworkflow-wasmsecreetssizelimit" id="perworkflow-wasmsecreetssizelimit">`PerWorkflow.WASMSecretsSizeLimit`</a> | Maximum total size of secrets accessible to a workflow | 1 MB | +| <a href="#perworkflow-secretsconcurrencylimit" id="perworkflow-secretsconcurrencylimit">`PerWorkflow.SecretsConcurrencyLimit`</a> | Maximum number of secrets that can be fetched concurrently. [Learn how to fetch multiple secrets](/cre/guides/workflow/secrets). | 5 | ### Consensus quotas -| Quota | Description | Value | -| --------------------- | ---------------------------------------------------------------- | ------ | -| Observation Size | Maximum size of data that can be passed to consensus aggregation | 100 KB | -| Total Consensus Calls | Maximum number of consensus calls per workflow execution | 2,000 | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | ----- | +| <a href="#perworkflow-consensus-observationsizelimit" id="perworkflow-consensus-observationsizelimit">`PerWorkflow.Consensus.ObservationSizeLimit`</a> | Maximum size of data that can be passed to consensus aggregation | 25 KB | +| <a href="#perworkflow-consensus-calllimit" id="perworkflow-consensus-calllimit">`PerWorkflow.Consensus.CallLimit`</a> | Maximum number of consensus calls per workflow execution | 2,000 | ### Logging quotas -| Quota | Description | Value | -| ------------- | --------------------------------------------------- | ----- | -| Log Line Size | Maximum size of a single log line | 1 KB | -| Log Events | Maximum number of log events per workflow execution | 1,000 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ----- | +| <a href="#perworkflow-loglinelimit" id="perworkflow-loglinelimit">`PerWorkflow.LogLineLimit`</a> | Maximum size of a single log line | 1 KB | +| <a href="#perworkflow-logeventlimit" id="perworkflow-logeventlimit">`PerWorkflow.LogEventLimit`</a> | Maximum number of log events per workflow execution | 1,000 | ## Trigger-specific quotas ### Cron trigger -| Quota | Description | Value | -| ------------ | --------------------------------------------- | -------------------------------------- | -| Trigger Rate | Maximum rate at which a cron trigger can fire | Rate: 1 per 30 seconds <br /> Burst: 1 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ---------- | +| <a href="#perworkflow-crontrigger-fastestscheduleinterval" id="perworkflow-crontrigger-fastestscheduleinterval">`PerWorkflow.CRONTrigger.FastestScheduleInterval`</a> | Minimum interval between cron trigger fires | 30 seconds | <Aside type="note" title="Minimum cron schedule"> While the rate quota allows firing once per 30 seconds, you should consider the [Concurrent Workflow @@ -339,47 +341,46 @@ These quotas apply to each individual workflow. ### HTTP trigger -| Quota | Description | Value | -| ------------ | ---------------------------------------------- | -------------------------------------- | -| Trigger Rate | Maximum rate at which an HTTP trigger can fire | Rate: 1 per 30 seconds <br /> Burst: 3 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | -------------------------------------- | +| <a href="#perworkflow-httptrigger-ratelimit" id="perworkflow-httptrigger-ratelimit">`PerWorkflow.HTTPTrigger.RateLimit`</a> | Maximum rate at which an HTTP trigger can fire | Rate: 1 per 30 seconds <br /> Burst: 3 | ### EVM log trigger -| Quota | Description | Value | -| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | -| Maximum Log Triggers | Maximum number of EVM log triggers per workflow | 5 | -| Event Rate | Maximum rate at which log events can be processed | Rate: 10 per 6 seconds <br /> Burst: 10 | -| Filter Addresses | Maximum number of contract addresses that can be monitored | 5 | -| Filter Topics per Slot | Maximum number of topic values that can be specified within a single topic position (Topics[0], Topics[1], Topics[2], or Topics[3]). [Learn about topic filtering](/cre/guides/workflow/using-triggers/evm-log-trigger). | 10 | -| Event Size | Maximum size of a single log event | 5 KB | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | +| <a href="#perworkflow-logtrigger-eventratelimit" id="perworkflow-logtrigger-eventratelimit">`PerWorkflow.LogTrigger.EventRateLimit`</a> | Maximum rate at which log events can be processed | Rate: 10 per 6 seconds <br /> Burst: 10 | +| <a href="#perworkflow-logtrigger-filteraddresslimit" id="perworkflow-logtrigger-filteraddresslimit">`PerWorkflow.LogTrigger.FilterAddressLimit`</a> | Maximum number of contract addresses that can be monitored | 5 | +| <a href="#perworkflow-logtrigger-filtertopicsperslotlimit" id="perworkflow-logtrigger-filtertopicsperslotlimit">`PerWorkflow.LogTrigger.FilterTopicsPerSlotLimit`</a> | Maximum number of topic values that can be specified within a single topic position (Topics[0], Topics[1], Topics[2], or Topics[3]). [Learn about topic filtering](/cre/guides/workflow/using-triggers/evm-log-trigger). | 10 | +| <a href="#perworkflow-logtrigger-eventsizelimit" id="perworkflow-logtrigger-eventsizelimit">`PerWorkflow.LogTrigger.EventSizeLimit`</a> | Maximum size of a single log event | 5 KB | ## Capability-specific quotas ### EVM write capability -| Quota | Description | Value | -| --------------------- | --------------------------------------------------------- | --------- | -| Target Chains | Maximum number of destination chains for write operations | 10 | -| Report Size | Maximum size of a report payload | 5 KB | -| Transaction Gas Quota | Gas quota per EVM transaction | 5,000,000 | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | --------- | +| <a href="#perworkflow-chainwrite-targetslimit" id="perworkflow-chainwrite-targetslimit">`PerWorkflow.ChainWrite.TargetsLimit`</a> | Maximum number of destination chains for write operations | 10 | +| <a href="#perworkflow-chainwrite-reportsizelimit" id="perworkflow-chainwrite-reportsizelimit">`PerWorkflow.ChainWrite.ReportSizeLimit`</a> | Maximum size of a report payload | 5 KB | +| <a href="#perworkflow-chainwrite-evm-transactiongaslimit" id="perworkflow-chainwrite-evm-transactiongaslimit">`PerWorkflow.ChainWrite.EVM.TransactionGasLimit`</a> | Gas quota per EVM transaction | 5,000,000 | ### EVM read capability -| Quota | Description | Value | -| ------------------------ | ---------------------------------------------------------------- | ----- | -| Read Calls per Execution | Maximum number of EVM read calls per workflow execution | 10 | -| Log Query Block Quota | Maximum number of blocks that can be queried for historical logs | 100 | -| Payload Size | Maximum size of an EVM read request payload | 5 KB | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | ----- | +| <a href="#perworkflow-chainread-calllimit" id="perworkflow-chainread-calllimit">`PerWorkflow.ChainRead.CallLimit`</a> | Maximum number of EVM read calls per workflow execution | 10 | +| <a href="#perworkflow-chainread-logqueryblocklimit" id="perworkflow-chainread-logqueryblocklimit">`PerWorkflow.ChainRead.LogQueryBlockLimit`</a> | Maximum number of blocks that can be queried for historical logs | 100 | +| <a href="#perworkflow-chainread-payloadsizelimit" id="perworkflow-chainread-payloadsizelimit">`PerWorkflow.ChainRead.PayloadSizeLimit`</a> | Maximum size of an EVM read request payload | 5 KB | ### HTTP capability -| Quota | Description | Value | -| ------------------------ | ------------------------------------------------------ | ---------- | -| HTTP Calls per Execution | Maximum number of HTTP requests per workflow execution | 5 | -| Response Size | Maximum size of an HTTP response | 10 KB | -| Connection Timeout | Maximum time to establish an HTTP connection | 10 seconds | -| Request Size | Maximum size of an HTTP request payload | 100 KB | -| Cache Age | Maximum time HTTP responses can be cached | 10 minutes | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------ | ---------- | +| <a href="#perworkflow-httpaction-calllimit" id="perworkflow-httpaction-calllimit">`PerWorkflow.HTTPAction.CallLimit`</a> | Maximum number of HTTP requests per workflow execution | 5 | +| <a href="#perworkflow-httpaction-responsesizelimit" id="perworkflow-httpaction-responsesizelimit">`PerWorkflow.HTTPAction.ResponseSizeLimit`</a> | Maximum size of an HTTP response | 100 KB | +| <a href="#perworkflow-httpaction-connectiontimeout" id="perworkflow-httpaction-connectiontimeout">`PerWorkflow.HTTPAction.ConnectionTimeout`</a> | Maximum time to establish an HTTP connection | 10 seconds | +| <a href="#perworkflow-httpaction-requestsizelimit" id="perworkflow-httpaction-requestsizelimit">`PerWorkflow.HTTPAction.RequestSizeLimit`</a> | Maximum size of an HTTP request payload | 10 KB | +| <a href="#perworkflow-httpaction-cacheagelimit" id="perworkflow-httpaction-cacheagelimit">`PerWorkflow.HTTPAction.CacheAgeLimit`</a> | Maximum time HTTP responses can be cached | 10 minutes | ## Quota increases @@ -441,15 +442,173 @@ To help us assist you faster, please include: # Release Notes Source: https://docs.chain.link/cre/release-notes -Last Updated: 2025-11-20 +Last Updated: 2026-02-10 This page provides detailed release notes for CRE. It includes information on new features, significant changes, and known limitations. +## CLI v1.0.10 - February 9, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.10" target="_blank">CRE CLI version 1.0.10</a> is now available.** + +- **Bug Fix**: Fixed secret injection for the [Confidential HTTP](/cre/capabilities/confidential-http) capability in the simulator — template placeholders (`{{.secretName}}`) now resolve correctly during `cre workflow simulate` +- **Bug Fix**: Fixed project context not being set before writing changeset files + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.9...v1.0.10) + +## CLI v1.0.9 - February 6, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.9" target="_blank">CRE CLI version 1.0.9</a> is now available.** + +- **Confidential HTTP (Experimental)**: Added [Confidential HTTP](/cre/capabilities/confidential-http) capability support in the simulator. You can now simulate workflows that use privacy-preserving API calls with secret injection and optional response encryption. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.8...v1.0.9) + +## CLI v1.0.8 - February 6, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.8" target="_blank">CRE CLI version 1.0.8</a> is now available.** + +- Changed `chain-id` to `chain-selector` in simulator settings +- Support for longer workflow names +- Fixed a logic bug in the template contract `MessageEmitter.sol` + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.7...v1.0.8) + +## New Networks Support - January 29, 2026 + +CRE now supports additional testnets for workflow simulation and production deployment: + +- Apechain Curtis +- Arc Testnet +- Hyperliquid Testnet +- Ink Sepolia +- Jovay Testnet +- Linea Sepolia +- Plasma Testnet +- World Chain Sepolia + +**Required versions:** CLI v1.0.7+, Go SDK v1.1.4+, TS SDK v1.0.7+ + +## CLI v1.0.7 - January 29, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.7" target="_blank">CRE CLI version 1.0.7</a> is now available.** + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.6...v1.0.7) + +## TS SDK v1.0.7 - January 29, 2026 + +**TypeScript SDK version 1.0.7** includes internal improvements. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.5...v1.0.7) + +## TS SDK v1.0.5 - January 28, 2026 + +- **Bug Fix**: Fixed an issue with `runtime.now()` returning incorrect timestamps + +For details on using time in workflows, see [Time in CRE](/cre/guides/workflow/time-in-workflows-ts). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.4...v1.0.5) + +## ZKSync Era Support - January 26, 2026 + +CRE now supports **ZKSync Era mainnet and testnet** for workflow simulation and production deployment. You can now build and test workflows that interact with ZKSync Era chains. + +**Required versions:** CLI v1.0.6+, Go SDK v1.1.3+ (mainnet) / v1.1.2+ (testnet), TS SDK v1.0.7+ + +## TS SDK v1.0.4 - January 26, 2026 + +**TypeScript SDK version 1.0.4** includes internal improvements. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.3...v1.0.4) + +## CLI v1.0.6 - January 21, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.6" target="_blank">CRE CLI version 1.0.6</a> is now available.** + +- **ZKSync Era support**: Added ZKSync Era testnet and mainnet to the simulator + +This release also includes various small improvements and bug fixes, such as better error messages when hitting workflow limits. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +## TS SDK v1.0.3 - January 19, 2026 + +- **Bug Fixes**: Fixed issue where workflows could execute twice during simulation + +- **Examples Updated**: All workflow examples in the SDK repository now use **direct imports** (e.g., `import { HTTPClient } from "@chainlink/cre-sdk"`) instead of the namespace pattern (e.g., `cre.capabilities.HTTPClient`). Both patterns remain fully supported—choose whichever fits your coding style. See [Import styles](/cre/reference/sdk/core-ts#import-styles) for details. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.2...v1.0.3) + +## TS SDK v1.0.2 - January 16, 2026 + +**TypeScript SDK version 1.0.2** introduces several improvements to developer experience: + +**New features:** + +- **Optional `main()` call**: You no longer need to call `main()` at the end of your workflow files. The SDK now automatically executes the `main()` function during compilation. See [`main()` reference](/cre/reference/sdk/core-ts#main) for details. +- **Automatic error handling**: If you don't provide custom error handling, the SDK automatically adds `.catch(sendErrorResponse)` to your workflow's `main()` function. This ensures errors are properly reported instead of silently failing. +- **Direct imports**: You can now import SDK components directly (e.g., `import { HTTPClient } from "@chainlink/cre-sdk"`) instead of accessing them through the `cre` namespace (e.g., `cre.capabilities.HTTPClient`). Both import styles remain supported for backward compatibility. See [Import styles](/cre/reference/sdk/core-ts#import-styles) for details and guidance on when to use each pattern. + +**Migration notes:** + +- **Custom error handling**: If you need custom error handling, you can still add your own `.catch()` handler: `main().catch(myCustomHandler)`. The SDK will respect your custom handler and not override it. See [`main()` reference](/cre/reference/sdk/core-ts#main) for examples. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.1...v1.0.2) + +## CLI v1.0.5 - January 13, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.5" target="_blank">CRE CLI version 1.0.5</a> is now available.** This release includes various small improvements and bug fixes. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +## CLI v1.0.4 - January 9, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.4" target="_blank">CRE CLI version 1.0.4</a> is now available.** This release includes various small improvements and bug fixes. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +## CLI v1.0.3 - December 12, 2025 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.3" target="_blank">CRE CLI version 1.0.3</a> is now available.** This release includes various small improvements and bug fixes. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + ## CLI v1.0.2 - November 20, 2025 **<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.2" target="_blank">CRE CLI version 1.0.2</a> is now available.** This release includes various improvements based on user feedback. -### How to update +**How to update:** - **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. - **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). @@ -529,9 +688,9 @@ These guides explain how to install the Chainlink Developer Platform CLI (also r # Installing the CRE CLI on macOS and Linux Source: https://docs.chain.link/cre/getting-started/cli-installation/macos-linux -Last Updated: 2025-11-20 +Last Updated: 2026-02-10 -This page explains how to install the CRE CLI on macOS or Linux. The recommended version at the time of writing is **v1.0.2**. +This page explains how to install the CRE CLI on macOS or Linux. The recommended version at the time of writing is **v1.0.10**. ## Installation @@ -545,7 +704,7 @@ Choose your installation method: The easiest way to install the CRE CLI is using the installation script: ```bash -curl -sSL https://cre.chain.link/install.sh | sh +curl -sSL https://cre.chain.link/install.sh | bash ``` This script will: @@ -553,7 +712,7 @@ This script will: - Detect your operating system and architecture automatically - Download the correct binary for your system - Verify the binary's integrity -- Install it to `/usr/local/bin` (or prompt you for a custom location) +- Install it to `$HOME/.cre` - Make the binary executable After the script completes, verify the installation: @@ -562,7 +721,7 @@ After the script completes, verify the installation: cre version ``` -**Expected output:** `cre version v1.0.2` +**Expected output:** `cre version v1.0.10` <Aside type="note" title="macOS Gatekeeper"> If you see warnings about "unrecognized developer/source" on macOS, run:{" "} @@ -580,9 +739,15 @@ The CRE CLI is publicly available on GitHub. Visit the releases page and downloa - On **macOS** (darwin), run <CopyText text="uname -m" code />: - `arm64` (Apple Silicon) → Download `cre_darwin_arm64.zip` - `x86_64` (Intel) → Download `cre_darwin_amd64.zip` - - On **Linux**, run <CopyText text="uname -m" code />: - - `aarch64` (ARM) → Download `cre_linux_arm64.tar.gz` - - `x86_64` (AMD/Intel) → Download `cre_linux_amd64.tar.gz` + - On **Linux**, the binary depends on both your architecture and OS version. First, run <CopyText text="uname -m" code /> to check your architecture, then <CopyText text="lsb_release -rs" code /> to check your Ubuntu version: + - **Ubuntu 22.04 or older**: + - `x86_64` (AMD/Intel) → Download `cre_linux_amd64_ldd2-35.tar.gz` + - `aarch64` (ARM) → Download `cre_linux_arm64_ldd2-35.tar.gz` + - **Ubuntu 24.04 or newer**: + - `x86_64` (AMD/Intel) → Download `cre_linux_amd64.tar.gz` + - `aarch64` (ARM) → Download `cre_linux_arm64.tar.gz` + + **Note:** The `ldd2-35` binaries are compiled for older glibc versions (2.35 and below). If you're using a non-Ubuntu Linux distribution, check your glibc version with <CopyText text="ldd --version" code /> and use the `ldd2-35` binary if your version is 2.35 or lower. </Aside> After downloading the correct file from the releases page, move on to the next step to verify its integrity. @@ -601,16 +766,21 @@ shasum -a 256 cre_darwin_arm64.zip **Verify against official checksums** -Compare the output with the official checksum below: +Compare the output with the official checksum from the [CRE CLI releases page](https://github.com/smartcontractkit/cre-cli/releases): + +1. Go to [https://github.com/smartcontractkit/cre-cli/releases](https://github.com/smartcontractkit/cre-cli/releases) +2. Find the release version you downloaded (e.g., v1.0.10) +3. Under the **Assets** section, locate your downloaded file +4. Compare the SHA-256 checksum shown next to the file with your command output -| File | SHA-256 Checksum | -| ------------------------ | ---------------------------------------------------------------- | -| `cre_darwin_amd64.zip` | 482e53d3a5f8471034d30c935196d2dca2ab09a5fe1ab2083ad336172565291b | -| `cre_darwin_arm64.zip` | 92b0409801dd4e44f90a85331615f3e4b8cf1fe9f90a8eab3ad8bb3458b4b6cf | -| `cre_linux_amd64.tar.gz` | d3a8b9b999b4b8bf73b2235d27386acf4efbc8f05d86d9e6066abda23ee9ce9b | -| `cre_linux_arm64.tar.gz` | f52d618727ccc8fb6ab4b1f9418b09424c8505428131a49c01bb33ca2bc86fe3 | +**Example:** For `cre_darwin_arm64.zip` in release v1.0.10, you'll see something like: + +``` +cre_darwin_arm64.zip +sha256:1359415a1f1baee7643107b82b3a0589a3627aef71018644e5c488960a97e955 +``` -If the checksum doesn't match, do not proceed with installation. Contact your Chainlink point of contact for assistance. +If the checksums match, the file is authentic and safe to install. If they don't match, do not proceed with installation and contact the Chainlink team for assistance. #### 2. Extract and install @@ -633,7 +803,7 @@ If the checksum doesn't match, do not proceed with installation. Contact your Ch 3. **Rename the extracted binary to `cre`** ```bash - mv cre_v1.0.2_darwin_arm64 cre + mv cre_v1.0.10_darwin_arm64 cre ``` 4. **Make it executable**: @@ -706,13 +876,13 @@ cre version **Expected output:** -You should see version information: `cre version v1.0.2`. +You should see version information: `cre version v1.0.10`. **If it doesn't work:** - Make sure you opened a **new terminal window** after making PATH changes -- Check the binary location: `which cre` should return `/usr/local/bin/cre` (or your custom path) -- Check that the binary has execute permissions: `ls -la /usr/local/bin/cre` +- Check the binary location: `which cre` should return the path to your installation +- Check that the binary has execute permissions: `ls -la $(which cre)` - Verify your PATH includes the correct directory: `echo $PATH` #### 5. Confirm your PATH (troubleshooting) @@ -743,9 +913,9 @@ Once you're authenticated, you're ready to build your first workflow: # Installing the CRE CLI on Windows Source: https://docs.chain.link/cre/getting-started/cli-installation/windows -Last Updated: 2025-11-20 +Last Updated: 2026-02-10 -This page explains how to install the Chainlink Developer Platform CLI (also referred to as the CRE CLI) on Windows. The recommended version at the time of writing is **v1.0.2**. +This page explains how to install the Chainlink Developer Platform CLI (also referred to as the CRE CLI) on Windows. The recommended version at the time of writing is **v1.0.10**. ## Installation @@ -766,7 +936,7 @@ This script will: - Download the correct binary for Windows - Verify the binary's integrity -- Install it to a location in your PATH +- Install it to `$env:LOCALAPPDATA\Programs\cre` - Make the binary executable After the script completes, **open a new PowerShell window** and verify the installation: @@ -775,7 +945,7 @@ After the script completes, **open a new PowerShell window** and verify the inst cre version ``` -**Expected output:** `cre version v1.0.2` +**Expected output:** `cre version v1.0.10` ### Manual installation @@ -799,20 +969,28 @@ Get-FileHash cre_windows_amd64.zip -Algorithm SHA256 **Verify against the official checksum** -Compare the `Hash` value in the output with the official checksum below: +Compare the `Hash` value in the output with the official checksum from the [CRE CLI releases page](https://github.com/smartcontractkit/cre-cli/releases): + +1. Go to [https://github.com/smartcontractkit/cre-cli/releases](https://github.com/smartcontractkit/cre-cli/releases) +2. Find the release version you downloaded (e.g., v1.0.10) +3. Under the **Assets** section, locate `cre_windows_amd64.zip` +4. Compare the SHA-256 checksum shown next to the file with the `Hash` value from your PowerShell output -| File | SHA-256 Checksum | -| ----------------------- | ---------------------------------------------------------------- | -| `cre_windows_amd64.zip` | 60fe65b74619c4164c0a9d6442611bf8537a04a6daf1ed3ecefc608cbbffdb01 | +**Example:** For `cre_windows_amd64.zip` in release v1.0.10, you'll see something like: + +``` +cre_windows_amd64.zip +sha256:372d16566479ff6bbfe9eb1d5cebe0e1e2a3c67062c6f0439fc96c735ddeaa18 +``` -If the checksum doesn't match, do not proceed with installation. Contact your Chainlink point of contact for assistance. +If the checksums match, the file is authentic and safe to install. If they don't match, do not proceed with installation and contact the Chainlink team for assistance. #### 2. Extract and install 1. Navigate to the directory where you downloaded the archive. 2. Right-click the `.zip` file and select **Extract All...**. 3. Choose a permanent location for the extracted folder (e.g., `C:\Program Files\cre-cli`). -4. Inside the extracted folder, rename the file `cre_v1.0.2_windows_amd64.exe` to `cre.exe`. +4. Inside the extracted folder, rename the file `cre_v1.0.10_windows_amd64.exe` to `cre.exe`. #### 3. Add the CLI to your PATH @@ -837,7 +1015,7 @@ Open a new **PowerShell** or **Command Prompt** window and run: cre version ``` -You should see version information: `cre version v1.0.2`. +You should see version information: `cre version v1.0.10`. ## Next steps @@ -852,116 +1030,6 @@ Once you're authenticated, you're ready to build your first workflow: --- -# Conclusion & Next Steps -Source: https://docs.chain.link/cre/getting-started/conclusion -Last Updated: 2025-11-04 - -You've built a complete, end-to-end CRE workflow from scratch. - -You started with an empty project and progressively built a workflow that: - -- Fetches data from an offchain API with consensus -- Reads values from a smart contract -- Performs calculations combining onchain and offchain data -- Writes results back to the blockchain - -**This is no small achievement.** You've mastered the core pattern that powers most CRE workflows: the trigger-and-callback model with capabilities for HTTP, EVM, and consensus. - -## What's next? - -Now that you have a working workflow, here's your natural progression from simulation to production and beyond. - -### 1. See a complete example - -Ready to see all these concepts in a more complex, real-world scenario? - -- **[Run the Custom Data Feed Demo](/cre/templates/running-demo-workflow)** - Explore an advanced template that combines multiple capabilities - -**Why this matters:** Templates show production-ready patterns. - -### 2. Deploy your Calculator workflow to Production - -You've simulated your workflow locally. **The logical next step is to deploy it to the CRE production environment** so it runs across a Decentralized Oracle Network (DON). - - -<Aside type="note" title="Deployment access required"> - - Deploying workflows requires Early Access approval. If you don't have deployment access yet, <a href="https://cre.chain.link/request-access" target="_blank" rel="noopener noreferrer">request it here</a>. - - **While you wait:** Continue building and simulating workflows using [`cre workflow simulate`](/cre/guides/operations/simulating-workflows). -</Aside> - -**Follow this deployment sequence:** - -1. **[Link a Wallet Key](/cre/organization/linking-keys)** - Connect your wallet address to your organization (required before deployment) -2. **[Deploy Your Workflow](/cre/guides/operations/deploying-workflows)** - Push your calculator workflow live -3. **[Monitor Your Workflow](/cre/guides/operations/monitoring-workflows)** - Watch it execute in production and debug any issues - -**Why this matters:** Deploying moves your workflow from local simulation to production execution across a DON. - -### 3. Explore different triggers - -You used a **Cron trigger** (time-based). **Most production workflows react to real-world events.** - -**Try these next:** - -- **[HTTP Trigger](/cre/guides/workflow/using-triggers/http-trigger/overview)** - Let external systems trigger your workflow via API calls -- **[EVM Log Trigger](/cre/guides/workflow/using-triggers/evm-log-trigger)** - React to onchain events (e.g., token transfers, contract events) - -**Why this matters:** Event-driven workflows are more powerful than scheduled ones. They respond instantly to real-world changes. - -### 4. Add secrets - -Your calculator used a public API. **Real workflows often need API keys and other sensitive data.** - -**Learn how to secure your secrets:** - -- **[Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation)** - Store secrets in your local environment for development -- **[Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed)** - Store secrets in the Vault DON for production -- **[Managing Secrets with 1Password](/cre/guides/workflow/secrets/managing-secrets-1password)** - Best practice: inject secrets at runtime - -**Why this matters:** Hardcoded credentials are a security risk. CRE's secrets management lets you safely use authenticated APIs and private keys. - -### 5. Build your own consumer contract - -You used a **pre-deployed consumer contract**. **For production workflows, you'll create custom contracts tailored to your use case.** - -**Learn the secure pattern:** - -- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)** - Create contracts that safely receive CRE data - -**Why this matters:** Consumer contracts enforce business logic and validation onchain, enabling trustless and verifiable execution. - -## Reference: Deepen Your Understanding - -Want to dive deeper into specific concepts from the Getting Started guide? Use this section as a quick reference. - -**Workflow Structure & Triggers** - -- **[Core SDK Reference](/cre/reference/sdk/core/)** - Fundamental building blocks (`InitWorkflow`, `Handler`, `Runtime`) -- **[Triggers Overview](/cre/guides/workflow/using-triggers/overview)** - Compare all available event sources - -**HTTP & Offchain Data** - -- **[API Interactions Guide](/cre/guides/workflow/using-http-client/)** - Complete patterns for HTTP requests -- **[Consensus & Aggregation](/cre/reference/sdk/consensus)** - All aggregation methods (median, mode, custom) -- **[Consensus Computing Concept](/cre/concepts/consensus-computing)** - How CRE's consensus-based execution works - -**EVM & Onchain Interactions** - -- **[EVM Client Overview](/cre/guides/workflow/using-evm-client/overview)** - Introduction to smart contract interactions -- **[Onchain Read Guide](/cre/guides/workflow/using-evm-client/onchain-read)** - Reading from a smart contract -- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write)** - Complete write patterns and report generation - -**Configuration & Secrets** - -- **[Project Configuration](/cre/reference/project-configuration/)** - Complete guide to `project.yaml`, `workflow.yaml`, and targets -- **[Secrets Guide](/cre/guides/workflow/secrets)** - All secrets management patterns - -**All Capabilities** - -- **[Capabilities Overview](/cre/capabilities/)** - See the full list of CRE capabilities and how they work together - ---- - # Using Triggers Source: https://docs.chain.link/cre/guides/workflow/using-triggers/overview Last Updated: 2025-11-04 @@ -1045,8 +1113,9 @@ cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --htt ``` <Aside type="note" title="Non-interactive requirements"> - The `--http-payload` flag requires `--non-interactive` mode. You must also specify `--trigger-index` (0-based index of - your HTTP trigger). If your HTTP trigger is the only trigger or the first one defined, use `--trigger-index 0`. + The `--http-payload` flag requires `--non-interactive` mode. You must also specify `--trigger-index` to select which + handler to run. The index is 0-based: if the handler with your HTTP trigger is the first handler defined in your + `InitWorkflow` function, use `--trigger-index 0`; if it's the second, use `--trigger-index 1`, and so on. </Aside> <Aside type="note" title="Escaping quotes"> @@ -1114,7 +1183,7 @@ This configuration sets the minimum purchase amount to 10, which we'll test with **Workflow code:** ```ts -import { cre, type Runtime, type HTTPPayload, Runner, decodeJson } from "@chainlink/cre-sdk" +import { HTTPCapability, handler, type Runtime, type HTTPPayload, Runner, decodeJson } from "@chainlink/cre-sdk" type Config = { minimumAmount: number @@ -1147,10 +1216,10 @@ const onHttpTrigger = (runtime: Runtime<Config>, payload: HTTPPayload): string = } const initWorkflow = (config: Config) => { - const http = new cre.capabilities.HTTPCapability() + const http = new HTTPCapability() return [ - cre.handler(http.trigger({}), onHttpTrigger), // Empty config OK for simulation + handler(http.trigger({}), onHttpTrigger), // Empty config OK for simulation ] } @@ -1158,8 +1227,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` **Run the simulation:** @@ -1617,7 +1684,7 @@ Manual JWT generation is complex and error-prone. For development and testing: # Testing with Local JWT Server Source: https://docs.chain.link/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool -Last Updated: 2025-11-04 +Last Updated: 2026-01-14 The <a href="https://github.com/smartcontractkit/cre-sdk-typescript/tree/main/packages/cre-http-trigger" target="_blank" rel="noopener noreferrer">`cre-http-trigger` TypeScript package</a> simplifies testing deployed workflows with HTTP triggers by handling JWT generation, signing, and request formatting automatically. It provides a local HTTP server that acts as a proxy between your test requests and the CRE gateway. @@ -1648,7 +1715,7 @@ The `cre-http-trigger` tool eliminates this complexity by: ## Prerequisites -- **Bun runtime**: The tool requires <a href="https://bun.sh" target="_blank" rel="noopener noreferrer">Bun</a> version 1.2.21 or higher +- **Bun runtime**: The tool requires <a href="https://bun.com" target="_blank" rel="noopener noreferrer">Bun</a> version 1.2.21 or higher - **Deployed workflow**: Your workflow must be deployed with an HTTP trigger - **Workflow ID**: Available from deployment output or the CRE UI - **Private key**: The private key corresponding to one of the `authorizedKeys` in your HTTP trigger configuration @@ -1923,7 +1990,7 @@ This tool is **not intended for production use**. For production integrations: # Building Consumer Contracts Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts -Last Updated: 2025-11-20 +Last Updated: 2026-02-03 When your workflow [writes data to the blockchain](/cre/guides/workflow/using-evm-client/onchain-write), it doesn't call your contract directly. Instead, it submits a signed report to a Chainlink `KeystoneForwarder` contract, which then calls your contract. @@ -1931,12 +1998,13 @@ This guide explains how to build a consumer contract that can securely receive a **In this guide:** -- [Core Concepts: The Onchain Data Flow](#1-core-concepts-the-onchain-data-flow) -- [The IReceiver Standard](#2-the-ireceiver-standard) -- [Using IReceiverTemplate](#3-using-ireceivertemplate) -- [Working with Simulation](#4-working-with-simulation) -- [Advanced Usage](#5-advanced-usage-optional) -- [Complete Examples](#6-complete-examples) +1. [Core Concepts: The Onchain Data Flow](#1-core-concepts-the-onchain-data-flow) +2. [The IReceiver Standard](#2-the-ireceiver-standard) +3. [Using ReceiverTemplate](#3-using-receivertemplate) +4. [Working with Simulation](#4-working-with-simulation) +5. [Advanced Usage](#5-advanced-usage-optional) +6. [Complete Examples](#6-complete-examples) +7. [Security Considerations](#7-security-considerations) ## 1. Core Concepts: The Onchain Data Flow @@ -1953,29 +2021,47 @@ To be a valid target for the `KeystoneForwarder`, your consumer contract must sa The `KeystoneForwarder` needs a standardized function to call. This is defined by the `IReceiver` interface, which mandates an `onReport` function. -```solidity +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC165} from "./IERC165.sol"; + +/// @title IReceiver - receives keystone reports +/// @notice Implementations must support the IReceiver interface through ERC165. interface IReceiver is IERC165 { - function onReport(bytes calldata metadata, bytes calldata report) external; + /// @notice Handles incoming keystone reports. + /// @dev If this function call reverts, it can be retried with a higher gas + /// limit. The receiver is responsible for discarding stale reports. + /// @param metadata Report's metadata. + /// @param report Workflow report. + function onReport( + bytes calldata metadata, + bytes calldata report + ) external; } ``` -- `metadata`: Contains information about the workflow (ID, name, owner). +- `metadata`: Contains information about the workflow (ID, name, owner). This is encoded by the Forwarder using `abi.encodePacked` with the following structure: `bytes32 workflowId`, `bytes10 workflowName`, `address workflowOwner`. - `report`: The raw, ABI-encoded data payload from your workflow. ### 2.2 Support ERC165 Interface Detection [ERC165](https://eips.ethereum.org/EIPS/eip-165) is a standard that allows contracts to publish the interfaces they support. The `KeystoneForwarder` uses this to check if your contract supports the `IReceiver` interface before sending a report. -## 3. Using `IReceiverTemplate` +Link to the `IERC165` interface: [IERC165.sol](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol) + +## 3. Using `ReceiverTemplate` ### 3.1 Overview -While you can implement these standards manually, we provide an abstract contract, `IReceiverTemplate.sol`, that does the heavy lifting for you. Inheriting from it is the recommended best practice. +While you can implement these standards manually, we provide an abstract contract, `ReceiverTemplate.sol`, that does the heavy lifting for you. Inheriting from it is the recommended best practice. **Key features:** -- **Optional Permission Controls**: Choose your security level—enable forwarder address checks, workflow ID validation, workflow owner verification, or any combination -- **Flexible and Updatable**: All permission settings can be configured and updated via setter functions after deployment +- **Secure by Default**: Requires forwarder address at deployment, ensuring your contract is protected from the start +- **Layered Security**: Add optional workflow ID validation, workflow owner verification, or any combination for defense-in-depth +- **Flexible Configuration**: All permission settings can be updated via setter functions after deployment - **Simplified Logic**: You only need to implement `_processReport(bytes calldata report)` with your business logic - **Built-in Access Control**: Includes OpenZeppelin's `Ownable` for secure permission management - **ERC165 Support**: Includes the necessary `supportsInterface` function @@ -1983,7 +2069,7 @@ While you can implement these standards manually, we provide an abstract contrac ### 3.2 Contract Source Code -```solidity +```sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; @@ -1991,159 +2077,267 @@ import {IERC165} from "./IERC165.sol"; import {IReceiver} from "./IReceiver.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -/// @title IReceiverTemplate - Abstract receiver with optional permission controls +/// @title ReceiverTemplate - Abstract receiver with optional permission controls /// @notice Provides flexible, updatable security checks for receiving workflow reports -/// @dev All permission fields default to zero (disabled). Use setter functions to enable checks. -abstract contract IReceiverTemplate is IReceiver, Ownable { - // Optional permission fields (all default to zero = disabled) - address public forwarderAddress; // If set, only this address can call onReport - address public expectedAuthor; // If set, only reports from this workflow owner are accepted - bytes10 public expectedWorkflowName; // If set, only reports with this workflow name are accepted - bytes32 public expectedWorkflowId; // If set, only reports from this specific workflow ID are accepted - - // Custom errors - error InvalidSender(address sender, address expected); - error InvalidAuthor(address received, address expected); - error InvalidWorkflowName(bytes10 received, bytes10 expected); - error InvalidWorkflowId(bytes32 received, bytes32 expected); - - /// @notice Constructor sets msg.sender as the owner - /// @dev All permission fields are initialized to zero (disabled by default) - constructor() Ownable(msg.sender) {} - - /// @inheritdoc IReceiver - /// @dev Performs optional validation checks based on which permission fields are set - function onReport(bytes calldata metadata, bytes calldata report) external override { - // Security Check 1: Verify caller is the trusted Chainlink Forwarder (if configured) - if (forwarderAddress != address(0) && msg.sender != forwarderAddress) { - revert InvalidSender(msg.sender, forwarderAddress); - } +/// @dev The forwarder address is required at construction time for security. +/// Additional permission fields can be configured using setter functions. +abstract contract ReceiverTemplate is IReceiver, Ownable { + // Required permission field at deployment, configurable after + address private s_forwarderAddress; // If set, only this address can call onReport + + // Optional permission fields (all default to zero = disabled) + address private s_expectedAuthor; // If set, only reports from this workflow owner are accepted + bytes10 private s_expectedWorkflowName; // Only validated when s_expectedAuthor is also set + bytes32 private s_expectedWorkflowId; // If set, only reports from this specific workflow ID are accepted + + // Hex character lookup table for bytes-to-hex conversion + bytes private constant HEX_CHARS = "0123456789abcdef"; + + // Custom errors + error InvalidForwarderAddress(); + error InvalidSender(address sender, address expected); + error InvalidAuthor(address received, address expected); + error InvalidWorkflowName(bytes10 received, bytes10 expected); + error InvalidWorkflowId(bytes32 received, bytes32 expected); + error WorkflowNameRequiresAuthorValidation(); + + // Events + event ForwarderAddressUpdated(address indexed previousForwarder, address indexed newForwarder); + event ExpectedAuthorUpdated(address indexed previousAuthor, address indexed newAuthor); + event ExpectedWorkflowNameUpdated(bytes10 indexed previousName, bytes10 indexed newName); + event ExpectedWorkflowIdUpdated(bytes32 indexed previousId, bytes32 indexed newId); + event SecurityWarning(string message); + + /// @notice Constructor sets msg.sender as the owner and configures the forwarder address + /// @param _forwarderAddress The address of the Chainlink Forwarder contract (cannot be address(0)) + /// @dev The forwarder address is required for security - it ensures only verified reports are processed + constructor( + address _forwarderAddress + ) Ownable(msg.sender) { + if (_forwarderAddress == address(0)) { + revert InvalidForwarderAddress(); + } + s_forwarderAddress = _forwarderAddress; + emit ForwarderAddressUpdated(address(0), _forwarderAddress); + } - // Security Checks 2-4: Verify workflow identity - ID, owner, and/or name (if any are configured) - if (expectedWorkflowId != bytes32(0) || expectedAuthor != address(0) || expectedWorkflowName != bytes10(0)) { - (bytes32 workflowId, bytes10 workflowName, address workflowOwner) = _decodeMetadata(metadata); - - if (expectedWorkflowId != bytes32(0) && workflowId != expectedWorkflowId) { - revert InvalidWorkflowId(workflowId, expectedWorkflowId); - } - if (expectedAuthor != address(0) && workflowOwner != expectedAuthor) { - revert InvalidAuthor(workflowOwner, expectedAuthor); - } - if (expectedWorkflowName != bytes10(0) && workflowName != expectedWorkflowName) { - revert InvalidWorkflowName(workflowName, expectedWorkflowName); - } - } + /// @notice Returns the configured forwarder address + /// @return The forwarder address (address(0) if disabled) + function getForwarderAddress() external view returns (address) { + return s_forwarderAddress; + } - _processReport(report); - } + /// @notice Returns the expected workflow author address + /// @return The expected author address (address(0) if not set) + function getExpectedAuthor() external view returns (address) { + return s_expectedAuthor; + } - /// @notice Updates the forwarder address that is allowed to call onReport - /// @param _forwarder The new forwarder address (use address(0) to disable this check) - function setForwarderAddress(address _forwarder) external onlyOwner { - forwarderAddress = _forwarder; - } + /// @notice Returns the expected workflow name + /// @return The expected workflow name (bytes10(0) if not set) + function getExpectedWorkflowName() external view returns (bytes10) { + return s_expectedWorkflowName; + } + + /// @notice Returns the expected workflow ID + /// @return The expected workflow ID (bytes32(0) if not set) + function getExpectedWorkflowId() external view returns (bytes32) { + return s_expectedWorkflowId; + } - /// @notice Updates the expected workflow owner address - /// @param _author The new expected author address (use address(0) to disable this check) - function setExpectedAuthor(address _author) external onlyOwner { - expectedAuthor = _author; + /// @inheritdoc IReceiver + /// @dev Performs optional validation checks based on which permission fields are set + function onReport( + bytes calldata metadata, + bytes calldata report + ) external override { + // Security Check 1: Verify caller is the trusted Chainlink Forwarder (if configured) + if (s_forwarderAddress != address(0) && msg.sender != s_forwarderAddress) { + revert InvalidSender(msg.sender, s_forwarderAddress); } - /// @notice Updates the expected workflow name from a plaintext string - /// @param _name The workflow name as a string (use empty string "" to disable this check) - /// @dev The name is hashed using SHA256 and truncated - function setExpectedWorkflowName(string calldata _name) external onlyOwner { - if (bytes(_name).length == 0) { - expectedWorkflowName = bytes10(0); - return; - } + // Security Checks 2-4: Verify workflow identity - ID, owner, and/or name (if any are configured) + if (s_expectedWorkflowId != bytes32(0) || s_expectedAuthor != address(0) || s_expectedWorkflowName != bytes10(0)) { + (bytes32 workflowId, bytes10 workflowName, address workflowOwner) = _decodeMetadata(metadata); + + if (s_expectedWorkflowId != bytes32(0) && workflowId != s_expectedWorkflowId) { + revert InvalidWorkflowId(workflowId, s_expectedWorkflowId); + } + if (s_expectedAuthor != address(0) && workflowOwner != s_expectedAuthor) { + revert InvalidAuthor(workflowOwner, s_expectedAuthor); + } - // Convert workflow name to bytes10: - // SHA256 hash → hex encode → take first 10 chars → hex encode those chars - bytes32 hash = sha256(bytes(_name)); - bytes memory hexString = _bytesToHexString(abi.encodePacked(hash)); - bytes memory first10 = new bytes(10); - for (uint i = 0; i < 10; i++) { - first10[i] = hexString[i]; + // ================================================================ + // WORKFLOW NAME VALIDATION - REQUIRES AUTHOR VALIDATION + // ================================================================ + // Do not rely on workflow name validation alone. Workflow names are unique + // per owner, but not across owners. + // Furthermore, workflow names use 40-bit truncation (bytes10), making collisions possible. + // Therefore, workflow name validation REQUIRES author (workflow owner) validation. + // The code enforces this dependency at runtime. + // ================================================================ + if (s_expectedWorkflowName != bytes10(0)) { + // Author must be configured if workflow name is used + if (s_expectedAuthor == address(0)) { + revert WorkflowNameRequiresAuthorValidation(); + } + // Validate workflow name matches (author already validated above) + if (workflowName != s_expectedWorkflowName) { + revert InvalidWorkflowName(workflowName, s_expectedWorkflowName); } - expectedWorkflowName = bytes10(first10); + } } - /// @notice Updates the expected workflow ID - /// @param _id The new expected workflow ID (use bytes32(0) to disable this check) - function setExpectedWorkflowId(bytes32 _id) external onlyOwner { - expectedWorkflowId = _id; + _processReport(report); + } + + /// @notice Updates the forwarder address that is allowed to call onReport + /// @param _forwarder The new forwarder address + /// @dev WARNING: Setting to address(0) disables forwarder validation. + /// This makes your contract INSECURE - anyone can call onReport() with arbitrary data. + /// Only use address(0) if you fully understand the security implications. + function setForwarderAddress( + address _forwarder + ) external onlyOwner { + address previousForwarder = s_forwarderAddress; + + // Emit warning if disabling forwarder check + if (_forwarder == address(0)) { + emit SecurityWarning("Forwarder address set to zero - contract is now INSECURE"); } - /// @notice Helper function to convert bytes to hex string - /// @param data The bytes to convert - /// @return The hex string representation - function _bytesToHexString(bytes memory data) private pure returns (bytes memory) { - bytes memory hexChars = "0123456789abcdef"; - bytes memory hexString = new bytes(data.length * 2); + s_forwarderAddress = _forwarder; + emit ForwarderAddressUpdated(previousForwarder, _forwarder); + } - for (uint256 i = 0; i < data.length; i++) { - hexString[i * 2] = hexChars[uint8(data[i] >> 4)]; - hexString[i * 2 + 1] = hexChars[uint8(data[i] & 0x0f)]; - } + /// @notice Updates the expected workflow owner address + /// @param _author The new expected author address (use address(0) to disable this check) + function setExpectedAuthor( + address _author + ) external onlyOwner { + address previousAuthor = s_expectedAuthor; + s_expectedAuthor = _author; + emit ExpectedAuthorUpdated(previousAuthor, _author); + } - return hexString; + /// @notice Updates the expected workflow name from a plaintext string + /// @param _name The workflow name as a string (use empty string "" to disable this check) + /// @dev IMPORTANT: Workflow name validation REQUIRES author validation to be enabled. + /// The workflow name uses only 40-bit truncation, making collision attacks feasible + /// when used alone. However, since workflow names are unique per owner, validating + /// both the name AND the author address provides adequate security. + /// You must call setExpectedAuthor() before or after calling this function. + /// The name is hashed using SHA256 and truncated to bytes10. + function setExpectedWorkflowName( + string calldata _name + ) external onlyOwner { + bytes10 previousName = s_expectedWorkflowName; + + if (bytes(_name).length == 0) { + s_expectedWorkflowName = bytes10(0); + emit ExpectedWorkflowNameUpdated(previousName, bytes10(0)); + return; } - /// @notice Extracts all metadata fields from the onReport metadata parameter - /// @param metadata The metadata in bytes format - /// @return workflowId The unique identifier of the workflow (bytes32) - /// @return workflowName The name of the workflow (bytes10) - /// @return workflowOwner The owner address of the workflow - function _decodeMetadata(bytes memory metadata) - internal - pure - returns (bytes32 workflowId, bytes10 workflowName, address workflowOwner) - { - // Metadata structure: - // - First 32 bytes: length of the byte array (standard for dynamic bytes) - // - Offset 32, size 32: workflow_id (bytes32) - // - Offset 64, size 10: workflow_name (bytes10) - // - Offset 74, size 20: workflow_owner (address) - assembly { - workflowId := mload(add(metadata, 32)) - workflowName := mload(add(metadata, 64)) - workflowOwner := shr(mul(12, 8), mload(add(metadata, 74))) - } + // Convert workflow name to bytes10: + // SHA256 hash → hex encode → take first 10 chars → hex encode those chars + bytes32 hash = sha256(bytes(_name)); + bytes memory hexString = _bytesToHexString(abi.encodePacked(hash)); + bytes memory first10 = new bytes(10); + for (uint256 i = 0; i < 10; i++) { + first10[i] = hexString[i]; + } + s_expectedWorkflowName = bytes10(first10); + emit ExpectedWorkflowNameUpdated(previousName, s_expectedWorkflowName); + } + + /// @notice Updates the expected workflow ID + /// @param _id The new expected workflow ID (use bytes32(0) to disable this check) + function setExpectedWorkflowId( + bytes32 _id + ) external onlyOwner { + bytes32 previousId = s_expectedWorkflowId; + s_expectedWorkflowId = _id; + emit ExpectedWorkflowIdUpdated(previousId, _id); + } + + /// @notice Helper function to convert bytes to hex string + /// @param data The bytes to convert + /// @return The hex string representation + function _bytesToHexString( + bytes memory data + ) private pure returns (bytes memory) { + bytes memory hexString = new bytes(data.length * 2); + + for (uint256 i = 0; i < data.length; i++) { + hexString[i * 2] = HEX_CHARS[uint8(data[i] >> 4)]; + hexString[i * 2 + 1] = HEX_CHARS[uint8(data[i] & 0x0f)]; } - /// @notice Abstract function to process the report data - /// @param report The report calldata containing your workflow's encoded data - /// @dev Implement this function with your contract's business logic - function _processReport(bytes calldata report) internal virtual; + return hexString; + } - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { - return interfaceId == type(IReceiver).interfaceId || interfaceId == type(IERC165).interfaceId; + /// @notice Extracts all metadata fields from the onReport metadata parameter + /// @param metadata The metadata bytes encoded using abi.encodePacked(workflowId, workflowName, workflowOwner) + /// @return workflowId The unique identifier of the workflow (bytes32) + /// @return workflowName The name of the workflow (bytes10) + /// @return workflowOwner The owner address of the workflow + function _decodeMetadata( + bytes memory metadata + ) internal pure returns (bytes32 workflowId, bytes10 workflowName, address workflowOwner) { + // Metadata structure (encoded using abi.encodePacked by the Forwarder): + // - First 32 bytes: length of the byte array (standard for dynamic bytes) + // - Offset 32, size 32: workflow_id (bytes32) + // - Offset 64, size 10: workflow_name (bytes10) + // - Offset 74, size 20: workflow_owner (address) + assembly { + workflowId := mload(add(metadata, 32)) + workflowName := mload(add(metadata, 64)) + workflowOwner := shr(mul(12, 8), mload(add(metadata, 74))) } + return (workflowId, workflowName, workflowOwner); + } + + /// @notice Abstract function to process the report data + /// @param report The report calldata containing your workflow's encoded data + /// @dev Implement this function with your contract's business logic + function _processReport( + bytes calldata report + ) internal virtual; + + /// @inheritdoc IERC165 + function supportsInterface( + bytes4 interfaceId + ) public view virtual override returns (bool) { + return interfaceId == type(IReceiver).interfaceId || interfaceId == type(IERC165).interfaceId; + } } ``` ### 3.3 Quick Start -The simplest way to use `IReceiverTemplate` is to inherit from it and implement the `_processReport` function: +The simplest way to use `ReceiverTemplate` is to inherit from it and implement the `_processReport` function: -```solidity +```sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -import { IReceiverTemplate } from "./IReceiverTemplate.sol"; +import {ReceiverTemplate} from "./ReceiverTemplate.sol"; -contract MyConsumer is IReceiverTemplate { - uint256 public storedValue; +contract MyConsumer is ReceiverTemplate { + uint256 public s_storedValue; event ValueUpdated(uint256 newValue); - // Simple constructor - no parameters needed - constructor() IReceiverTemplate() {} + // Constructor requires forwarder address + constructor( + address _forwarderAddress + ) ReceiverTemplate(_forwarderAddress) {} // Implement your business logic here - function _processReport(bytes calldata report) internal override { + function _processReport( + bytes calldata report + ) internal override { uint256 newValue = abi.decode(report, (uint256)); - storedValue = newValue; + s_storedValue = newValue; emit ValueUpdated(newValue); } } @@ -2151,7 +2345,7 @@ contract MyConsumer is IReceiverTemplate { ### 3.4 Configuring Permissions -After deploying your contract, the owner can enable any combination of security checks using the setter functions. +The forwarder address is configured at deployment via the constructor and provides your first line of defense. After deploying your contract, the owner can configure additional security checks or update the forwarder address if needed. <Aside type="caution" title="For simulation"> @@ -2160,21 +2354,23 @@ After deploying your contract, the owner can enable any combination of security <Aside type="tip" title="Finding forwarder addresses"> - For a complete list of `KeystoneForwarder` contract addresses on all supported networks, see [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks). + For a complete list of `KeystoneForwarder` and `MockForwarder` contract addresses on all supported networks, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). </Aside> **Configuration examples:** ```solidity -// Example: Enable forwarder check only -myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia +// Example: Update forwarder address (e.g., when moving from simulation to production) +myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia KeystoneForwarder -// Example: Enable workflow ID check +// Example: Add workflow ID check for additional security myConsumer.setExpectedWorkflowId(0x1234...); // Your specific workflow ID -// Example: Enable workflow owner and name checks +// Example: Add workflow owner check myConsumer.setExpectedAuthor(0xYourAddress...); -myConsumer.setExpectedWorkflowName("my_workflow"); // The plaintext workflow name + +// Example: Add workflow name check (requires author validation to be set) +myConsumer.setExpectedWorkflowName("my_workflow"); // Example: Disable a check later myConsumer.setExpectedWorkflowName(""); // Empty string disables the check @@ -2182,27 +2378,31 @@ myConsumer.setExpectedWorkflowName(""); // Empty string disables the check <Aside type="tip" title="Recommended production setup"> - For production contracts, we recommend enabling at minimum the `forwarderAddress` check. For highest security, combine it with `expectedWorkflowId` to ensure only your specific workflow can update the contract. + The forwarder address is required at deployment and provides basic security. For production contracts, we strongly recommend adding additional validation: + + - Use `setExpectedWorkflowId()` if only one workflow writes to your contract (highest security) + - Use `setExpectedAuthor()` if multiple workflows from the same owner write to your contract </Aside> **What the template handles for you:** -- Validates the caller address (if `forwarderAddress` is set) -- Validates the workflow ID (if `expectedWorkflowId` is set) -- Validates the workflow owner (if `expectedAuthor` is set) -- Validates the workflow name (if `expectedWorkflowName` is set) -- Validates the ERC165 interface detection -- Validates the Access control via OpenZeppelin's `Ownable` +- Validates the caller address against the configured forwarder (required at deployment) +- Validates the workflow ID (if `expectedWorkflowId` is configured) +- Validates the workflow owner (if `expectedAuthor` is configured) +- Validates the workflow name (if both `expectedWorkflowName` AND `expectedAuthor` are configured) +- Implements ERC165 interface detection +- Provides access control via OpenZeppelin's `Ownable` - Calls your `_processReport` function with validated data **What you implement:** +- Pass the forwarder address to the constructor during deployment - Your business logic in `_processReport` -- (Optional) Configure permissions after deployment using setter functions +- (Optional) Configure additional permissions after deployment using setter functions #### How workflow names are encoded -The `workflowName` field in the metadata uses the **`bytes10`** type rather than plaintext strings. When you call `setExpectedWorkflowName("my_workflow")`, the `IReceiverTemplate` automatically encodes it using the same algorithm as the CRE engine: +The `workflowName` field in the metadata uses the **`bytes10`** type rather than plaintext strings. When you call `setExpectedWorkflowName("my_workflow")`, the `ReceiverTemplate` automatically encodes it using the same algorithm as the CRE engine: 1. Compute SHA256 hash of the workflow name 2. Convert hash to hex string (64 characters) @@ -2213,14 +2413,22 @@ The `workflowName` field in the metadata uses the **`bytes10`** type rather than This encoding ensures consistent, fixed-size representation regardless of the original workflow name length. + +<Aside type="caution" title="Workflow name validation requires author validation"> + Workflow name validation is **only performed when author validation is also configured**. The code enforces this at runtime: if you set `expectedWorkflowName`, you must also set `expectedAuthor`, otherwise the validation will revert with `WorkflowNameRequiresAuthorValidation()`. This prevents the 40-bit collision attack by ensuring workflow names are validated in combination with the owner address. See [Security Considerations](#7-security-considerations) for details. +</Aside> + **Usage:** ```solidity -// Just use the plaintext workflow name - the interface handles the encoding automatically +// Set the expected author first (required) +myConsumer.setExpectedAuthor(0xYourAddress...); + +// Then set the expected workflow name (only works with author validation) myConsumer.setExpectedWorkflowName("my_workflow"); -// To disable the check later -myConsumer.setExpectedWorkflowName(""); // Empty string disables the check +// To disable the workflow name check +myConsumer.setExpectedWorkflowName(""); // Empty string clears the stored value ``` ## 4. Working with Simulation @@ -2231,20 +2439,21 @@ When you run `cre workflow simulate`, your workflow interacts with a **`MockKeys This is a **temporary limitation** until the `MockKeystoneForwarder` is updated to provide full metadata. </Aside> -### Forwarder address validation +### Deploying for Simulation -You **can** configure the forwarder address check during simulation using the **Mock Forwarder Address**: +When deploying your consumer contract for simulation, pass the **Mock Forwarder address** to the constructor: ```solidity -// Example: Use Mock Forwarder for Ethereum Sepolia simulation -myConsumer.setForwarderAddress(0x15fC6ae953E024d975e77382eEeC56A9101f9F88); +// Deploy with MockForwarder address for Ethereum Sepolia simulation +address mockForwarder = 0x15fC6ae953E024d975e77382eEeC56A9101f9F88; // Ethereum Sepolia MockForwarder +MyConsumer myConsumer = new MyConsumer(mockForwarder); ``` -Find Mock Forwarder addresses for all networks in the [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks) page. +Find Mock Forwarder addresses for all networks in the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) page. <Aside type="caution" title="Important: Different addresses for simulation vs production"> - The `MockKeystoneForwarder` address used during simulation is **different** from the `KeystoneForwarder` address used by deployed workflows. If you configure the forwarder address for simulation, remember to update it to the production `KeystoneForwarder` address after deploying. See [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks) for forwarder addresses. + The `MockKeystoneForwarder` address used during simulation is **different** from the `KeystoneForwarder` address used by deployed workflows. After testing with simulation, deploy a new instance with the production `KeystoneForwarder` address, or update the forwarder address using `setForwarderAddress()`. See [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) for forwarder addresses. </Aside> ### Metadata-based validation @@ -2257,18 +2466,28 @@ Find Mock Forwarder addresses for all networks in the [Supported Networks](/cre/ Setting any of these will cause your simulation to fail. -### After deployment +### Transitioning to Production + +Once you're ready to deploy your workflow to production: -Once you deploy your workflow: +**Option 1: Deploy a new contract instance** + +```solidity +// Deploy with production KeystoneForwarder address +address keystoneForwarder = 0xF8344CFd5c43616a4366C34E3EEE75af79a74482; // Ethereum Sepolia +MyConsumer myConsumer = new MyConsumer(keystoneForwarder); + +// Configure additional security checks +myConsumer.setExpectedWorkflowId(0xYourWorkflowId); +``` -1. Update the forwarder address to the real `KeystoneForwarder` (if you configured it for simulation) -2. Configure additional metadata-based validation as needed +**Option 2: Update existing contract's forwarder** ```solidity -// Update to production KeystoneForwarder address -myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Example: Ethereum Sepolia +// Update forwarder to production KeystoneForwarder +myConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia -// Now you can enable metadata-based validation +// Add metadata-based validation myConsumer.setExpectedWorkflowId(0xYourWorkflowId); ``` @@ -2281,25 +2500,29 @@ See [Configuring Permissions](#34-configuring-permissions) for complete details. You can override `onReport` to add your own validation logic before or after the standard checks: ```solidity -import { IReceiverTemplate } from "./IReceiverTemplate.sol"; +import { ReceiverTemplate } from "./ReceiverTemplate.sol"; -contract AdvancedConsumer is IReceiverTemplate { - uint256 public minReportInterval = 1 hours; - uint256 public lastReportTime; +contract AdvancedConsumer is ReceiverTemplate { + uint256 private s_minReportInterval = 1 hours; + uint256 private s_lastReportTime; error ReportTooFrequent(uint256 timeSinceLastReport, uint256 minInterval); + event MinReportIntervalUpdated(uint256 previousInterval, uint256 newInterval); + + constructor(address _forwarderAddress) ReceiverTemplate(_forwarderAddress) {} + // Add custom validation before parent's checks function onReport(bytes calldata metadata, bytes calldata report) external override { // Custom check: Rate limiting - if (block.timestamp < lastReportTime + minReportInterval) { - revert ReportTooFrequent(block.timestamp - lastReportTime, minReportInterval); + if (block.timestamp < s_lastReportTime + s_minReportInterval) { + revert ReportTooFrequent(block.timestamp - s_lastReportTime, s_minReportInterval); } // Call parent implementation for standard permission checks super.onReport(metadata, report); - lastReportTime = block.timestamp; + s_lastReportTime = block.timestamp; } function _processReport(bytes calldata report) internal override { @@ -2308,9 +2531,24 @@ contract AdvancedConsumer is IReceiverTemplate { // ... store or process the value ... } - // Allow owner to update rate limit + /// @notice Returns the minimum interval between reports + /// @return The minimum interval in seconds + function getMinReportInterval() external view returns (uint256) { + return s_minReportInterval; + } + + /// @notice Returns the timestamp of the last report + /// @return The last report timestamp + function getLastReportTime() external view returns (uint256) { + return s_lastReportTime; + } + + /// @notice Updates the minimum interval between reports + /// @param _interval The new minimum interval in seconds function setMinReportInterval(uint256 _interval) external onlyOwner { - minReportInterval = _interval; + uint256 previousInterval = s_minReportInterval; + s_minReportInterval = _interval; + emit MinReportIntervalUpdated(previousInterval, _interval); } } ``` @@ -2320,8 +2558,10 @@ contract AdvancedConsumer is IReceiverTemplate { The `_decodeMetadata` helper function is available for use in your `_processReport` implementation. This allows you to access workflow metadata for custom business logic: ```solidity -contract MetadataAwareConsumer is IReceiverTemplate { - mapping(bytes32 => uint256) public reportCountByWorkflow; +contract MetadataAwareConsumer is ReceiverTemplate { + mapping(bytes32 => uint256) public s_reportCountByWorkflow; + + constructor(address _forwarderAddress) ReceiverTemplate(_forwarderAddress) {} function _processReport(bytes calldata report) internal override { // Access the metadata to get workflow ID @@ -2329,7 +2569,7 @@ contract MetadataAwareConsumer is IReceiverTemplate { (bytes32 workflowId, , ) = _decodeMetadata(metadata); // Use workflow ID in your business logic - reportCountByWorkflow[workflowId]++; + s_reportCountByWorkflow[workflowId]++; // Process the report data uint256 value = abi.decode(report, (uint256)); @@ -2347,35 +2587,44 @@ contract MetadataAwareConsumer is IReceiverTemplate { ### Example 1: Simple Consumer Contract -This example inherits from `IReceiverTemplate` to store a temperature value. +This example inherits from `ReceiverTemplate` to store a temperature value. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -import { IReceiverTemplate } from "./IReceiverTemplate.sol"; +import { ReceiverTemplate } from "./ReceiverTemplate.sol"; -contract TemperatureConsumer is IReceiverTemplate { - int256 public currentTemperature; +contract TemperatureConsumer is ReceiverTemplate { + int256 public s_currentTemperature; event TemperatureUpdated(int256 newTemperature); - // Simple constructor - no parameters needed - constructor() IReceiverTemplate() {} + // Constructor requires forwarder address + constructor(address _forwarderAddress) ReceiverTemplate(_forwarderAddress) {} function _processReport(bytes calldata report) internal override { int256 newTemperature = abi.decode(report, (int256)); - currentTemperature = newTemperature; + s_currentTemperature = newTemperature; emit TemperatureUpdated(newTemperature); } } ``` -**Configuring permissions after deployment:** +**Deployment:** ```solidity -// Enable forwarder check for production -temperatureConsumer.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia +// For simulation: Use MockForwarder address +address mockForwarder = 0x15fC6ae953E024d975e77382eEeC56A9101f9F88; // e.g. Ethereum Sepolia +TemperatureConsumer temperatureConsumer = new TemperatureConsumer(mockForwarder); + +// For production: Use KeystoneForwarder address +address keystoneForwarder = 0xF8344CFd5c43616a4366C34E3EEE75af79a74482; // e.g. Ethereum Sepolia +TemperatureConsumer temperatureConsumer = new TemperatureConsumer(keystoneForwarder); +``` -// Enable workflow ID check for highest security +**Adding additional security after deployment:** + +```solidity +// Add workflow ID check for highest security temperatureConsumer.setExpectedWorkflowId(0xYourWorkflowId...); ``` @@ -2384,7 +2633,7 @@ temperatureConsumer.setExpectedWorkflowId(0xYourWorkflowId...); For more complex scenarios, it's best to separate your Chainlink-aware code from your core business logic. The **Proxy Pattern** is a robust architecture that uses two contracts to achieve this: - **A Logic Contract**: Holds the state and the core functions of your application. It knows nothing about the Forwarder contract or the `onReport` function. -- **A Proxy Contract**: Acts as the secure entry point. It inherits from `IReceiverTemplate` and forwards validated reports to the Logic Contract. +- **A Proxy Contract**: Acts as the secure entry point. It inherits from `ReceiverTemplate` and forwards validated reports to the Logic Contract. This separation makes your business logic more modular and reusable. @@ -2404,28 +2653,59 @@ contract ReserveManager is Ownable { uint256 btcPrice; } - address public proxyAddress; - uint256 public lastEthPrice; - uint256 public lastBtcPrice; - uint256 public lastUpdateTime; + address private s_proxyAddress; + uint256 private s_lastEthPrice; + uint256 private s_lastBtcPrice; + uint256 private s_lastUpdateTime; event ReservesUpdated(uint256 ethPrice, uint256 btcPrice, uint256 updateTime); + event ProxyAddressUpdated(address indexed previousProxy, address indexed newProxy); modifier onlyProxy() { - require(msg.sender == proxyAddress, "Caller is not the authorized proxy"); + require(msg.sender == s_proxyAddress, "Caller is not the authorized proxy"); _; } constructor() Ownable(msg.sender) {} + /// @notice Returns the proxy address + /// @return The authorized proxy address + function getProxyAddress() external view returns (address) { + return s_proxyAddress; + } + + /// @notice Returns the last ETH price + /// @return The last recorded ETH price + function getLastEthPrice() external view returns (uint256) { + return s_lastEthPrice; + } + + /// @notice Returns the last BTC price + /// @return The last recorded BTC price + function getLastBtcPrice() external view returns (uint256) { + return s_lastBtcPrice; + } + + /// @notice Returns the last update timestamp + /// @return The timestamp of the last update + function getLastUpdateTime() external view returns (uint256) { + return s_lastUpdateTime; + } + + /// @notice Updates the authorized proxy address + /// @param _proxyAddress The new proxy address function setProxyAddress(address _proxyAddress) external onlyOwner { - proxyAddress = _proxyAddress; + address previousProxy = s_proxyAddress; + s_proxyAddress = _proxyAddress; + emit ProxyAddressUpdated(previousProxy, _proxyAddress); } + /// @notice Updates the reserve prices + /// @param data The new reserve data containing ETH and BTC prices function updateReserves(UpdateReserves memory data) external onlyProxy { - lastEthPrice = data.ethPrice; - lastBtcPrice = data.btcPrice; - lastUpdateTime = block.timestamp; + s_lastEthPrice = data.ethPrice; + s_lastBtcPrice = data.btcPrice; + s_lastUpdateTime = block.timestamp; emit ReservesUpdated(data.ethPrice, data.btcPrice, block.timestamp); } } @@ -2433,23 +2713,29 @@ contract ReserveManager is Ownable { #### The Proxy Contract (`UpdateReservesProxy.sol`) -This contract, our "bouncer", is the only contract that interacts with the Chainlink platform. It inherits `IReceiverTemplate` to validate incoming reports and then calls the `ReserveManager`. +This contract, our "bouncer", is the only contract that interacts with the Chainlink platform. It inherits `ReceiverTemplate` to validate incoming reports and then calls the `ReserveManager`. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ReserveManager } from "./ReserveManager.sol"; -import { IReceiverTemplate } from "./keystone/IReceiverTemplate.sol"; +import { ReceiverTemplate } from "./ReceiverTemplate.sol"; -contract UpdateReservesProxy is IReceiverTemplate { - ReserveManager public s_reserveManager; +contract UpdateReservesProxy is ReceiverTemplate { + ReserveManager private s_reserveManager; - constructor(address reserveManagerAddress) { + constructor(address _forwarderAddress, address reserveManagerAddress) ReceiverTemplate(_forwarderAddress) { s_reserveManager = ReserveManager(reserveManagerAddress); } - /// @inheritdoc IReceiverTemplate + /// @notice Returns the reserve manager contract address + /// @return The ReserveManager contract instance + function getReserveManager() external view returns (ReserveManager) { + return s_reserveManager; + } + + /// @inheritdoc ReceiverTemplate function _processReport(bytes calldata report) internal override { ReserveManager.UpdateReserves memory updateReservesData = abi.decode(report, (ReserveManager.UpdateReserves)); s_reserveManager.updateReserves(updateReservesData); @@ -2460,16 +2746,13 @@ contract UpdateReservesProxy is IReceiverTemplate { **Configuring permissions after deployment:** ```solidity -// Enable forwarder check (recommended) -updateReservesProxy.setForwarderAddress(0xF8344CFd5c43616a4366C34E3EEE75af79a74482); // Ethereum Sepolia - -// Enable workflow ID check for production (highest security) +// Additional validation can be added after deployment updateReservesProxy.setExpectedWorkflowId(0xYourWorkflowId...); ``` <Aside type="note" title="KeystoneForwarder address shown"> - The examples above use the Ethereum Sepolia forwarder address. For other networks, see [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks). + The examples above use the Ethereum Sepolia forwarder address. For other networks, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). </Aside> #### How it Works @@ -2477,7 +2760,7 @@ updateReservesProxy.setExpectedWorkflowId(0xYourWorkflowId...); The deployment and configuration process involves these steps: 1. **Deploy the Logic Contract**: Deploy `ReserveManager.sol`. The wallet that deploys this contract becomes its `owner`. -2. **Deploy the Proxy Contract**: Deploy `UpdateReservesProxy.sol`, passing the address of the deployed `ReserveManager` contract to its constructor. +2. **Deploy the Proxy Contract**: Deploy `UpdateReservesProxy.sol`, passing the forwarder address and the address of the deployed `ReserveManager` contract to its constructor. 3. **Link the Contracts**: The `owner` of the `ReserveManager` contract must call its `setProxyAddress` function, passing in the address of the `UpdateReservesProxy` contract. This authorizes the proxy to call the logic contract. 4. **Configure Permissions** (Recommended): The `owner` of the proxy should call setter functions to enable security checks: ```solidity @@ -2487,27 +2770,73 @@ The deployment and configuration process involves these steps: 5. **Configure Workflow**: In your workflow's `config.json`, use the address of the **Proxy Contract** as the receiver address. 6. **Execution Flow**: When your workflow runs: - The Chainlink Forwarder calls `onReport` on your **Proxy** - - The Proxy validates the report (forwarder address, workflow ID, etc.) + - The Proxy validates the report (forwarder address is verified automatically; additional checks like workflow ID can be added) - The Proxy's `_processReport` function calls the `updateReserves` function on your **Logic Contract** - Because the caller is the trusted proxy, the `onlyProxy` check passes, and your state is securely updated 7. **(Optional) Upgrade**: If you later need to deploy a new proxy, the owner can: - - Deploy the new proxy contract + - Deploy the new proxy contract with the appropriate forwarder address - Call `setProxyAddress` on the `ReserveManager` to point it to the new proxy's address - Update the workflow configuration to use the new proxy address #### End-to-End Sequence -## Where to go next? +## 7. Security Considerations + +### Forwarder address + +**The forwarder address is the foundation of your contract's security.** The `KeystoneForwarder` contract performs cryptographic verification of DON signatures before calling your consumer. By requiring the forwarder address in the constructor, `ReceiverTemplate` ensures your contract is secure from deployment. + + +<Aside type="caution" title="Never set forwarder to address(0) in production"> + While the `setForwarderAddress()` function allows updating to `address(0)`, this disables the critical security check and allows **anyone** to call your `onReport()` function with arbitrary data. The function emits a `SecurityWarning` event if you attempt this. Only use `address(0)` for testing if you fully understand the implications. +</Aside> + +### Replay protection + +The `KeystoneForwarder` contract includes built-in replay protection that prevents successful reports from being executed multiple times. By requiring the forwarder address at construction time, `ReceiverTemplate` ensures your consumer benefits from this protection automatically. + + +<Aside type="note" title="Failed reports can be retried"> + If a report fails (reverts), the forwarder's replay protection allows it to be retried. This is safe because reverts undo all state changes, ensuring no duplicate effects occur in your contract. +</Aside> + +### Additional validation layers + +The forwarder address provides baseline security, but you can add additional validation for defense-in-depth: + +- **`expectedWorkflowId`**: Ensures only one specific workflow can update your contract. Use this when a single workflow writes to your consumer (highest security for single-workflow scenarios). +- **`expectedAuthor`**: Restricts to workflows owned by a specific address. Use this when multiple workflows from the same owner should access your contract. +- **`expectedWorkflowName`**: Can be used in combination with `expectedAuthor` for additional validation. Requires author validation to be configured. See [Workflow name validation](#workflow-name-validation) below. -Now that you know how to build a consumer contract, the next step is to call it from your workflow. +### Workflow name validation -- **[Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write)**: Learn how to use the `EVMClient` to send data to your new consumer contract. + +<Aside type="caution" title="Workflow name validation requires author validation"> + The `expectedWorkflowName` check in `ReceiverTemplate.onReport()` **requires author validation** to be configured: + + - **Collision Risk**: Workflow names use only 40-bit truncation (bytes10), making collision attacks computationally feasible when used alone + - **Unique per owner**: Workflow names are unique per owner but not across different owners + - **Runtime enforcement**: The code enforces that if `expectedWorkflowName` is set, `expectedAuthor` must also be set, otherwise it reverts with `WorkflowNameRequiresAuthorValidation()` + + By combining workflow name (40-bit) with author validation (160-bit address), the contract achieves adequate collision resistance. You can safely use workflow name validation as long as author validation is also enabled. +</Aside> + +### Best practices + +1. **Always deploy with a valid forwarder address** - The constructor requires this for security. Use `MockForwarder` for simulation, `KeystoneForwarder` for production. Forwarder addresses are available in the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) page. +2. **Add additional validation for production**: + - **Single workflow**: Use `setExpectedWorkflowId()` to restrict to one specific workflow (highest security) + - **Multiple workflows from same owner**: Use `setExpectedAuthor()` to restrict to workflows you own + - **Multiple workflows from different owners**: Implement custom validation logic in your `onReport()` override +3. **Keep your owner key secure** - The owner can update all permission settings +4. **Test permission configurations** - Verify your security settings work as expected before production deployment +5. **Workflow name validation** - Can be used with `setExpectedWorkflowName()` but requires `setExpectedAuthor()` to also be configured for security --- # Writing Data Onchain Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 This guide shows you how to write data from your CRE workflow to a smart contract on the blockchain using the TypeScript SDK. You'll learn the complete two-step process with examples for both single values and structs. @@ -2567,7 +2896,7 @@ This example shows how to write a single `uint256` value to your consumer contra ### Step 1: Set up your imports ```typescript -import { cre, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime } from "@chainlink/cre-sdk" import { encodeAbiParameters, parseAbiParameters } from "viem" ``` @@ -2586,10 +2915,21 @@ const reportData = encodeAbiParameters(parseAbiParameters("address"), ["0x123456 const reportData = encodeAbiParameters(parseAbiParameters("bool"), [true]) ``` -<Aside type="note" title="BigInt literals"> - Use the `n` suffix for integer literals to create `bigint` values in TypeScript. This is required for **all** Solidity - integer types (`uint8`, `uint256`, `int8`, `int256`, etc.) when using viem: `12345n`, `1000000000000000000n`, etc. -</Aside> + +<Aside type="caution" title="Always use bigint for Solidity integers"> + JavaScript `number` loses precision for values above \~9 quadrillion (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER" target="_blank" rel="noopener noreferrer">Number.MAX_SAFE_INTEGER</a>). This causes **silent precision loss** — your workflow sends the wrong value without any error. + + **Always use `bigint`** (with the `n` suffix) for all Solidity integer types: `12345n`, `1000000000000000000n`, etc. + + ```typescript + // WRONG - silent precision loss + const amount = 10000000000000001 // 10 quadrillion + 1 + // Silently becomes 10000000000000000 (the +1 vanishes) + + // CORRECT - use bigint + const amount = 10000000000000001n // Stays exactly 10000000000000001 + ``` +</Aside> ### Step 3: Generate the signed report @@ -2768,7 +3108,7 @@ export { CalculatorResultParams, type CalculatorResult } from "./ConsumerContrac Now you can import and use these definitions in your workflow: ```typescript -import { cre, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime } from "@chainlink/cre-sdk" import { encodeAbiParameters } from "viem" import { CalculatorResultParams, type CalculatorResult } from "../contracts/abi" @@ -2783,7 +3123,7 @@ const writeDataOnchain = (runtime: Runtime<Config>): string => { throw new Error(`Network not found`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) // Create type-safe data object const data: CalculatorResult = { @@ -2855,7 +3195,16 @@ Here's a full workflow that writes a struct to a consumer contract: ### Workflow code (`main.ts`) ```typescript -import { cre, getNetwork, hexToBase64, bytesToHex, TxStatus, type Runtime, Runner } from "@chainlink/cre-sdk" +import { + CronCapability, + EVMClient, + getNetwork, + hexToBase64, + bytesToHex, + TxStatus, + type Runtime, + Runner, +} from "@chainlink/cre-sdk" import { encodeAbiParameters, parseAbiParameters } from "viem" import { z } from "zod" @@ -2882,7 +3231,7 @@ const writeDataOnchain = (runtime: Runtime<Config>): string => { } // Create EVM client - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) // 1. Encode your data (struct with 3 fields) const reportData = encodeAbiParameters( @@ -2926,9 +3275,10 @@ const writeDataOnchain = (runtime: Runtime<Config>): string => { } const initWorkflow = (config: Config) => { + const cron = new CronCapability() return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + cron.handler( + cron.trigger({ schedule: config.schedule, }), writeDataOnchain @@ -2940,8 +3290,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Working with complex types @@ -3048,10 +3396,15 @@ if (writeResult.txStatus === TxStatus.SUCCESS) { # API Interactions Source: https://docs.chain.link/cre/guides/workflow/using-http-client -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 The CRE SDK provides an HTTP client that allows your workflows to interact with external APIs. Use it to fetch offchain data, send results to other systems, or trigger external events. + +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.now()` instead of `Date.now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + These guides will walk you through the common use cases for the HTTP client. ## Guides @@ -3062,6 +3415,25 @@ These guides will walk you through the common use cases for the HTTP client. --- +# Confidential API Interactions (Experimental) +Source: https://docs.chain.link/cre/guides/workflow/using-confidential-http-client +Last Updated: 2026-02-06 + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The CRE SDK provides a Confidential HTTP client that allows your workflows to interact with external APIs while keeping sensitive data private. Requests execute inside a secure enclave, secrets are injected via templates, and responses can optionally be encrypted. + +For a conceptual overview of what Confidential HTTP is and how it differs from the regular HTTP capability, see [The Confidential HTTP Capability](/cre/capabilities/confidential-http). + +## Guides + +- **[Making Confidential Requests](/cre/guides/workflow/using-confidential-http-client/making-requests)**: Learn how to make a confidential HTTP request with secret injection and optional response encryption. + +--- + # Managing Secrets Source: https://docs.chain.link/cre/guides/workflow/secrets Last Updated: 2025-11-04 @@ -3145,7 +3517,7 @@ For detailed CLI command documentation, see: # Using Secrets with Deployed Workflows Source: https://docs.chain.link/cre/guides/workflow/secrets/using-secrets-deployed -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 When your workflow is deployed, it cannot access your local `.env` file or environment variables. Instead, secrets must be stored in the **Vault DON**—a decentralized, secure secret storage system that your deployed workflows can access at runtime. @@ -3590,7 +3962,7 @@ Non-interactive mode allows you to run simulations without prompts, making it id **Requirements:** - Use the `--non-interactive` flag -- Specify `--trigger-index` (0-based index of the trigger to run) +- Specify `--trigger-index` to select which handler to run (0-based position: `0` = first handler, `1` = second, etc.) - Provide trigger-specific flags as needed (see [Trigger-specific configuration](#trigger-specific-configuration)) **Example:** @@ -3599,6 +3971,14 @@ Non-interactive mode allows you to run simulations without prompts, making it id cre workflow simulate my-workflow --non-interactive --trigger-index 0 --target staging-settings ``` +<Aside type="tip" title="Understanding trigger-index"> + The `--trigger-index` flag selects **which handler** in your workflow to execute. Handlers are created in your + `InitWorkflow` function using `cre.Handler()`, where [each handler connects a trigger to a callback + function](/cre/key-terms#handler). If your workflow has only one handler, use `--trigger-index 0`. If you have + multiple handlers (e.g., one for an HTTP trigger and one for an EVM log trigger), use `0` for the first, `1` for the + second, etc., based on their order in your code. +</Aside> + ## The `--broadcast` flag By default, the simulator performs a **dry run** for onchain write operations. It prepares the transaction but does not broadcast it to the blockchain. @@ -3706,6 +4086,20 @@ cre workflow simulate my-workflow \ --target staging-settings ``` + +<Aside type="tip" title="Understanding the two different indexes"> + **Two separate concepts:** + + - **`--trigger-index`** selects **which handler** in your workflow to run (e.g., if the + handler with an EVM log trigger is the third handler defined, use `--trigger-index 2`) + - **`--evm-event-index`** + specifies **which log/event within the transaction** to use for testing (e.g., if the transaction emitted 3 events and + you want the first one, use `--evm-event-index 0`) + + These are completely independent: one selects your workflow's + handler to execute, the other selects which event data from the blockchain to test with. +</Aside> + ## Additional flags ### `--engine-logs` (`-g`) @@ -4136,10 +4530,15 @@ For complete setup instructions, configuration requirements, and step-by-step gu # Updating Deployed Workflows Source: https://docs.chain.link/cre/guides/operations/updating-deployed-workflows -Last Updated: 2025-11-04 +Last Updated: 2026-01-23 When you update a deployed workflow, you redeploy it with the same workflow name. The new deployment replaces the previous version in the Workflow Registry contract. Currently, CRE does not maintain version history—each deployment overwrites the previous one. + +<Aside type="caution" title="Workflow ID changes on update"> + The workflow ID changes each time you update a workflow. This is because the workflow ID is a hash derived from the workflow binary and configuration. If your consumer contract uses the workflow ID for validation, make sure to update the expected workflow ID after each update. See [Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#34-configuring-permissions) for details. +</Aside> + ## Prerequisites Before updating a deployed workflow, ensure you have: @@ -4164,6 +4563,12 @@ cre workflow deploy my-workflow --target production-settings 2. **Upload**: The new binary and configuration files are uploaded to the CRE Storage Service 3. **Registration**: A new registration transaction is sent to the Workflow Registry contract 4. **Replacement**: The previous version is replaced with the new deployment +5. **Status preserved**: The workflow's status (active or paused) is preserved from the previous deployment + + +<Aside type="note" title="Workflow status is preserved"> + When you update a workflow, the CLI matches the status of the previously deployed version. If your workflow was paused, the updated version will remain paused. If it was active, the updated version will be active and immediately start responding to triggers. To change the workflow status, see [Activating & Pausing Workflows](/cre/guides/operations/activating-pausing-workflows). +</Aside> <Aside type="caution" title="No version history"> @@ -5288,6 +5693,96 @@ To unlink a key: The CLI will submit an onchain transaction to remove the address from the Workflow Registry. After the transaction is confirmed, the address and all its associated workflows will be deleted. +## Unlinking a key without the original private key + +If you need to unlink a key but no longer have access to the original private key (for example, the key owner left your organization), you can still complete the unlinking process using a different wallet. + + +<Aside type="caution" title="Destructive operation"> + **Unlinking a key will permanently delete all workflows registered under that address.** This action cannot be undone. Make sure you want to permanently remove all associated workflows before proceeding. +</Aside> + +### How it works + +When you run `cre account unlink-key --unsigned` while logged into your CRE organization, the CLI generates: + +1. An authorization signature proving you have permission to unlink the key (through your CRE organization membership) +2. Raw transaction data that any funded wallet can submit to the blockchain + + +<Aside type="note" title="Security"> + The authorization is tied to the **organization**, not to the individual who originally linked the key. Any authenticated member of the CRE organization can generate valid unlink authorization for keys linked to that organization. +</Aside> + +### Prerequisites + +- **Logged in to CRE CLI**: You must be authenticated as a member of the CRE organization that owns the key +- **`workflow-owner-address` configured**: Set this in your `project.yaml` to the address you want to unlink +- **A funded wallet**: Any wallet with ETH on Ethereum Mainnet to submit the transaction and pay gas fees + +### Steps + +1. **Configure your `project.yaml`** with the address you want to unlink: + + ```yaml + production-settings: + account: + workflow-owner-address: "<address_to_unlink>" + # ... other settings + ``` + +2. **Generate the unsigned transaction**: + + ```bash + cre account unlink-key --unsigned --target production-settings + ``` + + **Example output:** + + ```bash + Unlinking web3 key from your CRE organization + Target : production-settings + ✔ Using Address : 0x.... + + Starting unlinking: owner=0x.... + ✔ Yes + Contract address validation passed + --unsigned flag detected: transaction not sent on-chain. + Generating call data for offline signing and submission in your preferred tool: + + Ownership unlinking initialized successfully! + + Next steps: + + 1. Submit the following transaction on the target chain: + + Chain: ethereum-mainnet + Contract Address: 0x4Ac54353FA4Fa961AfcC5ec4B118596d3305E7e5 + + 2. Use the following transaction data: + + 39d68c6a000000000000000000... + + Unlinked successfully + ``` + +3. **Submit the transaction** using any wallet that supports sending transactions with custom data. + + + <Aside type="caution" title="Destructive operation"> + **Unlinking a key will permanently delete all workflows registered under that address.** This action cannot be undone. Make sure you want to permanently remove all associated workflows before proceeding. + </Aside> + + Here's an example using MetaMask: + + 1. In MetaMask, go to **Settings → Advanced** and enable **"Show hex data"** + 2. Click **Send** and enter the contract address as the recipient 0x4Ac54353FA4Fa961AfcC5ec4B118596d3305E7e5 + 3. Set the amount to **0 ETH** + 4. Paste the transaction data in the **Hex data** field (add `0x` prefix) + 5. Review and confirm the transaction + + The unlink operation completes once the transaction is confirmed onchain. All workflows registered under that address will be permanently deleted. + ## Non-interactive mode For automation or CI/CD pipelines, use the `--yes` flag to skip confirmation prompts: @@ -5488,9 +5983,10 @@ This section provides a high-level, conceptual overview of the capabilities curr - **[Triggers](/cre/capabilities/triggers)**: Event sources that start your workflow executions. - **[HTTP](/cre/capabilities/http)**: Fetch and post data from external APIs with decentralized consensus. +- **[Confidential HTTP](/cre/capabilities/confidential-http)** *(Experimental)*: Make privacy-preserving API calls with enclave execution, secret injection, and optional response encryption. - **[EVM Read & Write](/cre/capabilities/evm-read-write)**: Interact with smart contracts on EVM-compatible blockchains with decentralized consensus. -All execution capabilities (HTTP, EVM) automatically use [built-in consensus](/cre/concepts/consensus-computing) to validate results across multiple nodes, ensuring security and reliability. +All execution capabilities (HTTP, Confidential HTTP, EVM) automatically use [built-in consensus](/cre/concepts/consensus-computing) to validate results across multiple nodes, ensuring security and reliability. --- @@ -5731,6 +6227,11 @@ Javy uses [QuickJS](https://bellard.org/quickjs), a lightweight JavaScript engin Not all Node.js built-in modules are available. For example, `node:crypto` is not supported. Before using third-party NPM packages, verify they don't rely on unsupported Node.js APIs. + +<Aside type="tip" title="Cryptography libraries"> + If you need cryptographic functions, <a href="https://paulmillr.com/noble/" target="_blank" rel="noopener noreferrer">Noble</a> is a popular JavaScript cryptography library with minimal dependencies that works well with QuickJS. Always verify any third-party library in simulation before deploying. +</Aside> + <Aside type="note" title="Note on async/await with SDK capabilities"> While JavaScript `Promise` and `async/await` are supported by QuickJS, **SDK capabilities do not use them**. The CRE TypeScript SDK uses a custom `.result()` pattern instead. See the [Core SDK @@ -5964,10 +6465,10 @@ See the [repository README](https://github.com/smartcontractkit/cre-gcp-predicti # CLI Reference Source: https://docs.chain.link/cre/reference/cli -Last Updated: 2025-11-20 +Last Updated: 2026-02-10 -<Aside type="note" title="Required CLI Version: v1.0.2"> - To ensure compatibility with the guides and examples in this documentation, please use version `v1.0.2` of the CRE +<Aside type="note" title="Required CLI Version: v1.0.10"> + To ensure compatibility with the guides and examples in this documentation, please use version `v1.0.10` of the CRE CLI. You can check your installed version by running `cre version`. Refer to the [CLI Installation](/cre/getting-started/cli-installation/macos-linux) guide for more information. </Aside> @@ -6341,15 +6842,15 @@ cre workflow simulate <workflow-name-or-path> [flags] **Flags:** -| Flag | Description | -| ------------------------- | -------------------------------------------------------------------------------------------------- | -| `--broadcast` | Broadcast onchain write transactions (default: `false`). Without this flag, a dry run is performed | -| `-g, --engine-logs` | Enable non-fatal engine logging | -| `--non-interactive` | Run without prompts; requires `--trigger-index` and inputs for the selected trigger type | -| `--trigger-index <int>` | Index of the trigger to run (0-based). Required when using `--non-interactive` | -| `--http-payload <string>` | HTTP trigger payload as JSON string or path to JSON file (with or without `@` prefix) | -| `--evm-tx-hash <string>` | EVM trigger transaction hash (`0x...`). For EVM log triggers | -| `--evm-event-index <int>` | EVM trigger log index (0-based). For EVM log triggers | +| Flag | Description | +| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--broadcast` | Broadcast onchain write transactions (default: `false`). Without this flag, a dry run is performed | +| `-g, --engine-logs` | Enable non-fatal engine logging | +| `--non-interactive` | Run without prompts; requires `--trigger-index` (see the line below) and inputs for the selected trigger type | +| `--trigger-index <int>` | Selects which handler to run (0-based position). If your workflow has multiple handlers, `0` is the first, `1` is the second, etc. Required with `--non-interactive` | +| `--http-payload <string>` | HTTP trigger payload as JSON string or path to JSON file (with or without `@` prefix). For HTTP triggers only | +| `--evm-tx-hash <string>` | Transaction hash (`0x...`) containing the event that triggered your workflow. For EVM log triggers only | +| `--evm-event-index <int>` | Which log/event within the transaction to use (0-based position). If the transaction emitted multiple events, `0` is the first, `1` is the second, etc. For EVM log triggers only | **Examples:** @@ -6365,6 +6866,21 @@ cre workflow simulate <workflow-name-or-path> [flags] cre workflow simulate ./my-workflow --broadcast --target local-simulation ``` +- Non-interactive mode with HTTP trigger + + ```bash + # If your HTTP trigger handler is the first handler in your workflow, use --trigger-index 0 + cre workflow simulate my-workflow --non-interactive --trigger-index 0 --http-payload '{"key":"value"}' --target staging-settings + ``` + +- Non-interactive mode with EVM log trigger + + ```bash + # If your EVM log trigger handler is the second handler in your workflow, use --trigger-index 1 + # --evm-event-index 0 means you want the first event from that transaction + cre workflow simulate my-workflow --non-interactive --trigger-index 1 --evm-tx-hash 0x420721d7d00130a03c5b525b2dbfd42550906ddb3075e8377f9bb5d1a5992f8e --evm-event-index 0 --target staging-settings + ``` + <Aside type="note" title="Dry run by default"> By default, `cre workflow simulate` performs a **dry run** for onchain write operations. It simulates the transaction to confirm it would succeed, but does not broadcast it to the network. This results in a successful log with an empty transaction hash (`0x`). To send a real transaction, use the `--broadcast` flag. @@ -6814,7 +7330,7 @@ For details, see [Using Multi-sig Wallets](/cre/guides/operations/using-multisig # Utility Commands Source: https://docs.chain.link/cre/reference/cli/utilities -Last Updated: 2025-11-20 +Last Updated: 2026-02-03 Utility commands provide helpful information and troubleshooting capabilities. @@ -6846,6 +7362,11 @@ cre update The CLI automatically checks if your version is outdated when you run certain commands. If a newer version is available, you'll see a warning message encouraging you to run `cre update`. </Aside> + +<Aside type="note" title="Updating existing projects"> + Running `cre update` updates the CLI itself. For existing projects, you may also need to update your SDK dependency to access new features. See [Updating Dependencies](/cre/reference/project-configuration#updating-dependencies) for instructions. +</Aside> + ## `cre version` Prints the current version of the CRE CLI. @@ -6859,12 +7380,12 @@ cre version **Example output:** ```bash -cre version v1.0.2 +cre version v1.0.10 ``` <Aside type="note" title="Version compatibility"> - Always check that your CLI version matches the version recommended in the documentation. The current recommended version is **v1.0.2**. See the [CLI Installation guide](/cre/getting-started/cli-installation) for more information. + Always check that your CLI version matches the version recommended in the documentation. The current recommended version is **v1.0.10**. See the [CLI Installation guide](/cre/getting-started/cli-installation) for more information. </Aside> ## Learn more @@ -6874,9 +7395,229 @@ cre version v1.0.2 --- +# The Confidential HTTP Capability (Experimental) +Source: https://docs.chain.link/cre/capabilities/confidential-http-ts +Last Updated: 2026-02-06 + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The **Confidential HTTP** capability is a privacy-preserving HTTP service powered by the Chainlink Privacy Standard. It enables your workflow to interact with external APIs while keeping sensitive data—such as API credentials, request body fields, and response data—confidential. + +## The problem it solves + +Traditional consensus mechanisms require all nodes to see and agree on the same data. While this provides strong reliability and tamper resistance, it creates challenges for use cases with strict privacy requirements: + +- **Regulatory compliance:** Some industries require that sensitive data never be exposed to multiple parties. +- **Credential security:** High-risk API credentials could cause damage if compromised or exposed in node memory. +- **Response privacy:** API responses may contain sensitive fields that should not be visible to the decentralized network. + +Confidential HTTP addresses these challenges by executing requests inside a **secure enclave** and offering optional **response encryption**. + +## How it works + +Confidential HTTP operates differently from the [regular HTTP capability](/cre/capabilities/http): + +1. **Request consensus:** Nodes in the Confidential HTTP DON reach quorum on the request parameters (forwarded by each Workflow DON node). +2. **Secret retrieval:** The Confidential HTTP DON fetches encrypted secrets from the [Vault DON](/cre/guides/workflow/secrets/using-secrets-deployed). +3. **Enclave execution:** Secrets are decrypted and injected into the request inside a secure enclave. The HTTP request executes from the enclave—credentials never exist in accessible memory. +4. **Response:** The response is returned to your workflow. If `EncryptOutput` is enabled, the response body is encrypted before leaving the enclave. + +This approach ensures: + +- **Credential isolation:** Secrets are encrypted at rest and in transit, and are decrypted only inside the enclave—never in node memory. +- **Response privacy:** You can optionally encrypt the full response body so that it leaves the enclave encrypted and can be decrypted only in your own backend service. +- **Single execution:** Exactly one API call is made, not one per node. + +## What's kept confidential + +| Component | How it's protected | +| :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Secrets** (API keys, tokens) | Fully confidential. Stored in the Vault DON, decrypted only inside the enclave. | +| **Request body** | Template-based injection: secrets referenced in the request body (e.g., `{{.myApiKey}}`) are resolved inside the enclave, so sensitive values never appear in workflow memory. | +| **Response body** | Optionally encrypted. When `EncryptOutput` is enabled, the full response is [AES-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode) encrypted before leaving the enclave. | + +## Use cases + +### Credential isolation + +A SaaS service fetches user data from an e-commerce provider API. The same credential could also modify user data if misused. Confidential HTTP ensures the credential is decrypted only inside the enclave, never accessible in node memory. + +### Response encryption + +A workflow calls a payment processor API to execute a transaction. The API response includes the transaction ID and success status, but also returns sensitive data like the user's account balance and an internal risk score. With Confidential HTTP and `EncryptOutput` enabled, the full response is encrypted before leaving the enclave—it can only be decrypted using the encryption key, for example in your own backend service. + +### Processing sensitive request data + +A workflow processes card transactions where the request contains card details and the API key provides processor access. Confidential HTTP keeps both the credentials and card details private through template-based injection, returning only the encrypted response to the workflow. + +### Guaranteed single execution + +An API endpoint cannot tolerate duplicate requests (e.g., initiating a payment or creating a unique transaction). + +With the [regular HTTP capability](/cre/capabilities/http), each node in the DON executes the request independently to reach consensus on the response. For non-idempotent operations, [`cacheSettings` mitigates](/cre/guides/workflow/using-http-client/post-request-ts#1-understanding-single-execution-with-cachesettings) this by enabling nodes to share cached responses, reducing duplicate calls in most cases. + +Confidential HTTP takes a different approach: by design, only one request is ever made from the enclave after quorum is reached on the request parameters. This provides an **architectural guarantee** of single execution. + +## When to use Confidential HTTP vs. regular HTTP + +### Use Confidential HTTP when: + +- The API response contains sensitive data that should not be visible to the network +- API credentials must never be accessible in node memory (enclave-only access) +- You need exactly one API call with zero tolerance for duplicates +- Regulatory or compliance requirements mandate data confidentiality + +### Use regular HTTP when: + +- **Querying multiple APIs and combining results**: For example, fetching prices from 3 different sources and computing a median. Each node calls all APIs, aggregates locally, then nodes reach consensus on the final value. + +- **Transforming data before consensus**: For example, parsing a complex API response, filtering fields, or performing calculations on the data before nodes agree on the result. + +- **Computing with a secret before the request**: For example, generating an HMAC signature for API authentication — use the [`runInNodeMode` pattern](/cre/guides/workflow/using-http-client/post-request-ts#2-the-low-level-runinnodemode-pattern) to access secrets and perform computations before making the request. + +- **No confidentiality requirements**: The API response doesn't contain sensitive data, and you don't need enclave-level protection for credentials. + +## Key differences from regular HTTP + +| Aspect | Regular HTTP | Confidential HTTP | +| :------------------------ | :------------------------------------ | :----------------------------- | +| **API calls** | One per node (multiple)\* | Exactly one (single) | +| **Consensus target** | Response data | Request parameters | +| **Execution environment** | Each node individually | Secure enclave | +| **Secrets exposure** | Decrypted in Workflow DON node memory | Decrypted only in the enclave | +| **Response handling** | Full response to all nodes | Optionally encrypted (AES-GCM) | +| **Data transformation** | Supported in workflow code | Not yet supported in enclave | + +\*For non-idempotent operations (POST, PUT, PATCH, DELETE), [`cacheSettings`](/cre/guides/workflow/using-http-client/post-request#1-understanding-single-execution-with-cachesettings) enables nodes to share cached responses, reducing multiple calls to a single execution in most cases. + +<Aside type="note" title="Confidential Compute"> + Confidential HTTP currently does not support complex data transformations within the enclave. A future **Confidential + Compute** capability will enable processing logic inside the enclave. +</Aside> + +## Learn more + +- **[Confidential API Interactions Guide](/cre/guides/workflow/using-confidential-http-client)**: Learn how to use the SDK to invoke the Confidential HTTP capability. +- **[Confidential HTTP Client SDK Reference](/cre/reference/sdk/confidential-http-client)**: See the detailed API reference for the `confidentialhttp.Client`. + +--- + +# Finality and Confidence Levels +Source: https://docs.chain.link/cre/concepts/finality-ts +Last Updated: 2025-12-10 + +Finality determines when a blockchain transaction is considered irreversible. Until a block is finalized, it could be reorganized (replaced by a different block if the chain temporarily forks), which means any data you read from it might change. + +Different blockchains achieve finality in different ways and at different speeds. CRE abstracts these differences through **confidence levels**, allowing you to specify your finality requirements without needing to know the underlying chain-specific implementation. + +## Understanding CRE's finality model + +CRE provides three confidence levels for reading blockchain data and monitoring events. These levels work consistently across all supported chains. + +### The three confidence levels + +| Confidence Level | Description | Use Case | +| ---------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| **`LATEST`** | The most recent block. No finality guarantees—the block could still be reorganized. | Non-critical, time-sensitive operations where speed matters more than certainty. | +| **`SAFE`** | A block that is unlikely to be reorganized, but not yet fully finalized. | A balance between speed and security for most operations. | +| **`FINALIZED`** | A block that is considered irreversible. This is the safest option. | Critical operations where you need absolute certainty the data won't change. | + +**Choosing the right level:** + +- **`FINALIZED`** — Use for financial transactions, critical state updates, or when incorrect data could cause significant issues +- **`SAFE`** — Use when you need reasonable confidence without waiting for full finality (good for most monitoring/alerting) +- **`LATEST`** — Use for real-time dashboards or displays where speed matters more than guaranteed accuracy + +### How confidence levels map to chains + +**SAFE and LATEST:** + +CRE uses the chain's native `safe` and `latest` block tags respectively for all supported chains. + +**FINALIZED:** + +When you specify `FINALIZED` in your workflow, CRE automatically maps this to its finality method—whether it uses the native finality tag or block depth (with the number of blocks specified for block depth). + +| Chain | Finality Method | +| ------------------------------- | ------------------------ | +| Arbitrum One / Arbitrum Sepolia | Native `finalized` tag | +| Avalanche / Avalanche Fuji | Native `finalized` tag | +| Base / Base Sepolia | Native `finalized` tag | +| BNB Chain / BNB Testnet | Native `finalized` tag | +| Ethereum / Ethereum Sepolia | Native `finalized` tag | +| OP Mainnet / OP Sepolia | Native `finalized` tag | +| Polygon / Polygon Amoy | Block depth (500 blocks) | + +## Finality for chain reads + +Chain read operations ([`CallContract`](/cre/reference/sdk/evm-client-ts#callcontract), [`BalanceAt`](/cre/reference/sdk/evm-client-ts#balanceat), [`FilterLogs`](/cre/reference/sdk/evm-client-ts#filterlogs), etc.) support confidence levels and custom block depths. + +### Using confidence levels + +For most read operations, use the standard confidence levels by passing [`LATEST_BLOCK_NUMBER`](/cre/reference/sdk/evm-client-ts#latest_block_number) or [`LAST_FINALIZED_BLOCK_NUMBER`](/cre/reference/sdk/evm-client-ts#last_finalized_block_number) as the `blockNumber` parameter. If you don't specify a block number, CRE defaults to `LATEST`. + +**Note:** The `SAFE` confidence level is not available for chain reads—only `LATEST` and `FINALIZED` are supported. + +### Custom block depths + +For use cases requiring fixed confirmation thresholds or historical state verification, you can specify **any explicit block number** instead of using the predefined confidence levels. This enables you to: + +- Implement custom finality rules tailored to your risk profile (e.g., "always wait 1,000 blocks") +- Meet regulatory requirements that mandate fixed, auditable confirmation thresholds +- Query historical state at specific past block heights for analysis or verification + +**When to use custom block depths:** + +- **Regulatory compliance** — Your interactions require provable, fixed confirmation thresholds for auditors +- **Changing chain parameters** — The chain's finality definition may change, but your security model must remain constant +- **Historical verification** — You need to verify state at a specific moment + +**Implementation:** + +Block numbers must be provided as `BigIntJson` objects. See [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths) for the conversion pattern and examples. + +## Finality for chain writes + +Chain write operations return a [`WriteReportReply`](/cre/reference/sdk/evm-client-ts#writereportreply) when the transaction is included in a block, not when it reaches finality. + +### What a successful response means + +When [`WriteReportReply`](/cre/reference/sdk/evm-client-ts#writereportreply) returns with `txStatus` equal to `TX_STATUS_SUCCESS`: + +- Your transaction was **included in a block** +- The transaction is **not necessarily finalized** yet + +The reply is returned as soon as the transaction appears in a block, not when the block reaches finality. This is important for time-sensitive workflows, but it means the transaction could still be reorganized. + +### Reorg handling + +If a block containing your transaction is reorganized: + +- CRE's Transaction Manager (TXM) automatically resubmits your transaction +- Gas bumping is applied as needed to ensure the transaction is included +- **Important:** The transaction hash may change during resubmission +- You are not automatically notified if the hash changes + +<Aside type="caution" title="For mission-critical applications"> + If you need absolute certainty that your write transaction reached finality, implement post-write verification by + reading the blockchain state after a custom number of confirmations. Do not rely solely on `WriteReportReply` for + finality confirmation. +</Aside> + +## Finality for event triggers + +EVM Log Triggers must use the three confidence levels (`LATEST`, `SAFE`, or `FINALIZED`). Custom block depths are not supported for triggers. + +By default, triggers use `SAFE` if no confidence level is specified. For details on configuring trigger confidence levels, see [EVM Log Trigger](/cre/reference/sdk/triggers/evm-log-trigger-ts#configuration). + +--- + # Avoiding Non-Determinism in Workflows Source: https://docs.chain.link/cre/concepts/non-determinism-ts -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 <Aside type="note" title="TL;DR"> In DON mode, all nodes must execute identical code paths to reach consensus. Non-deterministic code causes nodes to @@ -6911,7 +7652,7 @@ const obj = { b: 2, a: 1 } // Order may vary across runtimes or serialization for (const key in obj) { - console.log(key) // Could be "b", "a" or "a", "b" + // key could be "b", "a" or "a", "b" — non-deterministic! } ``` @@ -6922,7 +7663,7 @@ const obj = { b: 2, a: 1 } // Preserves insertion order for (const key of Object.keys(obj)) { - console.log(key, obj[key]) // "b", "a" (insertion order) + // key order: "b", "a" (insertion order) } ``` @@ -6933,7 +7674,7 @@ const obj = { b: 2, a: 1 } // Guaranteed alphabetical order for (const key of Object.keys(obj).sort()) { - console.log(key, obj[key]) // "a", "b" (alphabetically sorted) + // key order: "a", "b" (alphabetically sorted) } ``` @@ -6949,7 +7690,7 @@ map.set("b", 2) map.set("a", 1) for (const [key, value] of map) { - console.log(key, value) // Always "b", then "a" + // Order: ["b", 2], then ["a", 1] — guaranteed } ``` @@ -6959,7 +7700,7 @@ for (const [key, value] of map) { const set = new Set(["b", "a"]) for (const value of set) { - console.log(value) // Always "b", then "a" + // Order: "b", then "a" — guaranteed } ``` @@ -6991,11 +7732,11 @@ const firstSuccess = await Promise.any([fetchFromAPI1(), fetchFromAPI2()]) **Good: Deterministic order with `.result()`** ```typescript -import { cre, type Runtime, type NodeRuntime, consensusMedianAggregation } from "@chainlink/cre-sdk" +import { HTTPClient, type Runtime, type NodeRuntime, consensusMedianAggregation } from "@chainlink/cre-sdk" // Fetch from API 1, then API 2, in a fixed order const fetchPrice = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // Try first API const response1 = httpClient @@ -7054,7 +7795,7 @@ const now = runtime.now() // Same timestamp across all nodes runtime.log(`Current time: ${now.toISOString()}`) ``` -The `runtime.now()` method returns a `Date` object representing DON Time—a consensus-derived timestamp that all nodes agree on. See [Time in CRE](/cre/concepts/time-in-cre) for more details. +The `runtime.now()` method returns a `Date` object representing DON Time—a consensus-derived timestamp that all nodes agree on. See [Time in CRE](/cre/guides/workflow/time-in-workflows-ts) for more details. ## 4. Working with LLMs @@ -7083,18 +7824,131 @@ Large Language Models (LLMs) generate different responses for the same prompt, e ## Related concepts -- **[Time in CRE](/cre/concepts/time-in-cre)**: Learn about DON Time and why `runtime.now()` is required +- **[Time in CRE](/cre/guides/workflow/time-in-workflows-ts)**: Learn about DON Time and why `runtime.now()` is required - **[Consensus Computing](/cre/concepts/consensus-computing)**: Deep dive into how nodes reach agreement - **[Core SDK Reference](/cre/reference/sdk/core-ts)**: Details on `Runtime`, `NodeRuntime`, and the `.result()` pattern --- +# Before You Build +Source: https://docs.chain.link/cre/getting-started/before-you-build-ts +Last Updated: 2026-02-04 + +You've completed the Getting Started guide and built a workflow that fetches offchain data, reads from a smart contract, performs calculations, and writes results onchain. You're ready to build your own workflows. + +Before you do, take two minutes to understand how CRE differs from typical development. These tips will save you debugging time. + +## Library compatibility + +Your TypeScript code compiles to WebAssembly and runs in a QuickJS environment, **not Node.js**. Some NPM packages won't work if they rely on Node.js-specific APIs like `node:crypto` or `node:fs`. + +**Before using a third-party package:** + +1. Check if it relies on Node.js built-in modules +2. Test with `cre workflow simulate` — simulation uses the same WASM environment as production, so compatibility issues surface immediately + + +<Aside type="tip" title="Cryptography libraries"> + If you need cryptographic functions, <a href="https://paulmillr.com/noble/" target="_blank" rel="noopener noreferrer">Noble</a> is a popular JavaScript cryptography library that works well with QuickJS. Always verify any third-party library in simulation before deploying. +</Aside> + + +<Aside type="tip" title="Learn more"> + See [TypeScript Runtime Environment](/cre/concepts/typescript-wasm-runtime) for details on QuickJS compatibility and how to [verify library support](/cre/concepts/typescript-wasm-runtime#checking-library-compatibility). +</Aside> + +## Working with Solidity integers + +When sending values to smart contracts, always use `bigint` (with the `n` suffix) in your workflow code. JavaScript `number` loses precision for large values, causing **silent precision loss**. + +```typescript +// WRONG - silent precision loss +const amount = 10000000000000001 // 10 quadrillion + 1 +// Silently becomes 10000000000000000 (the +1 vanishes) + +// CORRECT - use bigint +const amount = 10000000000000001n // Stays exactly 10000000000000001 +``` + + +<Aside type="tip" title="Learn more"> + See [Writing Data Onchain](/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain#step-2-abi-encode-your-value) for the complete Solidity-to-TypeScript type mapping. +</Aside> + +## Working with time + +If your workflow uses timestamps (e.g., for API authentication or time-based queries), use `runtime.now()` instead of `Date.now()`. This ensures all nodes in the DON use the same timestamp and can reach consensus. + + +<Aside type="tip" title="Learn more"> + See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details on DON time and best practices. +</Aside> + + +<Aside type="note" title="Going deeper"> + These are the most common cases. For a complete guide to non-determinism (object iteration, Promise handling, and more), see [Avoiding Non-Determinism in Workflows](/cre/concepts/non-determinism). +</Aside> + +## What's next? + +Here are resources to help you go from simulation to production. + +### Learn from examples + +- **[Run the Custom Data Feed Demo](/cre/templates/running-demo-workflow)** — A starter template you can run locally and customize +- **[Browse all Templates](/cre/templates)** — Building blocks for specific patterns (secrets, HTTP auth, streams) and starter templates +- **[AI-Powered Prediction Market](/cre/demos/prediction-market)** — Full end-to-end demo integrating CRE with Gemini AI and Firebase + +### Deploy to production + + +<Aside type="note" title="Deployment access required"> + Deploying requires Early Access approval. <a href="https://cre.chain.link/request-access" target="_blank" rel="noopener noreferrer">Request access here</a>. While you wait, continue building and simulating workflows. +</Aside> + +1. **[Link a Wallet Key](/cre/organization/linking-keys)** — Connect your wallet to your organization +2. **[Deploy Your Workflow](/cre/guides/operations/deploying-workflows)** — Push your workflow live +3. **[Monitor Your Workflow](/cre/guides/operations/monitoring-workflows)** — Watch it execute and debug issues + +### Explore different triggers + +You used a Cron trigger. Most production workflows react to events: + +- **[HTTP Trigger](/cre/guides/workflow/using-triggers/http-trigger/overview)** — Trigger via API calls +- **[EVM Log Trigger](/cre/guides/workflow/using-triggers/evm-log-trigger)** — React to onchain events + +### Add secrets + +Real workflows need API keys and sensitive data: + +- **[Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation)** — Local development +- **[Using Secrets with Deployed Workflows](/cre/guides/workflow/secrets/using-secrets-deployed)** — Store secrets in the Vault DON for production +- **[Managing Secrets with 1Password](/cre/guides/workflow/secrets/managing-secrets-1password)** — Best practice: inject secrets at runtime + +### Build your own consumer contract + +- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)** — Create contracts that receive CRE data + +## Reference + +Dive deeper into concepts from this guide: + +| Topic | Resources | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Workflow structure** | [Core SDK](/cre/reference/sdk/core), [Triggers Overview](/cre/guides/workflow/using-triggers/overview) | +| **HTTP & offchain data** | [API Interactions](/cre/guides/workflow/using-http-client), [Consensus & Aggregation](/cre/reference/sdk/consensus) | +| **EVM interactions** | [EVM Client Overview](/cre/guides/workflow/using-evm-client/overview), [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read), [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview) | +| **Configuration** | [Project Configuration](/cre/reference/project-configuration), [Secrets Guide](/cre/guides/workflow/secrets) | +| **All capabilities** | [Capabilities Overview](/cre/capabilities) | + +--- + # Part 1: Project Setup & Simulation Source: https://docs.chain.link/cre/getting-started/part-1-project-setup-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 <Aside type="note" title="SDK Language: TypeScript"> - You're viewing the **TypeScript** version of this guide. If you prefer Go, use the language selector in the right + You're viewing the **TypeScript** version of this guide. If you prefer Go, use the language selector in the left sidebar to switch to the Go version. </Aside> @@ -7113,7 +7967,7 @@ Before you begin, ensure you have the following: - **CRE CLI**: See the [Installation Guide](/cre/getting-started/cli-installation/macos-linux) for details. - **CRE account & authentication**: You must have a CRE account and be logged in with the CLI. See [Create your account](/cre/account/creating-account) and [Log in with the CLI](/cre/account/cli-login) for instructions. -- **Bun**: You must have <a href="https://bun.com/docs" target="blank">Bun</a> version 1.2.21 or higher installed. Check your version with bun --version. See [Install Bun](https://bun.sh/) for instructions. +- **Bun**: You must have <a href="https://bun.com/docs" target="blank">Bun</a> version 1.2.21 or higher installed. Check your version with bun --version. See [Install Bun](https://bun.com) for instructions. - **Funded Sepolia Account**: An account with Sepolia ETH to pay for transaction gas fees. Go to <a href="https://faucets.chain.link" target="blank">faucets.chain.link</a> to get some Sepolia ETH. ## Step 1: Verify your authentication @@ -7234,7 +8088,7 @@ Open `onchain-calculator/my-calculator-workflow/main.ts` to see its contents: Code snippet for onchain-calculator/my-calculator-workflow/main.ts: ```typescript -import { cre, Runner, type Runtime } from "@chainlink/cre-sdk" +import { CronCapability, handler, Runner, type Runtime } from "@chainlink/cre-sdk" type Config = { schedule: string @@ -7246,17 +8100,15 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` **Key components:** @@ -7266,6 +8118,12 @@ main() - **`initWorkflow`**: Creates the workflow by registering handlers (trigger-callback pairs). This is where you define what events your workflow responds to. - **`main`**: The entry point that creates a `Runner`, passes your config type, and runs the workflow. +<Aside type="note" title="Automatic execution"> + You don't need to call `main()` at the end of your file—the SDK automatically executes it during compilation. The SDK + also handles error reporting automatically, so you don't need to add `.catch()` unless you need custom error handling. + See the [Core SDK Reference](/cre/reference/sdk/core-ts#main) for details. +</Aside> + ## Step 4: Configure your workflow Now that you've explored the generated files, let's configure your workflow for simulation. You'll need to adjust a few configuration files. @@ -7524,8 +8382,16 @@ Replace the entire content of `onchain-calculator/my-calculator-workflow/main.ts Code snippet for onchain-calculator/my-calculator-workflow/main.ts: ```typescript -import { cre, consensusMedianAggregation, Runner, type NodeRuntime, type Runtime } from "@chainlink/cre-sdk" - +import { + CronCapability, + HTTPClient, + handler, + consensusMedianAggregation, + Runner, + type NodeRuntime, + type Runtime, +} from "@chainlink/cre-sdk" + type Config = { schedule: string apiUrl: string @@ -7536,15 +8402,15 @@ type MyResult = { } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } // fetchMathResult is the function passed to the runInNodeMode helper. // It contains the logic for making the request and parsing the response. const fetchMathResult = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const req = { url: nodeRuntime.config.apiUrl, @@ -7580,8 +8446,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` @@ -7797,7 +8661,10 @@ Code snippet for onchain-calculator/my-calculator-workflow/main.ts: ```typescript import { - cre, + CronCapability, + HTTPClient, + EVMClient, + handler, consensusMedianAggregation, Runner, type NodeRuntime, @@ -7829,14 +8696,14 @@ type MyResult = { } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } // fetchMathResult is the function passed to the runInNodeMode helper. const fetchMathResult = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const req = { url: nodeRuntime.config.apiUrl, @@ -7871,7 +8738,7 @@ const onCronTrigger = (runtime: Runtime<Config>): MyResult => { throw new Error(`Unknown chain name: ${evmConfig.chainName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) // Encode the function call using the Storage ABI const callData = encodeFunctionData({ @@ -7914,8 +8781,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` @@ -7978,7 +8843,7 @@ You have successfully read a value from a smart contract and combined it with of # Part 4: Writing Onchain Source: https://docs.chain.link/cre/getting-started/part-4-writing-onchain-ts -Last Updated: 2025-11-04 +Last Updated: 2025-12-09 In the previous parts, you successfully fetched offchain data and read from a smart contract. Now, you'll complete the "Onchain Calculator" by writing your computed result back to the blockchain. @@ -8001,20 +8866,20 @@ Here is the source code for the contract so you can see how it works: of how this works in a later guide. </Aside> -```solidity +```sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import { IReceiverTemplate } from "./keystone/IReceiverTemplate.sol"; +import {ReceiverTemplate} from "./ReceiverTemplate.sol"; /** * @title CalculatorConsumer (Testing Version) * @notice This contract receives reports from a CRE workflow and stores the results of a calculation onchain. - * @dev This version uses IReceiverTemplate without configuring any security checks, making it compatible - * with the mock Forwarder used during simulation. All permission fields remain at their default zero - * values (disabled). + * @dev Inherits from ReceiverTemplate which provides security checks. The forwarder address must be + * configured at deployment. Additional security checks (workflowId, workflowName, author) can be enabled via setter + * functions. */ -contract CalculatorConsumer is IReceiverTemplate { +contract CalculatorConsumer is ReceiverTemplate { // Struct to hold the data sent in a report from the workflow struct CalculatorResult { uint256 offchainValue; @@ -8031,16 +8896,22 @@ contract CalculatorConsumer is IReceiverTemplate { event ResultUpdated(uint256 indexed resultId, uint256 finalResult); /** - * @dev The constructor doesn't set any security checks. - * The IReceiverTemplate parent constructor will initialize all permission fields to zero (disabled). + * @notice Constructor requires the forwarder address for security + * @param _forwarderAddress The address of the Chainlink Forwarder contract (for testing: MockForwarder) + * @dev The forwarder address enables the first layer of security - only the forwarder can call onReport. + * Additional security checks can be configured after deployment using setter functions. */ - constructor() {} + constructor( + address _forwarderAddress + ) ReceiverTemplate(_forwarderAddress) {} /** * @notice Implements the core business logic for processing reports. - * @dev This is called automatically by IReceiverTemplate's onReport function after security checks. + * @dev This is called automatically by ReceiverTemplate's onReport function after security checks. */ - function _processReport(bytes calldata report) internal override { + function _processReport( + bytes calldata report + ) internal override { // Decode the report bytes into our CalculatorResult struct CalculatorResult memory calculatorResult = abi.decode(report, (CalculatorResult)); @@ -8056,7 +8927,9 @@ contract CalculatorConsumer is IReceiverTemplate { // This function is a "dry-run" utility. It allows an offchain system to check // if a prospective result is an outlier before submitting it for a real onchain update. // It is also used to guide the binding generator to create a method that accepts the CalculatorResult struct. - function isResultAnomalous(CalculatorResult memory _prospectiveResult) public view returns (bool) { + function isResultAnomalous( + CalculatorResult memory _prospectiveResult + ) public view returns (bool) { // A result is not considered anomalous if it's the first one. if (resultCount == 0) { return false; @@ -8069,7 +8942,7 @@ contract CalculatorConsumer is IReceiverTemplate { } ``` -The contract is already deployed for you on Sepolia at the following address: <a href="https://sepolia.etherscan.io/address/0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54#code" target="_blank" rel="noopener noreferrer">`0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54`</a>. You will use this address in your configuration file. +The contract is already deployed for you on Sepolia at the following address: <a href="https://sepolia.etherscan.io/address/0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb#code" target="_blank" rel="noopener noreferrer">`0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb`</a>. You will use this address in your configuration file. ## Step 2: Update your workflow configuration @@ -8082,7 +8955,7 @@ Add the `CalculatorConsumer` contract address to your `config.staging.json`: "evms": [ { "storageAddress": "0xa17CF997C28FF154eDBae1422e6a50BeF23927F4", - "calculatorConsumerAddress": "0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54", + "calculatorConsumerAddress": "0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb", "chainName": "ethereum-testnet-sepolia", "gasLimit": "500000" } @@ -8113,7 +8986,10 @@ Code snippet for onchain-calculator/my-calculator-workflow/main.ts: ```typescript import { - cre, + CronCapability, + HTTPClient, + EVMClient, + handler, consensusMedianAggregation, Runner, type NodeRuntime, @@ -8151,9 +9027,9 @@ type MyResult = { const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } const onCronTrigger = (runtime: Runtime<Config>): MyResult => { @@ -8175,7 +9051,7 @@ const onCronTrigger = (runtime: Runtime<Config>): MyResult => { runtime.log(`Successfully fetched offchain value: ${offchainValue}`) // Step 2: Read onchain data using the EVM client - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) const callData = encodeFunctionData({ abi: Storage, @@ -8234,7 +9110,7 @@ const onCronTrigger = (runtime: Runtime<Config>): MyResult => { const fetchMathResult = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const req = { url: nodeRuntime.config.apiUrl, @@ -8260,7 +9136,7 @@ function updateCalculatorResult( ): string { runtime.log(`Updating calculator result for consumer: ${evmConfig.calculatorConsumerAddress}`) - const evmClient = new cre.capabilities.EVMClient(chainSelector) + const evmClient = new EVMClient(chainSelector) // Encode the CalculatorResult struct according to the contract's ABI const reportData = encodeAbiParameters( @@ -8306,8 +9182,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` @@ -8348,7 +9222,7 @@ main() <Aside type="note" title="Funding Your Account"> This step submits an onchain transaction, which requires gas. Before running the simulation, verify that the account associated with the private key from [Part - 1](/cre/getting-started/part-1-project-setup#step-3-configure-your-workflow) is funded with sufficient Sepolia ETH. + 1](/cre/getting-started/part-1-project-setup-ts#set-up-your-private-key) is funded with sufficient Sepolia ETH. An unfunded account will cause the transaction to fail, often with an error message like `gas required exceeds allowance`. @@ -8371,31 +9245,35 @@ Your workflow will now show the complete end-to-end execution, including the fin ```bash Workflow compiled -2025-11-03T19:09:22Z [SIMULATION] Simulator Initialized - -2025-11-03T19:09:22Z [SIMULATION] Running trigger trigger=cron-trigger@1.0.0 -2025-11-03T19:09:22Z [USER LOG] Successfully fetched offchain value: 39 -2025-11-03T19:09:22Z [USER LOG] Successfully read onchain value: 22 -2025-11-03T19:09:22Z [USER LOG] Final calculated result: 61 -2025-11-03T19:09:22Z [USER LOG] Updating calculator result for consumer: 0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54 -2025-11-03T19:09:22Z [USER LOG] Writing report to consumer contract - offchainValue: 39, onchainValue: 22, finalResult: 61 -2025-11-03T19:09:25Z [USER LOG] Waiting for write report response -2025-11-03T19:09:25Z [USER LOG] Write report transaction succeeded: 0xcc99cf4fcdc1262162762f747eeb660b52cc117754c953fdb72842414fcecdc4 -2025-11-03T19:09:25Z [USER LOG] View transaction at https://sepolia.etherscan.io/tx/0xcc99cf4fcdc1262162762f747eeb660b52cc117754c953fdb72842414fcecdc4 -2025-11-03T19:09:25Z [USER LOG] Workflow finished successfully! offchainValue: 39, onchainValue: 22, finalResult: 61, txHash: 0xcc99cf4fcdc1262162762f747eeb660b52cc117754c953fdb72842414fcecdc4 +2026-01-09T17:52:05Z [SIMULATION] Simulator Initialized + +2026-01-09T17:52:05Z [SIMULATION] Running trigger trigger=cron-trigger@1.0.0 +2026-01-09T17:52:06Z [USER LOG] Successfully fetched offchain value: 68 +2026-01-09T17:52:06Z [USER LOG] Successfully read onchain value: 22 +2026-01-09T17:52:06Z [USER LOG] Final calculated result: 90 +2026-01-09T17:52:06Z [USER LOG] Updating calculator result for consumer: 0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb +2026-01-09T17:52:06Z [USER LOG] Writing report to consumer contract - offchainValue: 68, onchainValue: 22, finalResult: 90 +2026-01-09T17:52:12Z [USER LOG] Waiting for write report response +2026-01-09T17:52:12Z [USER LOG] Write report transaction succeeded: 0x6346d9eeca2f2875131d38aa9903a216f16e3cc7188f0ac6a1d5cd1fcbfbf9e6 +2026-01-09T17:52:12Z [USER LOG] View transaction at https://sepolia.etherscan.io/tx/0x6346d9eeca2f2875131d38aa9903a216f16e3cc7188f0ac6a1d5cd1fcbfbf9e6 +2026-01-09T17:52:12Z [USER LOG] Workflow finished successfully! offchainValue: 68, onchainValue: 22, finalResult: 90, txHash: 0x6346d9eeca2f2875131d38aa9903a216f16e3cc7188f0ac6a1d5cd1fcbfbf9e6 Workflow Simulation Result: { - "finalResult": 61, - "offchainValue": 39, + "finalResult": 90, + "offchainValue": 68, "onchainValue": 22, - "txHash": "0xcc99cf4fcdc1262162762f747eeb660b52cc117754c953fdb72842414fcecdc4" + "txHash": "0x6346d9eeca2f2875131d38aa9903a216f16e3cc7188f0ac6a1d5cd1fcbfbf9e6" } -2025-11-03T19:09:25Z [SIMULATION] Execution finished signal received -2025-11-03T19:09:25Z [SIMULATION] Skipping WorkflowEngineV2 +2026-01-09T17:52:12Z [SIMULATION] Execution finished signal received +2026-01-09T17:52:12Z [SIMULATION] Skipping WorkflowEngineV2 ``` +- **`[USER LOG]`**: You can see all of your `logger.info()` calls showing the complete workflow execution, including the offchain value (`68`), onchain value (`22`), final calculation (`90`), and the transaction hash. +- **`[SIMULATION]`**: These are system-level messages from the simulator showing its internal state. +- **`Workflow Simulation Result`**: This is the final return value of your workflow. The `MyResult` object contains all the values (68 + 22 = 90) and the transaction hash confirming the write operation succeeded. + ## Step 5: Verify the result onchain ### **1. Check the Transaction** @@ -8410,13 +9288,13 @@ Click the URL (or copy and paste it into your browser) to see the full details o **What are you seeing on a blockchain explorer?** -You'll notice the transaction's `to` address is not the `CalculatorConsumer` contract you intended to call. Instead, it's to a **Forwarder** contract. Your workflow sends a secure report to the Forwarder, which then verifies the request and makes the final call to the `CalculatorConsumer` on your workflow's behalf. To learn more, see the [Onchain Write guide](/cre/guides/workflow/using-evm-client/onchain-write). +You'll notice the transaction's `to` address is not the `CalculatorConsumer` contract you intended to call. Instead, it's to a **Forwarder** contract. Your workflow sends a secure report to the Forwarder, which then verifies the request and makes the final call to the `CalculatorConsumer` on your workflow's behalf. To learn more, see the [Onchain Write guide](/cre/guides/workflow/using-evm-client/onchain-write/overview). ### **2. Check the contract state** While your wallet interacted with the Forwarder, the `CalculatorConsumer` contract's state was still updated. You can verify this change directly on Etherscan: -- Navigate to the `CalculatorConsumer` contract address: <a href="https://sepolia.etherscan.io/address/0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54#readContract" target="_blank" rel="noopener noreferrer">`0xF3abEAa889e46c6C5b9A0bD818cE54Cc4eAF8A54`</a>. +- Navigate to the `CalculatorConsumer` contract address: <a href="https://sepolia.etherscan.io/address/0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb#readContract" target="_blank" rel="noopener noreferrer">`0x95e10BaC2B89aB4D8508ccEC3f08494FcB3D23cb`</a>. - Expand the `latestResult` function and click **Query**. The values should match the `finalResult`, `offchainValue`, and `onchainValue` from your workflow logs. This completes the end-to-end loop: triggering a workflow, fetching data, reading onchain state, and verifiably writing the result back to a public blockchain. @@ -8424,13 +9302,13 @@ This completes the end-to-end loop: triggering a workflow, fetching data, readin To learn more about implementing consumer contracts and the secure write process, see these guides: - **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)**: Learn how to create your own secure consumer contracts with proper validation. -- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write)**: Dive deeper into the write patterns. +- **[Onchain Write Guide](/cre/guides/workflow/using-evm-client/onchain-write/overview-ts)**: Dive deeper into the write patterns. ## Next steps You've now mastered the complete CRE development workflow! -- **[Conclusion & Next Steps](/cre/getting-started/conclusion)**: Review what you've learned and find resources for advanced topics. +- **[Before You Build](/cre/getting-started/before-you-build-ts)**: Don't skip this — critical tips before building your own workflows. --- @@ -8523,7 +9401,7 @@ The following code shows a complete, runnable workflow that triggers on a schedu Code snippet for Fetching Single Secret (TypeScript): ```typescript -import { cre, Runner, type Runtime } from "@chainlink/cre-sdk" +import { CronCapability, handler, Runner, type Runtime } from "@chainlink/cre-sdk" // Config can be an empty object if you don't need any parameters from config.json type Config = Record<string, never> @@ -8547,9 +9425,9 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { // initWorkflow is the entry point for the workflow const initWorkflow = () => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] + return [handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] } // main is the entry point for the WASM binary @@ -8557,8 +9435,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ### Step 4: Configure secrets path in `workflow.yaml` @@ -8620,7 +9496,7 @@ Now you can fetch both secrets in your workflow code: Code snippet for Fetching Multiple Secrets (TypeScript): ```typescript -import { cre, Runner, type Runtime } from "@chainlink/cre-sdk" +import { CronCapability, handler, Runner, type Runtime } from "@chainlink/cre-sdk" // Config can be an empty object if you don't need any parameters from config.json type Config = Record<string, never> @@ -8643,9 +9519,9 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { // initWorkflow is the entry point for the workflow const initWorkflow = () => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] + return [handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] } // main is the entry point for the WASM binary @@ -8653,285 +9529,869 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` --- -# Onchain Read -Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-read-ts -Last Updated: 2025-11-04 +# Using Time in Workflows +Source: https://docs.chain.link/cre/guides/workflow/time-in-workflows-ts +Last Updated: 2026-02-03 -This guide explains how to read data from a smart contract from within your CRE workflow. The TypeScript SDK uses [viem](https://viem.sh/) for ABI handling and the SDK's [`EVMClient`](/cre/reference/sdk/evm-client-ts) to create a type-safe developer experience. +<Aside type="note" title="TL;DR"> + CRE provides **DON Time**: a consensus-derived timestamp so different nodes see the *same time*. Use the SDK's runtime + call, `runtime.now()`, whenever your workflow logic depends on time. Do **not** use `Date.now()` or other local time + sources in DON Mode — they introduce non-determinism. +</Aside> -## The read pattern +## The problem: Why time needs consensus -Reading from a contract follows this pattern: +Workflows often rely on time for decisions (market-hours checks), scheduling (retries/backoffs), and observability (log timestamps). In a decentralized network, nodes do not share an identical clock—clock drift, resource contention, and OS scheduling can skew each node's local time. If each node consults its own clock: -1. **Define your contract ABI**: Create a TypeScript file with your contract's ABI using <a href="https://viem.sh/docs/abi/parseAbi" target="_blank">viem's `parseAbi`</a> (inline) or store it in `contracts/abi/` for complex workflows -2. **Get network information**: Use the SDK's `getNetwork()` helper to look up chain selector and other network details -3. **Instantiate the EVM Client**: Create an `EVMClient` instance with the chain selector -4. **Encode the function call**: Use <a href="https://viem.sh/docs/contract/encodeFunctionData#encodefunctiondata" target="_blank">viem's `encodeFunctionData()`</a> to ABI-encode your function call -5. **Encode the call message**: Use `encodeCallMsg()` to create a properly formatted call message with `from`, `to`, and `data` -6. **Call the contract**: Use `callContract(runtime, {...})` to execute the read operation -7. **Decode the result**: Use <a href="https://viem.sh/docs/contract/decodeFunctionResult#decodefunctionresult" target="_blank">viem's `decodeFunctionResult()`</a> to decode the returned data -8. **Await the result**: Call `.result()` on the returned object to get the consensus-verified result +- Different nodes may take **different branches** of your logic (e.g., one thinks the market is open, another does not). +- Logs across nodes become **hard to correlate**. +- Data fetched using time (e.g., "fetch price at timestamp N") can be **inconsistent**. -## Step-by-step example +**DON Time** removes these divergences by making time **deterministic in the DON**. -Let's read a value from a simple `Storage` contract with a `get() view returns (uint256)` function. +## The solution: DON time -### 1. Define the contract ABI +**DON Time** is a timestamp computed by an <a href="https://docs.chain.link/architecture-overview/off-chain-reporting" target="_blank" rel="noopener noreferrer">OCR (Off-Chain Reporting)</a> plugin and agreed upon by the nodes participating in CRE. You access it through the SDK's runtime call, `runtime.now()`, not via JavaScript's `Date.now()`. The `runtime.now()` method returns a standard JavaScript `Date` object. -For simple contracts, you can define the ABI inline using viem's `parseAbi`: +**Key properties:** -```typescript -import { parseAbi } from "viem" +- **Deterministic across nodes**: nodes see the same timestamp. +- **Sequenced per workflow**: time responses are associated with a **time-call sequence number** inside each workflow execution (1st call, 2nd call, …). Node execution timing might be slightly off, but a given call will resolve to the **same DON timestamp**. +- **Low latency**: the plugin runs continuously with **delta round = 0**, and each node **transmits** results back to outstanding requests at the end of every round. +- **Tamper-resistant**: workflows don't expose host machine time, reducing timing-attack surface. -const storageAbi = parseAbi(["function get() view returns (uint256)"]) -``` +<Aside type="note" title="A Note on Accuracy"> + DON Time is computed as the **median of nodes' local observations** in each round. It is designed for **consistency** + across the DON rather than exact alignment to an external UTC source. Think of it as a highly reliable clock for your + workflows. Do not treat it as a high-precision clock. +</Aside> -For complex workflows with multiple contracts, it's recommended to create separate ABI files in a `contracts/abi/` directory. See [Part 3 of the Getting Started guide](/cre/getting-started/part-3-reading-onchain-value-ts#step-3-create-the-contract-abi-file) for an example of this pattern. +## How it works: A high-level view -### 2. The workflow logic +1. Your workflow calls **`runtime.now()`**. +2. **The Chainlink network takes this request**: The Workflow Engine's **TimeProvider** assigns that call a **sequence number** and enqueues it in the **DON Time Store**. +3. **All the nodes agree on a single time (the DON Time)**: The **OCR Time Plugin** on each node reaches consensus on a new DON timestamp (the median of observed times). +4. Each node **returns** the newest DON timestamp to every pending request and updates its **last observed DON time** cache. +5. The result is written back into the WebAssembly execution, and your workflow continues. -Here's a complete example of reading from a Storage contract: +Because requests are sequenced, *Call 1* for a workflow instance will always return the same DON timestamp on every node. If Node A hits *Call 2* before Node B, A will block until the DON timestamp for *Call 2* is produced; when B reaches *Call 2*, it immediately reuses that value. -```typescript -import { - cre, - getNetwork, - encodeCallMsg, - bytesToHex, - LAST_FINALIZED_BLOCK_NUMBER, - type Runtime, - Runner, -} from "@chainlink/cre-sdk" -import { type Address, encodeFunctionData, decodeFunctionResult, parseAbi, zeroAddress } from "viem" -import { z } from "zod" +## Execution modes: DON mode vs. Node mode -// Define config schema with Zod -const configSchema = z.object({ - contractAddress: z.string(), - chainSelectorName: z.string(), -}) +### DON mode (default for workflows) -type Config = z.infer<typeof configSchema> +- Time is **consensus-based** and **deterministic**. +- Use for **any** logic where different outcomes across nodes would be a bug. Examples: + - Market-hours gates + - Time-windowed queries ("last 15 minutes") + - Retry/backoff logic that must align across nodes + - Timestamps used for cross-node correlation (logging, audit trails) -// Define the Storage contract ABI -const storageAbi = parseAbi(["function get() view returns (uint256)"]) +### Node mode (advanced / special cases) -const onCronTrigger = (runtime: Runtime<Config>): string => { - // Get network information - const network = getNetwork({ - chainFamily: "evm", - chainSelectorName: runtime.config.chainName, - isTestnet: true, - }) +- Workflow authors handle consensus themselves. +- `runtime.now()` in Node Mode is a non-blocking call that returns the **last generated DON timestamp** from the local node's cache. +- Useful in situations where you already expect non-determinism (e.g., inherently variable HTTP responses). - if (!network) { - throw new Error(`Network not found: ${runtime.config.chainSelectorName}`) +<Aside type="caution" title="Use DON Mode"> + Unless you have a specific reason and understand the trade-offs, **always use DON Mode** for time-dependent logic. +</Aside> + +## Best practices: Avoiding non-determinism in DON mode + +When running in DON Mode, you get determinism **if and only if** you base time-dependent logic on DON Time. + +**Avoid** these patterns: + +- **Reading local time** (`Date.now()`, `new Date()`, etc.). Always use `runtime.now()` from the CRE SDK. +- **Mixing time sources** in the same control path. +- **Per-node "sleeps" based on local time** that gate deterministic decisions. + +**Deterministic patterns:** + +- ✅ Gate behavior with: + ```typescript + const now = runtime.now() + if (isMarketOpen(now)) { + // proceed } + ``` +- ✅ Compute windows from DON Time: + ```typescript + const now = runtime.now() + const fifteenMinutesMs = 15 * 60 * 1000 + const windowStart = new Date(now.getTime() - fifteenMinutesMs) + fetchData(windowStart, now) + ``` - // Create EVM client with chain selector - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +## FAQ - // Encode the function call - const callData = encodeFunctionData({ - abi: storageAbi, - functionName: "get", - args: [], // No arguments for this function - }) +**Is DON Time "real UTC time"?** - // Call the contract - const contractCall = evmClient - .callContract(runtime, { - call: encodeCallMsg({ - from: zeroAddress, - to: runtime.config.contractAddress as Address, - data: callData, - }), - blockNumber: LAST_FINALIZED_BLOCK_NUMBER, - }) - .result() +It's the **median of node observations** per round. It closely tracks real time but prioritizes **consistency** over absolute accuracy. - // Decode the result (convert Uint8Array to hex string for viem) - const storedValue = decodeFunctionResult({ - abi: storageAbi, - functionName: "get", - data: bytesToHex(contractCall.data), - }) +**What is the resolution?** - runtime.log(`Successfully read storage value: ${storedValue.toString()}`) - return storedValue.toString() -} +New DON timestamps are produced continuously (multiple per second). Treat it as coarse-grained real time suitable for gating and logging, not sub-millisecond measurement. -const initWorkflow = (config: Config) => { - return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ - schedule: "*/10 * * * * *", // Every 10 seconds - }), - onCronTrigger - ), - ] -} +**Why can't I use `Date.now()`?** -export async function main() { - const runner = await Runner.newRunner<Config>() - await runner.run(initWorkflow) -} +`Date.now()` reads the local system clock, which differs slightly on each node. This breaks consensus—nodes may execute different code paths and fail to agree on the workflow result. -main() -``` +--- -## Understanding the components +# Making Confidential Requests +Source: https://docs.chain.link/cre/guides/workflow/using-confidential-http-client/making-requests-ts +Last Updated: 2026-02-10 -<Aside type="note" title="Type-safe addresses"> - Notice the `as Address` type assertion when passing `contractAddress` to `encodeCallMsg`. This tells TypeScript the - string is a valid Ethereum address, which is required by viem's `encodeCallMsg` function. The `Address` type is - imported from `viem`. +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. </Aside> -### Network lookup with `getNetwork()` +The `ConfidentialHTTPClient` is the SDK's interface for the underlying [Confidential HTTP Capability](/cre/capabilities/confidential-http). It allows your workflow to make privacy-preserving API calls where secrets are injected inside a secure enclave and responses can be optionally encrypted. -The SDK provides a `getNetwork()` helper that looks up network information by name: +Unlike the regular [`HTTPClient`](/cre/reference/sdk/http-client), the Confidential HTTP client: -```typescript -const network = getNetwork({ - chainFamily: "evm", - chainSelectorName: "ethereum-testnet-sepolia", - isTestnet: true, -}) +- Executes the request in a secure **enclave** (not on each node individually) +- Injects secrets from the **Vault DON** using template syntax +- Optionally **encrypts the response** before returning it to your workflow -// Returns network info including: -// - chainSelector.selector (numeric ID) -// - name -// - chainType -``` +## Prerequisites -See the [EVM Client SDK Reference](/cre/reference/sdk/evm-client-ts#chain-selectors) for all available networks. +This guide assumes you have: -### Block number options +- A basic understanding of CRE. If you are new, complete the [Getting Started tutorial](/cre/getting-started/overview) first. +- Familiarity with [secrets management](/cre/guides/workflow/secrets) in CRE. -When calling `callContract()`, you can specify which block to read from: +## Step-by-step example -- **`LAST_FINALIZED_BLOCK_NUMBER`**: Read from the last finalized block (recommended for production) -- **`LATEST_BLOCK_NUMBER`**: Read from the latest block -- **Specific block**: Use an object with `{ absVal: "base64EncodedNumber", sign: "1" }` format +This example shows a workflow that makes a confidential GET request to an API, injecting a secret into the request headers using template syntax. -```typescript -import { LAST_FINALIZED_BLOCK_NUMBER, LATEST_BLOCK_NUMBER } from "@chainlink/cre-sdk" +### Step 1: Configure your workflow -// Read from finalized block (most common) -const contractCall = evmClient.callContract(runtime, { - call: encodeCallMsg({...}), - blockNumber: LAST_FINALIZED_BLOCK_NUMBER, -}).result() +Add the API URL to your `config.json` file. -// Or read from latest block -const contractCall = evmClient.callContract(runtime, { - call: encodeCallMsg({...}), - blockNumber: LATEST_BLOCK_NUMBER, -}).result() +```json +{ + "schedule": "0 */5 * * * *", + "url": "https://api.example.com/data", + "owner": "" +} ``` -### Encoding call messages with `encodeCallMsg()` +### Step 2: Set up secrets for simulation -The `encodeCallMsg()` helper converts your hex-formatted call data into the base64 format required by the EVM capability: +Confidential HTTP uses the `secrets.yaml` file. If you've already set up secrets for your project, you can reuse the same file. For a full walkthrough, see [Using Secrets in Simulation](/cre/guides/workflow/secrets/using-secrets-simulation). -```typescript -import { encodeCallMsg } from "@chainlink/cre-sdk" -import { zeroAddress } from "viem" +Add the secrets your confidential request needs to your `secrets.yaml`: -const callMsg = encodeCallMsg({ - from: zeroAddress, // Caller address (typically zeroAddress for view functions) - to: "0xYourContractAddress", // Contract address - data: callData, // ABI-encoded function call from encodeFunctionData() -}) +```yaml +# secrets.yaml +secretsNames: + myApiKey: + - MY_API_KEY_ALL ``` -This helper is required because the underlying EVM capability expects addresses and data in base64 format, not hex. - -### ABI encoding/decoding with viem - -The TypeScript SDK relies on viem for all ABI operations: +Provide the actual value via an environment variable or `.env` file: -- **`encodeFunctionData()`**: Encodes a function call into bytes -- **`decodeFunctionResult()`**: Decodes the returned bytes into TypeScript types -- **`parseAbi()`**: Parses human-readable ABI strings into typed ABI objects +```bash +export MY_API_KEY_ALL="your-secret-api-key" +``` -### The `.result()` pattern +<Aside type="note" title="Verify secrets-path in workflow.yaml"> + Make sure the `secrets-path` field in your `workflow.yaml` points to your `secrets.yaml` file (for example, + `"../secrets.yaml"` if it is at the project root). New projects created with the CLI may have this field empty by + default. +</Aside> -All CRE capability calls return objects with a `.result()` method. Calling `.result()` blocks execution synchronously (within the WASM environment) and waits for the consensus-verified result. +### Step 3: Define your types ```typescript -// This returns an object with a .result() method -const callObject = evmClient.callContract(runtime, { - call: encodeCallMsg({...}), - blockNumber: LAST_FINALIZED_BLOCK_NUMBER, +import { z } from "zod" + +const configSchema = z.object({ + schedule: z.string(), + url: z.string(), + owner: z.string(), }) -// This blocks and returns the actual result -const contractCall = callObject.result() +type Config = z.infer<typeof configSchema> + +type TransactionResult = { + transactionId: string + status: string +} ``` -This pattern is consistent across all SDK capabilities (EVM, HTTP, etc.). +### Step 4: Implement the fetch function -## Solidity-to-TypeScript type mappings +Create the function that will be passed to `sendRequest()`. This function receives a `ConfidentialHTTPSendRequester` and your config as parameters: -Viem automatically handles type conversions: +```typescript +import { type ConfidentialHTTPSendRequester, ok, json } from "@chainlink/cre-sdk" -| Solidity Type | TypeScript Type | -| ------------------------ | --------------- | -| `uint8`, `uint256`, etc. | `bigint` | -| `int8`, `int256`, etc. | `bigint` | -| `address` | `string` | -| `bool` | `boolean` | -| `string` | `string` | -| `bytes`, `bytes32`, etc. | `Uint8Array` | +const fetchTransaction = (sendRequester: ConfidentialHTTPSendRequester, config: Config): TransactionResult => { + // 1. Send the confidential request + const response = sendRequester + .sendRequest({ + request: { + url: config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.myApiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "myApiKey", owner: config.owner }], + }) + .result() -## Complete example with configuration + // 2. Check the response status + if (!ok(response)) { + throw new Error(`HTTP request failed with status: ${response.statusCode}`) + } -Here's a full runnable workflow with external configuration: + // 3. Parse and return the result + return json(response) as TransactionResult +} +``` -### Main workflow file (`main.ts`) +### Step 5: Wire it into your workflow + +In your trigger handler, call `confHTTPClient.sendRequest()` with your fetch function and a consensus method: ```typescript import { - cre, - getNetwork, - encodeCallMsg, - bytesToHex, - LAST_FINALIZED_BLOCK_NUMBER, + CronCapability, + ConfidentialHTTPClient, + handler, + consensusIdenticalAggregation, type Runtime, Runner, } from "@chainlink/cre-sdk" -import { type Address, encodeFunctionData, decodeFunctionResult, parseAbi, zeroAddress } from "viem" -import { z } from "zod" -const configSchema = z.object({ - contractAddress: z.string(), - chainSelectorName: z.string(), -}) +const onCronTrigger = (runtime: Runtime<Config>): string => { + const confHTTPClient = new ConfidentialHTTPClient() -type Config = z.infer<typeof configSchema> + const result = confHTTPClient + .sendRequest(runtime, fetchTransaction, consensusIdenticalAggregation<TransactionResult>())(runtime.config) + .result() -const storageAbi = parseAbi(["function get() view returns (uint256)"]) + runtime.log(`Transaction result: ${result.transactionId} — ${result.status}`) + return result.transactionId +} +``` -const onCronTrigger = (runtime: Runtime<Config>): string => { - const network = getNetwork({ - chainFamily: "evm", - chainSelectorName: runtime.config.chainSelectorName, - isTestnet: true, - }) +### Step 6: Simulate - if (!network) { - throw new Error(`Network not found: ${runtime.config.chainSelectorName}`) - } +Run the simulation: - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +```bash +cre workflow simulate +``` + +## Template syntax for secrets + +Secrets are injected into request bodies and headers using Go template syntax: `{{.secretName}}`. The placeholder name must match the `key` in your `vaultDonSecrets` list. + +**In the request body:** + +```json +{ "auth": "{{.myApiKey}}", "data": "public-data" } +``` + +**In headers:** + +```typescript +multiHeaders: { + "Authorization": { values: ["Basic {{.myCredential}}"] }, +} +``` + +The template placeholders are resolved inside the enclave. The actual secret values never appear in your workflow code or in node memory. + +## Response encryption + +By default, the API response is returned unencrypted (`encryptOutput: false`). To encrypt the response body before it leaves the enclave, set `encryptOutput: true` and provide an AES-256 encryption key as a Vault DON secret. + +### Setting up response encryption + +1. **Store an AES-256 key** as a Vault DON secret with the identifier `san_marino_aes_gcm_encryption_key`: + + ```yaml + # secrets.yaml + secretsNames: + san_marino_aes_gcm_encryption_key: + - AES_KEY_ALL + ``` + +The key must be a 256-bit (32 bytes) hex-encoded string: + +```bash +export AES_KEY_ALL="your-256-bit-hex-encoded-key" +``` + +1. **Include the key in your `vaultDonSecrets`** and set `encryptOutput: true`: + + ```typescript + const response = sendRequester + .sendRequest({ + request: { + url: config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.myApiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "myApiKey", owner: config.owner }, { key: "san_marino_aes_gcm_encryption_key" }], + encryptOutput: true, + }) + .result() + ``` + +2. **Decrypt the response** in your own backend service. The encrypted response body is structured as `nonce || ciphertext || tag` and uses AES-GCM encryption. + + +<Aside type="caution" title="Do not decrypt inside the workflow"> + The purpose of response encryption is to keep the response confidential even within the decentralized network. Decrypt + the response in your own backend service, not inside the workflow itself. +</Aside> + +## Response helper functions + +The SDK response helpers `ok()`, `text()`, and `json()` work with Confidential HTTP responses just as they do with regular HTTP responses. For full documentation, see the [HTTP Client SDK Reference](/cre/reference/sdk/http-client-ts#helper-functions). + +## Complete example + +Here's the full workflow code for a confidential HTTP request with secret injection: + +```typescript +import { + CronCapability, + ConfidentialHTTPClient, + handler, + consensusIdenticalAggregation, + ok, + json, + type ConfidentialHTTPSendRequester, + type Runtime, + Runner, +} from "@chainlink/cre-sdk" +import { z } from "zod" + +// Config schema +const configSchema = z.object({ + schedule: z.string(), + url: z.string(), + owner: z.string(), +}) + +type Config = z.infer<typeof configSchema> + +// Result type +type TransactionResult = { + transactionId: string + status: string +} + +// Fetch function — receives a ConfidentialHTTPSendRequester and config +const fetchTransaction = (sendRequester: ConfidentialHTTPSendRequester, config: Config): TransactionResult => { + const response = sendRequester + .sendRequest({ + request: { + url: config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.myApiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "myApiKey", owner: config.owner }], + }) + .result() + + if (!ok(response)) { + throw new Error(`HTTP request failed with status: ${response.statusCode}`) + } + + return json(response) as TransactionResult +} + +// Main workflow handler +const onCronTrigger = (runtime: Runtime<Config>): string => { + const confHTTPClient = new ConfidentialHTTPClient() + + const result = confHTTPClient + .sendRequest(runtime, fetchTransaction, consensusIdenticalAggregation<TransactionResult>())(runtime.config) + .result() + + runtime.log(`Transaction result: ${result.transactionId} — ${result.status}`) + return result.transactionId +} + +// Initialize workflow +const initWorkflow = (config: Config) => { + return [ + handler( + new CronCapability().trigger({ + schedule: config.schedule, + }), + onCronTrigger + ), + ] +} + +export async function main() { + const runner = await Runner.newRunner<Config>({ configSchema }) + await runner.run(initWorkflow) +} +``` + +## API reference + +For the full list of types and methods available on the Confidential HTTP client, see the [Confidential HTTP Client SDK Reference](/cre/reference/sdk/confidential-http-client-ts). + +--- + +# Forwarder Directory +Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/forwarder-directory-ts +Last Updated: 2026-02-03 + +<Aside type="note" title="Looking for supported networks?"> + For a complete list of supported networks and version requirements, see [Supported Networks](/cre/supported-networks). +</Aside> + +This page lists forwarder contract addresses for CRE workflows, organized by network. + +## How to Use This Page + +This reference provides three key pieces of information for each network: + +1. **Network Name**: The human-readable network identifier (click to view the forwarder contract on the block explorer) +2. **Chain Name**: The value to use in your [`project.yaml`](/cre/reference/project-configuration-ts#31-global-configuration-projectyaml) configuration and [EVM Client code](/cre/reference/sdk/evm-client-ts#chain-selectors) +3. **Forwarder Address**: The contract address for optional consumer contract validation + +## Understanding Forwarder Addresses + +Forwarder addresses identify the trusted Chainlink Forwarder contract that delivers verified workflow reports to your consumer contract. Your workflow code does not interact with forwarders directly—the EVM capability handles report delivery automatically. Learn more: [Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview-ts). + +**Using the [ReceiverTemplate](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#3-using-receivertemplate) (recommended)**: If you use the [`ReceiverTemplate`](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#receivertemplate), the forwarder address is **required** in the constructor. This ensures your contract only accepts reports from the trusted Chainlink Forwarder. + +**Custom implementations**: If you implement the `IReceiver` interface directly without using `ReceiverTemplate`, you control your own security checks. See [Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts) for details. + +### Simulation vs Production Addresses + +**Important**: Forwarder contracts differ between local simulation and production: + +| Environment | Contract Type | Section | +| ---------------- | ----------------------- | ----------------------------------------------- | +| Local simulation | `MockKeystoneForwarder` | [Simulation Forwarders](#simulation-forwarders) | +| Production | `KeystoneForwarder` | [Production Forwarders](#production-forwarders) | + +If you configure forwarder validation in your consumer contract, **remember to update the forwarder address** when deploying to production. Learn more: [Working with Simulation](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#4-working-with-simulation). + +## Simulation Forwarders + +These `MockKeystoneForwarder` addresses are used when running `cre workflow simulate` with the `--broadcast` flag. Use these addresses **only** during local development and testing. + +### Simulation Mainnets + +| Network | Chain Name | Mock Forwarder Address | +| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------------------ | +| <a href="https://arbiscan.io/address/0xd770499057619c9a76205fd4168161cf94abc532" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | ethereum-mainnet-arbitrum-1 | 0xd770499057619c9a76205fd4168161cf94abc532 | +| <a href="https://snowscan.xyz/address/0xdc21e279934ff6721cadfdd112dafb3261f09a2c" target="_blank" rel="noopener noreferrer">Avalanche</a> | avalanche-mainnet | 0xdc21e279934ff6721cadfdd112dafb3261f09a2c | +| <a href="https://basescan.org/address/0x5e342a8438b4f5d39e72875fcee6f76b39cce548" target="_blank" rel="noopener noreferrer">Base</a> | ethereum-mainnet-base-1 | 0x5e342a8438b4f5d39e72875fcee6f76b39cce548 | +| <a href="https://bscscan.com/address/0x6f3239bbb26e98961e1115aba83f8a282e5508c8" target="_blank" rel="noopener noreferrer">BNB Smart Chain</a> | binance_smart_chain-mainnet | 0x6f3239bbb26e98961e1115aba83f8a282e5508c8 | +| <a href="https://etherscan.io/address/0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | ethereum-mainnet | 0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9 | +| <a href="https://optimistic.etherscan.io/address/0x9119a1501550ed94a3f2794038ed9258337afa18" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | ethereum-mainnet-optimism-1 | 0x9119a1501550ed94a3f2794038ed9258337afa18 | +| <a href="https://polygonscan.com/address/0xf458d621885e29a5003ea9bbba5280d54e19b1ce" target="_blank" rel="noopener noreferrer">Polygon</a> | polygon-mainnet | 0xf458d621885e29a5003ea9bbba5280d54e19b1ce | +| <a href="https://explorer.zksync.io/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">ZKSync Era</a> | ethereum-mainnet-zksync-1 | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | + +### Simulation Testnets + +| Network | Chain Name | Mock Forwarder Address | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------ | +| <a href="https://explorer.curtis.apechain.com/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Apechain Curtis</a> | apechain-testnet-curtis | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://testnet.arcscan.app/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Arc Testnet</a> | arc-testnet | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia.arbiscan.io/address/0xd41263567ddfead91504199b8c6c87371e83ca5d" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | ethereum-testnet-sepolia-arbitrum-1 | 0xd41263567ddfead91504199b8c6c87371e83ca5d | +| <a href="https://testnet.snowscan.xyz/address/0x2e7371a5d032489e4f60216d8d898a4c10805963" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | avalanche-testnet-fuji | 0x2e7371a5d032489e4f60216d8d898a4c10805963 | +| <a href="https://sepolia.basescan.org/address/0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | ethereum-testnet-sepolia-base-1 | 0x82300bd7c3958625581cc2f77bc6464dcecdf3e5 | +| <a href="https://testnet.bscscan.com/address/0xa238e42cb8782808dbb2f37e19859244ec4779b0" target="_blank" rel="noopener noreferrer">BSC Testnet</a> | binance_smart_chain-testnet | 0xa238e42cb8782808dbb2f37e19859244ec4779b0 | +| <a href="https://sepolia.etherscan.io/address/0x15fC6ae953E024d975e77382eEeC56A9101f9F88" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | ethereum-testnet-sepolia | 0x15fC6ae953E024d975e77382eEeC56A9101f9F88 | +| <a href="https://testnet.purrsec.com/address/0xB27fA1c28288c50542527F64BCda22C9FbAc24CB" target="_blank" rel="noopener noreferrer">Hyperliquid Testnet</a> | hyperliquid-testnet | 0xB27fA1c28288c50542527F64BCda22C9FbAc24CB | +| <a href="https://explorer-sepolia.inkonchain.com/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Ink Sepolia</a> | ink-testnet-sepolia | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia-explorer.jovay.io/l2/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Jovay Testnet</a> | jovay-testnet | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia.lineascan.build/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Linea Sepolia</a> | ethereum-testnet-sepolia-linea-1 | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia-optimism.etherscan.io/address/0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | ethereum-testnet-sepolia-optimism-1 | 0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3 | +| <a href="https://testnet.plasmascan.to/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">Plasma Testnet</a> | plasma-testnet | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://amoy.polygonscan.com/address/0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | polygon-testnet-amoy | 0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74 | +| <a href="https://sepolia.worldscan.org/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">World Chain Sepolia</a> | ethereum-testnet-sepolia-worldchain-1 | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | +| <a href="https://sepolia.explorer.zksync.io/address/0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1" target="_blank" rel="noopener noreferrer">ZKSync Era Sepolia</a> | ethereum-testnet-sepolia-zksync-1 | 0x6E9EE680ef59ef64Aa8C7371279c27E496b5eDc1 | + +## Production Forwarders + +These `KeystoneForwarder` addresses are used by deployed workflows. Use these addresses when configuring your consumer contracts for production. + +### Mainnets + +| Network | Chain Name | Forwarder Address | +| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------------------ | +| <a href="https://arbiscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | ethereum-mainnet-arbitrum-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche</a> | avalanche-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base</a> | ethereum-mainnet-base-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Smart Chain</a> | binance_smart_chain-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://etherscan.io/address/0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | ethereum-mainnet | 0x0b93082D9b3C7C97fAcd250082899BAcf3af3885 | +| <a href="https://optimistic.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | ethereum-mainnet-optimism-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon</a> | polygon-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://explorer.zksync.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">ZKSync Era</a> | ethereum-mainnet-zksync-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | + +### Testnets + +| Network | Chain Name | Forwarder Address | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------ | +| <a href="https://explorer.curtis.apechain.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Apechain Curtis</a> | apechain-testnet-curtis | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.arbiscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | ethereum-testnet-sepolia-arbitrum-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://testnet.snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | avalanche-testnet-fuji | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | ethereum-testnet-sepolia-base-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://testnet.bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BSC Testnet</a> | binance_smart_chain-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | ethereum-testnet-sepolia | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | +| <a href="https://testnet.purrsec.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Hyperliquid Testnet</a> | hyperliquid-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://explorer-sepolia.inkonchain.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Ink Sepolia</a> | ink-testnet-sepolia | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia-explorer.jovay.io/l2/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Jovay Testnet</a> | jovay-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.lineascan.build/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Linea Sepolia</a> | ethereum-testnet-sepolia-linea-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia-optimism.etherscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | ethereum-testnet-sepolia-optimism-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://testnet.plasmascan.to/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Plasma Testnet</a> | plasma-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://amoy.polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | polygon-testnet-amoy | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.worldscan.org/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">World Chain Sepolia</a> | ethereum-testnet-sepolia-worldchain-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | +| <a href="https://sepolia.explorer.zksync.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">ZKSync Era Sepolia</a> | ethereum-testnet-sepolia-zksync-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | + +--- + +# Onchain Read +Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-read-ts +Last Updated: 2026-01-20 + +This guide explains how to read data from a smart contract from within your CRE workflow. The TypeScript SDK uses [viem](https://viem.sh/) for ABI handling and the SDK's [`EVMClient`](/cre/reference/sdk/evm-client-ts) to create a type-safe developer experience. + +## The read pattern + +Reading from a contract follows this pattern: + +1. **Define your contract ABI**: Create a TypeScript file with your contract's ABI using <a href="https://viem.sh/docs/abi/parseAbi" target="_blank">viem's `parseAbi`</a> (inline) or store it in `contracts/abi/` for complex workflows +2. **Get network information**: Use the SDK's `getNetwork()` helper to look up chain selector and other network details +3. **Instantiate the EVM Client**: Create an `EVMClient` instance with the chain selector +4. **Encode the function call**: Use <a href="https://viem.sh/docs/contract/encodeFunctionData#encodefunctiondata" target="_blank">viem's `encodeFunctionData()`</a> to ABI-encode your function call +5. **Encode the call message**: Use `encodeCallMsg()` to create a properly formatted call message with `from`, `to`, and `data` +6. **Call the contract**: Use `callContract(runtime, {...})` to execute the read operation +7. **Decode the result**: Use <a href="https://viem.sh/docs/contract/decodeFunctionResult#decodefunctionresult" target="_blank">viem's `decodeFunctionResult()`</a> to decode the returned data +8. **Await the result**: Call `.result()` on the returned object to get the consensus-verified result + +## Step-by-step example + +Let's read a value from a simple `Storage` contract with a `get() view returns (uint256)` function. + +### 1. Define the contract ABI + +For simple contracts, you can define the ABI inline using viem's `parseAbi`: + +```typescript +import { parseAbi } from "viem" + +const storageAbi = parseAbi(["function get() view returns (uint256)"]) +``` + +For complex workflows with multiple contracts, it's recommended to create separate ABI files in a `contracts/abi/` directory. See [Part 3 of the Getting Started guide](/cre/getting-started/part-3-reading-onchain-value-ts#step-3-create-the-contract-abi-file) for an example of this pattern. + +### 2. The workflow logic + +Here's a complete example of reading from a Storage contract: + +```typescript +import { + CronCapability, + EVMClient, + getNetwork, + encodeCallMsg, + bytesToHex, + LAST_FINALIZED_BLOCK_NUMBER, + type Runtime, + Runner, +} from "@chainlink/cre-sdk" +import { type Address, encodeFunctionData, decodeFunctionResult, parseAbi, zeroAddress } from "viem" +import { z } from "zod" + +// Define config schema with Zod +const configSchema = z.object({ + contractAddress: z.string(), + chainSelectorName: z.string(), +}) + +type Config = z.infer<typeof configSchema> + +// Define the Storage contract ABI +const storageAbi = parseAbi(["function get() view returns (uint256)"]) + +const onCronTrigger = (runtime: Runtime<Config>): string => { + // Get network information + const network = getNetwork({ + chainFamily: "evm", + chainSelectorName: runtime.config.chainName, + isTestnet: true, + }) + + if (!network) { + throw new Error(`Network not found: ${runtime.config.chainSelectorName}`) + } + + // Create EVM client with chain selector + const evmClient = new EVMClient(network.chainSelector.selector) + + // Encode the function call + const callData = encodeFunctionData({ + abi: storageAbi, + functionName: "get", + args: [], // No arguments for this function + }) + + // Call the contract + const contractCall = evmClient + .callContract(runtime, { + call: encodeCallMsg({ + from: zeroAddress, + to: runtime.config.contractAddress as Address, + data: callData, + }), + blockNumber: LAST_FINALIZED_BLOCK_NUMBER, + }) + .result() + + // Decode the result (convert Uint8Array to hex string for viem) + const storedValue = decodeFunctionResult({ + abi: storageAbi, + functionName: "get", + data: bytesToHex(contractCall.data), + }) + + runtime.log(`Successfully read storage value: ${storedValue.toString()}`) + return storedValue.toString() +} + +const initWorkflow = (config: Config) => { + const cron = new CronCapability() + return [ + cron.handler( + cron.trigger({ + schedule: "*/10 * * * * *", // Every 10 seconds + }), + onCronTrigger + ), + ] +} + +export async function main() { + const runner = await Runner.newRunner<Config>() + await runner.run(initWorkflow) +} +``` + +## Understanding the components + +<Aside type="note" title="Type-safe addresses"> + Notice the `as Address` type assertion when passing `contractAddress` to `encodeCallMsg`. This tells TypeScript the + string is a valid Ethereum address, which is required by viem's `encodeCallMsg` function. The `Address` type is + imported from `viem`. +</Aside> + +### Network lookup with `getNetwork()` + +The SDK provides a `getNetwork()` helper that looks up network information by name: + +```typescript +const network = getNetwork({ + chainFamily: "evm", + chainSelectorName: "ethereum-testnet-sepolia", + isTestnet: true, +}) + +// Returns network info including: +// - chainSelector.selector (numeric ID) +// - name +// - chainType +``` + +See the [EVM Client SDK Reference](/cre/reference/sdk/evm-client-ts#chain-selectors) for all available networks. + +### Block number options + +When calling `callContract()`, you can specify which block to read from: + +- **`LAST_FINALIZED_BLOCK_NUMBER`**: Read from the last finalized block (recommended for production) +- **`LATEST_BLOCK_NUMBER`**: Read from the latest block +- **Custom block number**: Use a `BigIntJson` object for custom finality depths or historical queries + +```typescript +import { LAST_FINALIZED_BLOCK_NUMBER, LATEST_BLOCK_NUMBER } from "@chainlink/cre-sdk" + +// Read from finalized block (most common) +const contractCall = evmClient.callContract(runtime, { + call: encodeCallMsg({...}), + blockNumber: LAST_FINALIZED_BLOCK_NUMBER, +}).result() + +// Or read from latest block +const contractCall = evmClient.callContract(runtime, { + call: encodeCallMsg({...}), + blockNumber: LATEST_BLOCK_NUMBER, +}).result() +``` + +#### Custom block depths + +For use cases requiring fixed confirmation thresholds (e.g., regulatory compliance) or historical state verification, you can specify an exact block number. + +**Example 1 - Read from a specific historical block**: + +```typescript +import { blockNumber } from '@chainlink/cre-sdk' + +const historicalBlock = 9767655n +const contractCall = evmClient.callContract(runtime, { + call: encodeCallMsg({...}), + blockNumber: blockNumber(historicalBlock), +}).result() +``` + +**Example 2 - Read from 500 blocks ago for custom finality**: + +```typescript +import { protoBigIntToBigint, blockNumber } from '@chainlink/cre-sdk' + +// Get the latest block number +const latestHeader = evmClient.headerByNumber(runtime, {}).result() +if (!latestHeader.header?.blockNumber) { + throw new Error("Failed to get latest block number") +} + +// Convert protobuf BigInt to native bigint and calculate custom block +const latestBlockNum = protoBigIntToBigint(latestHeader.header.blockNumber) +const customBlock = latestBlockNum - 500n + +// Call the contract at the custom block height +const contractCall = evmClient.callContract(runtime, { + call: encodeCallMsg({...}), + blockNumber: blockNumber(customBlock), +}).result() +``` + +**Helper functions:** + +The SDK provides two helper functions for working with block numbers: + +- **`protoBigIntToBigint(pb)`** — Converts a protobuf `BigInt` (returned by SDK methods like `headerByNumber`) to a native JavaScript `bigint`. Use this when you need to perform arithmetic on block numbers. + +- **`blockNumber(n)`** — Converts a native `bigint`, `number`, or `string` to the protobuf `BigInt` JSON format required by SDK methods. This is an alias for `bigintToProtoBigInt`. + +See [Finality and Confidence Levels](/cre/concepts/finality-ts) for more details on when to use custom block depths. + +### Encoding call messages with `encodeCallMsg()` + +The `encodeCallMsg()` helper converts your hex-formatted call data into the base64 format required by the EVM capability: + +```typescript +import { encodeCallMsg } from "@chainlink/cre-sdk" +import { zeroAddress } from "viem" + +const callMsg = encodeCallMsg({ + from: zeroAddress, // Caller address (typically zeroAddress for view functions) + to: "0xYourContractAddress", // Contract address + data: callData, // ABI-encoded function call from encodeFunctionData() +}) +``` + +This helper is required because the underlying EVM capability expects addresses and data in base64 format, not hex. + +### ABI encoding/decoding with viem + +The TypeScript SDK relies on viem for all ABI operations: + +- **`encodeFunctionData()`**: Encodes a function call into bytes +- **`decodeFunctionResult()`**: Decodes the returned bytes into TypeScript types +- **`parseAbi()`**: Parses human-readable ABI strings into typed ABI objects + +### The `.result()` pattern + +All CRE capability calls return objects with a `.result()` method. Calling `.result()` blocks execution synchronously (within the WASM environment) and waits for the consensus-verified result. + +```typescript +// This returns an object with a .result() method +const callObject = evmClient.callContract(runtime, { + call: encodeCallMsg({...}), + blockNumber: LAST_FINALIZED_BLOCK_NUMBER, +}) + +// This blocks and returns the actual result +const contractCall = callObject.result() +``` + +This pattern is consistent across all SDK capabilities (EVM, HTTP, etc.). + +## Solidity-to-TypeScript type mappings + +Viem automatically handles type conversions: + +| Solidity Type | TypeScript Type | +| ------------------------ | --------------- | +| `uint8`, `uint256`, etc. | `bigint` | +| `int8`, `int256`, etc. | `bigint` | +| `address` | `string` | +| `bool` | `boolean` | +| `string` | `string` | +| `bytes`, `bytes32`, etc. | `Uint8Array` | + +## Complete example with configuration + +Here's a full runnable workflow with external configuration: + +### Main workflow file (`main.ts`) + +```typescript +import { + CronCapability, + EVMClient, + getNetwork, + encodeCallMsg, + bytesToHex, + LAST_FINALIZED_BLOCK_NUMBER, + type Runtime, + Runner, +} from "@chainlink/cre-sdk" +import { type Address, encodeFunctionData, decodeFunctionResult, parseAbi, zeroAddress } from "viem" +import { z } from "zod" + +const configSchema = z.object({ + contractAddress: z.string(), + chainSelectorName: z.string(), +}) + +type Config = z.infer<typeof configSchema> + +const storageAbi = parseAbi(["function get() view returns (uint256)"]) + +const onCronTrigger = (runtime: Runtime<Config>): string => { + const network = getNetwork({ + chainFamily: "evm", + chainSelectorName: runtime.config.chainSelectorName, + isTestnet: true, + }) + + if (!network) { + throw new Error(`Network not found: ${runtime.config.chainSelectorName}`) + } + + const evmClient = new EVMClient(network.chainSelector.selector) const callData = encodeFunctionData({ abi: storageAbi, @@ -8961,9 +10421,10 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { } const initWorkflow = (config: Config) => { + const cron = new CronCapability() return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + cron.handler( + cron.trigger({ schedule: "*/10 * * * * *", }), onCronTrigger @@ -8975,8 +10436,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ### Configuration file (`config.json`) @@ -9028,7 +10487,7 @@ This pattern provides better organization, reusability, and type safety across y ## Next steps -- Learn how to [write data to contracts](/cre/guides/workflow/using-evm-client/onchain-write) +- Learn how to [write data to contracts](/cre/guides/workflow/using-evm-client/onchain-write/overview) - Explore the [EVM Client SDK Reference](/cre/reference/sdk/evm-client-ts) for all available methods - See [Part 3](/cre/getting-started/part-3-reading-onchain-value) and [Part 4](/cre/getting-started/part-4-writing-onchain) of the Getting Started guide for more examples @@ -9155,98 +10614,9 @@ This approach gives you the flexibility of direct ABI handling with the type saf --- -# Supported Networks -Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/supported-networks-ts -Last Updated: 2025-11-20 - -This page lists the EVM-compatible networks supported by CRE workflows, along with their chain names (for configuration) and forwarder contract addresses (for consumer contract validation). - -## How to Use This Page - -This reference provides three key pieces of information for each network: - -1. **Network Name**: The human-readable network identifier (click to view the forwarder contract on the block explorer) -2. **Chain Name**: The value to use in your [`project.yaml`](/cre/reference/project-configuration-ts#31-global-configuration-projectyaml) configuration and [EVM Client code](/cre/reference/sdk/evm-client-ts#chain-selectors) -3. **Forwarder Address**: The contract address for optional consumer contract validation (click to copy) - -## Understanding Forwarder Addresses - -Forwarder addresses are relevant **only if you want to add security validation to your consumer contracts**. Your workflow code does not interact with forwarders directly—the EVM capability handles report delivery automatically. Learn more: [Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview-ts). - -**Optional security layer**: You can configure your consumer contract's `onReport()` function to accept calls only from the trusted forwarder address. See [Configuring Permissions](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#34-configuring-permissions) for implementation details. - -### Simulation vs Production Addresses - -**Important**: Forwarder contracts differ between local simulation and production: - -| Environment | Contract Type | Section | -| ---------------- | ----------------------- | ----------------------------------------------- | -| Local simulation | `MockKeystoneForwarder` | [Simulation Forwarders](#simulation-forwarders) | -| Production | `KeystoneForwarder` | [Production Forwarders](#production-forwarders) | - -If you configure forwarder validation in your consumer contract, **remember to update the forwarder address** when deploying to production. Learn more: [Working with Simulation](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#4-working-with-simulation). - -## Simulation Forwarders - -These `MockKeystoneForwarder` addresses are used when running `cre workflow simulate` with the `--broadcast` flag. Use these addresses **only** during local development and testing. - -### Simulation Mainnets - -| Network | Chain Name | Mock Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------------------ | -| <a href="https://arbiscan.io/address/0xd770499057619c9a76205fd4168161cf94abc532" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | ethereum-mainnet-arbitrum-1 | 0xd770499057619c9a76205fd4168161cf94abc532 | -| <a href="https://snowscan.xyz/address/0xdc21e279934ff6721cadfdd112dafb3261f09a2c" target="_blank" rel="noopener noreferrer">Avalanche</a> | avalanche-mainnet | 0xdc21e279934ff6721cadfdd112dafb3261f09a2c | -| <a href="https://basescan.org/address/0x5e342a8438b4f5d39e72875fcee6f76b39cce548" target="_blank" rel="noopener noreferrer">Base</a> | ethereum-mainnet-base-1 | 0x5e342a8438b4f5d39e72875fcee6f76b39cce548 | -| <a href="https://bscscan.com/address/0x6f3239bbb26e98961e1115aba83f8a282e5508c8" target="_blank" rel="noopener noreferrer">BNB Smart Chain</a> | binance_smart_chain-mainnet | 0x6f3239bbb26e98961e1115aba83f8a282e5508c8 | -| <a href="https://etherscan.io/address/0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | ethereum-mainnet | 0xa3d1ad4ac559a6575a114998affb2fb2ec97a7d9 | -| <a href="https://optimistic.etherscan.io/address/0x9119a1501550ed94a3f2794038ed9258337afa18" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | ethereum-mainnet-optimism-1 | 0x9119a1501550ed94a3f2794038ed9258337afa18 | -| <a href="https://polygonscan.com/address/0xf458d621885e29a5003ea9bbba5280d54e19b1ce" target="_blank" rel="noopener noreferrer">Polygon</a> | polygon-mainnet | 0xf458d621885e29a5003ea9bbba5280d54e19b1ce | - -### Simulation Testnets - -| Network | Chain Name | Mock Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------------------------------------------ | -| <a href="https://sepolia.arbiscan.io/address/0xd41263567ddfead91504199b8c6c87371e83ca5d" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | ethereum-testnet-sepolia-arbitrum-1 | 0xd41263567ddfead91504199b8c6c87371e83ca5d | -| <a href="https://testnet.snowscan.xyz/address/0x2e7371a5d032489e4f60216d8d898a4c10805963" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | avalanche-testnet-fuji | 0x2e7371a5d032489e4f60216d8d898a4c10805963 | -| <a href="https://sepolia.basescan.org/address/0x82300bd7c3958625581cc2f77bc6464dcecdf3e5" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | ethereum-testnet-sepolia-base-1 | 0x82300bd7c3958625581cc2f77bc6464dcecdf3e5 | -| <a href="https://testnet.bscscan.com/address/0xa238e42cb8782808dbb2f37e19859244ec4779b0" target="_blank" rel="noopener noreferrer">BSC Testnet</a> | binance_smart_chain-testnet | 0xa238e42cb8782808dbb2f37e19859244ec4779b0 | -| <a href="https://sepolia.etherscan.io/address/0x15fC6ae953E024d975e77382eEeC56A9101f9F88" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | ethereum-testnet-sepolia | 0x15fC6ae953E024d975e77382eEeC56A9101f9F88 | -| <a href="https://sepolia-optimism.etherscan.io/address/0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | ethereum-testnet-sepolia-optimism-1 | 0xa2888380dff3704a8ab6d1cd1a8f69c15fea5ee3 | -| <a href="https://amoy.polygonscan.com/address/0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | polygon-testnet-amoy | 0x3675a5eb2286a3f87e8278fc66edf458a2e3bb74 | - -## Production Forwarders - -These `KeystoneForwarder` addresses are used by deployed workflows. Use these addresses when configuring your consumer contracts for production. - -### Mainnets - -| Network | Chain Name | Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------------------ | -| <a href="https://arbiscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Arbitrum One</a> | ethereum-mainnet-arbitrum-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche</a> | avalanche-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base</a> | ethereum-mainnet-base-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BNB Smart Chain</a> | binance_smart_chain-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://etherscan.io/address/0x0b93082D9b3C7C97fAcd250082899BAcf3af3885" target="_blank" rel="noopener noreferrer">Ethereum Mainnet</a> | ethereum-mainnet | 0x0b93082D9b3C7C97fAcd250082899BAcf3af3885 | -| <a href="https://optimistic.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">OP Mainnet</a> | ethereum-mainnet-optimism-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon</a> | polygon-mainnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | - -### Testnets - -| Network | Chain Name | Forwarder Address | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------------------------------------------ | -| <a href="https://sepolia.arbiscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Arbitrum Sepolia</a> | ethereum-testnet-sepolia-arbitrum-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://testnet.snowscan.xyz/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Avalanche Fuji</a> | avalanche-testnet-fuji | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://sepolia.basescan.org/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Base Sepolia</a> | ethereum-testnet-sepolia-base-1 | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://testnet.bscscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">BSC Testnet</a> | binance_smart_chain-testnet | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://sepolia.etherscan.io/address/0xF8344CFd5c43616a4366C34E3EEE75af79a74482" target="_blank" rel="noopener noreferrer">Ethereum Sepolia</a> | ethereum-testnet-sepolia | 0xF8344CFd5c43616a4366C34E3EEE75af79a74482 | -| <a href="https://sepolia-optimism.etherscan.io/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">OP Sepolia</a> | ethereum-testnet-sepolia-optimism-1 | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | -| <a href="https://amoy.polygonscan.com/address/0x76c9cf548b4179F8901cda1f8623568b58215E62" target="_blank" rel="noopener noreferrer">Polygon Amoy</a> | polygon-testnet-amoy | 0x76c9cf548b4179F8901cda1f8623568b58215E62 | - ---- - # Making GET Requests Source: https://docs.chain.link/cre/guides/workflow/using-http-client/get-request-ts -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 The `HTTPClient` is the SDK's interface for the underlying [HTTP Capability](/cre/capabilities/http). It allows your workflow to fetch data from any external API. @@ -9259,6 +10629,16 @@ All HTTP requests are wrapped in a consensus mechanism to provide a single, reli This guide assumes you have a basic understanding of CRE. If you are new, we strongly recommend completing the [Getting Started tutorial](/cre/getting-started/overview) first. + +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + + +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.now()` instead of `Date.now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + ## Choosing your approach ### Use `sendRequest` (Section 1) when: @@ -9311,7 +10691,7 @@ Add the API URL to your `config.json` file. Define TypeScript types for the API response and your internal data model. ```typescript -import { cre, type Runtime, type HTTPSendRequester, Runner } from "@chainlink/cre-sdk" +import { HTTPClient, type Runtime, type HTTPSendRequester, Runner } from "@chainlink/cre-sdk" import { z } from "zod" // Config schema @@ -9373,17 +10753,19 @@ const fetchAndParse = (sendRequester: HTTPSendRequester, config: Config): PriceD In your `onCronTrigger` handler, call `httpClient.sendRequest()`. This returns a function that you call with `runtime.config`. ```typescript +import { HTTPClient, ConsensusAggregationByFields, median, type Runtime } from "@chainlink/cre-sdk" + const onCronTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // sendRequest returns a function that we call with runtime.config const result = httpClient .sendRequest( runtime, fetchAndParse, - new cre.consensus.ConsensusAggregationByFields<PriceData>({ - price: cre.consensus.median<number>(), - lastUpdated: cre.consensus.median<Date>(), + ConsensusAggregationByFields<PriceData>({ + price: median<number>(), + lastUpdated: median<Date>(), }) )(runtime.config) // Call the returned function with config .result() @@ -9399,7 +10781,16 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { Here's the full workflow code: ```typescript -import { cre, type Runtime, type HTTPSendRequester, Runner } from "@chainlink/cre-sdk" +import { + CronCapability, + HTTPClient, + handler, + ConsensusAggregationByFields, + median, + type Runtime, + type HTTPSendRequester, + Runner, +} from "@chainlink/cre-sdk" import { z } from "zod" // Config schema @@ -9447,15 +10838,15 @@ const fetchAndParse = (sendRequester: HTTPSendRequester, config: Config): PriceD // Main workflow handler const onCronTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const result = httpClient .sendRequest( runtime, fetchAndParse, - new cre.consensus.ConsensusAggregationByFields<PriceData>({ - price: cre.consensus.median<number>(), - lastUpdated: cre.consensus.median<Date>(), + ConsensusAggregationByFields<PriceData>({ + price: median<number>(), + lastUpdated: median<Date>(), }) )(runtime.config) // Call with config .result() @@ -9468,8 +10859,8 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { // Initialize workflow const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -9481,8 +10872,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## 2. The `runInNodeMode` Pattern (Low-Level) @@ -9497,7 +10886,16 @@ The pattern works like a "map-reduce" for the DON: The example below is functionally identical to the `sendRequest` example above, but implemented using the low-level pattern. ```typescript -import { cre, type Runtime, type NodeRuntime, Runner } from "@chainlink/cre-sdk" +import { + CronCapability, + HTTPClient, + handler, + ConsensusAggregationByFields, + median, + type Runtime, + type NodeRuntime, + Runner, +} from "@chainlink/cre-sdk" import { z } from "zod" // Config and types (same as before) @@ -9523,7 +10921,7 @@ type ExternalApiResponse = { // fetchPriceData is a function that runs on each individual node const fetchPriceData = (nodeRuntime: NodeRuntime<Config>): PriceData => { // 1. Create HTTP client and fetch raw data - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const req = { url: nodeRuntime.config.apiUrl, @@ -9551,9 +10949,9 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { const result = runtime .runInNodeMode( fetchPriceData, - new cre.consensus.ConsensusAggregationByFields<PriceData>({ - price: cre.consensus.median<number>(), - lastUpdated: cre.consensus.median<Date>(), + ConsensusAggregationByFields<PriceData>({ + price: median<number>(), + lastUpdated: median<Date>(), }) )() .result() @@ -9566,8 +10964,8 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { // Initialize workflow (same as before) const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -9579,8 +10977,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Response helper functions @@ -9593,14 +10989,14 @@ The request object provides several fields to customize your HTTP call. See the - **Headers**: Custom HTTP headers - **Body**: Request payload (for POST, PUT, etc.) -- **Timeout**: Request timeout in milliseconds +- **Timeout**: Request timeout as a duration string in seconds (e.g., `"5s"`, `"8s"`) - **Cache settings**: Control response caching behavior --- # Making POST Requests Source: https://docs.chain.link/cre/guides/workflow/using-http-client/post-request-ts -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 This guide explains how to use the HTTP Client to send data to an external API using a `POST` request. Because POST requests typically create resources or trigger actions, this guide shows you how to ensure your request executes only once, even though multiple nodes in the DON run your workflow. @@ -9616,6 +11012,11 @@ All HTTP requests are wrapped in a consensus mechanism. The SDK provides two way - **[High-level `sendRequest`](#1-the-high-level-sendrequest-pattern-recommended):** A high-level helper method that simplifies making requests. This is the recommended approach for most use cases. - **[Low-level `runInNodeMode`](#2-the-low-level-runinnodemode-pattern):** The lower-level pattern for more complex scenarios. + +<Aside type="caution" title="Using timestamps in requests"> + If your HTTP request includes timestamps (e.g., for authentication headers or time-based queries), use `runtime.now()` instead of `Date.now()`. This ensures all nodes use the same timestamp and reach consensus. See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details. +</Aside> + ## Choosing your approach ### Use High-Level `sendRequest` (Section 1) when: @@ -9642,6 +11043,11 @@ For this example, we will use <a href="https://webhook.site/" target="_blank">** This guide assumes you have a basic understanding of CRE. If you are new, we strongly recommend completing the [Getting Started tutorial](/cre/getting-started/overview) first. + +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + ## 1. The High-Level `sendRequest` Pattern (recommended) The high-level `sendRequest()` method is the simplest and recommended way to make `POST` requests. It automatically handles the `runInNodeMode` pattern for you. @@ -9692,7 +11098,7 @@ In your `main.ts`, define the TypeScript types for your configuration and the da ```typescript import { - cre, + HTTPClient, ok, consensusIdenticalAggregation, type Runtime, @@ -9769,8 +11175,10 @@ const postData = (sendRequester: HTTPSendRequester, config: Config): PostRespons In your main `onCronTrigger` handler, call `httpClient.sendRequest()`, which returns a function that you call with `runtime.config`. ```typescript +import { HTTPClient, consensusIdenticalAggregation, type Runtime } from "@chainlink/cre-sdk" + const onCronTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const result = httpClient .sendRequest( @@ -9790,10 +11198,12 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { Finally, add the `initWorkflow` and `main` functions. ```typescript +import { CronCapability, handler, Runner } from "@chainlink/cre-sdk" + const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -9807,15 +11217,15 @@ export async function main() { }) await runner.run(initWorkflow) } - -main() ``` #### The complete workflow file ```typescript import { - cre, + CronCapability, + HTTPClient, + handler, ok, consensusIdenticalAggregation, type Runtime, @@ -9881,7 +11291,7 @@ const postData = (sendRequester: HTTPSendRequester, config: Config): PostRespons } const onCronTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const result = httpClient .sendRequest( @@ -9897,8 +11307,8 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -9912,8 +11322,6 @@ export async function main() { }) await runner.run(initWorkflow) } - -main() ``` ### Step 4: Run the simulation and verify @@ -9954,7 +11362,16 @@ For more complex scenarios, you can use the lower-level `runtime.runInNodeMode() Here's how to make a POST request with an API key from secrets: ```typescript -import { cre, ok, consensusIdenticalAggregation, type Runtime, type NodeRuntime, Runner } from "@chainlink/cre-sdk" +import { + CronCapability, + HTTPClient, + handler, + ok, + consensusIdenticalAggregation, + type Runtime, + type NodeRuntime, + Runner, +} from "@chainlink/cre-sdk" import { z } from "zod" // Config and types @@ -9982,7 +11399,7 @@ const postData = (nodeRuntime: NodeRuntime<Config>): PostResponse => { // Use the secret value const apiKey = secret.value - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // 2. Prepare the data const dataToSend: MyData = { @@ -10030,8 +11447,8 @@ const onCronTrigger = (runtime: Runtime<Config>): string => { const initWorkflow = (config: Config) => { return [ - cre.handler( - new cre.capabilities.CronCapability().trigger({ + handler( + new CronCapability().trigger({ schedule: config.schedule, }), onCronTrigger @@ -10045,8 +11462,6 @@ export async function main() { }) await runner.run(initWorkflow) } - -main() ``` ## Learn more @@ -10059,7 +11474,7 @@ main() # Submitting Reports via HTTP Source: https://docs.chain.link/cre/guides/workflow/using-http-client/submitting-reports-http-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 This guide shows how to send a cryptographically signed report (generated by your workflow) to an external HTTP API. You'll learn how to write a transformation function that formats the report for your specific API's requirements. @@ -10079,6 +11494,11 @@ This guide shows how to send a cryptographically signed report (generated by you - Familiarity with [making POST requests](/cre/guides/workflow/using-http-client/post-request) - Familiarity with `runtime.report()` (covered [below](#generating-reports-for-http-submission)) + +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + ## Quick start: Minimal example Here's the simplest possible workflow that generates and submits a report via HTTP: @@ -10175,7 +11595,7 @@ Here are common patterns for formatting reports. Choose the one that matches you | Pattern | When to use | | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | | [**Pattern 1: Report in body**](#pattern-1-report-in-body-simplest) | Your API accepts raw binary data and handles decoding | -| [**Pattern 2: Report + signatures in body**](#pattern-2-report-signatures-in-body) | Your API needs everything concatenated in one binary blob | +| [**Pattern 2: Report + signatures in body**](#pattern-2-report--signatures-in-body) | Your API needs everything concatenated in one binary blob | | [**Pattern 3: Report in body, signatures in headers**](#pattern-3-report-in-body-signatures-in-headers) | Your API needs signatures separated for easier parsing | | [**Pattern 4: JSON-formatted report**](#pattern-4-json-formatted-report) | Your API only accepts JSON payloads | @@ -10388,7 +11808,7 @@ Use the high-level `httpClient.sendRequest()` pattern with `sendRequester.sendRe ```typescript import { - cre, + HTTPClient, consensusIdenticalAggregation, ok, type Runtime, @@ -10413,7 +11833,7 @@ const submitReportViaHTTP = (sendRequester: HTTPSendRequester, report: Report): // In your trigger callback const onCronTrigger = (runtime: Runtime<Config>): MyResult => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // Assume 'report' was generated earlier in your workflow @@ -10440,7 +11860,8 @@ This example shows a workflow that: ```typescript import { - cre, + CronCapability, + HTTPClient, Runner, consensusIdenticalAggregation, hexToBase64, @@ -10466,9 +11887,9 @@ interface SubmitResponse { type MyResult = Record<string, never> const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [cron.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } // Transformation function: defines how the API expects the report @@ -10525,7 +11946,7 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): MyResult runtime.log("Report generated successfully") // Step 2: Submit the report via HTTP - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const submitResult = httpClient .sendRequest( @@ -10543,8 +11964,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ### Configuration file (`config.json`) @@ -10571,14 +11990,21 @@ main() For complex scenarios where you need more control, use `clientCapability.sendReport()` with `runtime.runInNodeMode()`: ```typescript -import { cre, consensusIdenticalAggregation, ok, type Runtime, type NodeRuntime, type Report } from "@chainlink/cre-sdk" +import { + HTTPClient, + consensusIdenticalAggregation, + ok, + type Runtime, + type NodeRuntime, + type Report, +} from "@chainlink/cre-sdk" const onCronTrigger = (runtime: Runtime<Config>): MyResult => { // Assume 'report' was generated earlier const result = runtime .runInNodeMode((nodeRuntime: NodeRuntime<Config>) => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const response = httpClient.sendReport(nodeRuntime, report, formatReportSimple).result() @@ -10633,7 +12059,7 @@ const onCronTrigger = (runtime: Runtime<Config>): MyResult => { # Cron Trigger Source: https://docs.chain.link/cre/guides/workflow/using-triggers/cron-trigger-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 The Cron trigger fires based on a time-based schedule, defined by a standard cron expression. @@ -10675,7 +12101,7 @@ The timezone-aware scheduler automatically handles daylight saving time transiti </Aside> ```typescript -import { cre, type Runtime, type CronPayload, Runner } from "@chainlink/cre-sdk" +import { CronCapability, handler, type Runtime, type CronPayload, Runner } from "@chainlink/cre-sdk" type Config = {} @@ -10691,25 +12117,23 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = const initWorkflow = (config: Config) => { // Create the trigger - fires every 30 seconds in UTC - const cronTrigger = new cre.capabilities.CronCapability().trigger({ + const cronTrigger = new CronCapability().trigger({ schedule: "*/30 * * * * *", }) // Or use a timezone-aware schedule - fires daily at 9 AM Eastern Time - // const cronTrigger = new cre.capabilities.CronCapability().trigger({ + // const cronTrigger = new CronCapability().trigger({ // schedule: "TZ=America/New_York 0 9 * * *", // }) // Register a handler with the trigger and a callback function - return [cre.handler(cronTrigger, onCronTrigger)] + return [handler(cronTrigger, onCronTrigger)] } export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Callback and payload @@ -10755,7 +12179,7 @@ For detailed instructions on simulating cron triggers, including interactive and # EVM Log Trigger Source: https://docs.chain.link/cre/guides/workflow/using-triggers/evm-log-trigger-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 The EVM Log trigger fires when a specific log (event) is emitted by a smart contract on an EVM-compatible blockchain. This capability allows you to build powerful, event-driven workflows that react to onchain activity. @@ -10768,12 +12192,28 @@ This guide explains the two key parts of working with log triggers: You create an EVM Log trigger by calling the `EVMClient.logTrigger()` method with a `FilterLogTriggerRequest` configuration. This configuration specifies which contract addresses and event topics to listen for. +<Aside type="note" title="Base64 Encoding Required"> + **All addresses and topic values must be base64 encoded** using the `hexToBase64()` helper function from the CRE SDK. + While the workflow simulator accepts raw hex strings for convenience during development, **deployed workflows require + base64 encoding**. Always use `hexToBase64()` on addresses and topic values to ensure your workflow works in both + simulation and production. +</Aside> + ### Basic configuration The simplest configuration listens for **all events** from specific contract addresses: ```typescript -import { cre, getNetwork, type Runtime, type EVMLog, Runner, bytesToHex } from "@chainlink/cre-sdk" +import { + EVMClient, + handler, + getNetwork, + type Runtime, + type EVMLog, + Runner, + bytesToHex, + hexToBase64, +} from "@chainlink/cre-sdk" type Config = { chainSelectorName: string @@ -10798,12 +12238,12 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], }), onLogTrigger ), @@ -10814,16 +12254,15 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ### Filtering by event type -To listen for **specific event types**, you need to provide the event's signature hash as the first topic (`Topics[0]`). You can compute this using viem's `keccak256` and `toHex` functions: +To listen for **specific event types**, you need to provide the event's signature hash as the first topic (`Topics[0]`). You can compute this using viem's `keccak256` and `toBytes` functions: ```typescript -import { keccak256, toHex } from "viem" +import { keccak256, toBytes } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -10836,17 +12275,17 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) // Compute the event signature hash for Transfer(address,address,uint256) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Listen only for Transfer events + { values: [hexToBase64(transferEventHash)] }, // Listen only for Transfer events ], }), onLogTrigger @@ -10863,13 +12302,26 @@ EVM events can have up to 3 `indexed` parameters (in addition to the event signa - **`addresses`**: The trigger fires if the event is emitted from **any** contract in this list (**OR** logic). - **`topics`**: An event must match the conditions for **all** defined topic slots (**AND** logic between topics). Within a single topic, you can provide multiple values, and it will match if the event's topic is **any** of those values (**OR** logic within a topic). +- **Wildcarding topics**: To skip filtering on a specific topic position, omit it from the topics array or provide an empty values array `{ values: [] }`. For example, to filter on topic 1 and topic 3 but not topic 2, you would provide `[topic0, topic1, { values: [] }, topic3]`. + +<Aside type="caution" title="Topic values must be padded to 32 bytes and base64 encoded"> + EVM logs always store indexed parameters as **32-byte values**. When filtering on topics 1, 2, or 3: + + 1. **Pad your values to 32 bytes** using `padHex(value, { size: 32 })` (e.g., addresses are 20 bytes and must be padded) + 2. **Convert to base64** using `hexToBase64()` + + If you don't pad correctly, your filter won't match the actual log topics and the trigger will not fire. + + Topic 0 (the event signature from `keccak256`) is already 32 bytes and doesn't need padding. +</Aside> #### Example 1: Filtering on a single indexed parameter To trigger only on `Transfer` events where the `from` address is a specific value: ```typescript -import { keccak256, toHex, pad } from "viem" +import { keccak256, toBytes, padHex } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -10882,18 +12334,18 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) - const aliceAddress = "0xAlice..." + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) + const aliceAddress = "0xAlice..." as `0x${string}` return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Topic 0: Event signature (Transfer) - { values: [pad(aliceAddress)] }, // Topic 1: from = Alice + { values: [hexToBase64(transferEventHash)] }, // Topic 0: Event signature (Transfer) + { values: [hexToBase64(padHex(aliceAddress, { size: 32 }))] }, // Topic 1: from = Alice ], }), onLogTrigger @@ -10902,18 +12354,63 @@ const initWorkflow = (config: Config) => { } ``` + <Aside type="note" title="Indexed Parameters and Topics"> - Only parameters marked as `indexed` in the Solidity event definition can be filtered using topics. The event signature - is always `Topics[0]`. Subsequent indexed parameters are `Topics[1]`, `Topics[2]`, and `Topics[3]`. Address values - must be padded to 32 bytes using viem's `pad()` function. + Only parameters marked as `indexed` in the Solidity event definition can be filtered using topics. The event signature is always `Topics[0]`. Subsequent indexed parameters are `Topics[1]`, `Topics[2]`, and `Topics[3]`. Encoding different types: + + - **Addresses**: Cast as `` `0x${string}` ``, use `padHex(address, { size: 32 })` then `hexToBase64()` + - **uint256**: Use `padHex(numberToHex(value), { size: 32 })` then `hexToBase64()` + - **bytes32**: Ensure it's 32 bytes, then use `hexToBase64()` directly </Aside> -#### Example 2: "AND" filtering +#### Example 2: "AND" filtering + +To trigger on `Transfer` events where `from` is Alice **AND** `to` is Bob: + +```typescript +import { keccak256, toBytes, padHex } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" + +const initWorkflow = (config: Config) => { + const network = getNetwork({ + chainFamily: "evm", + chainSelectorName: config.chainSelectorName, + isTestnet: true, + }) + + if (!network) { + throw new Error(`Network not found: ${config.chainSelectorName}`) + } + + const evmClient = new EVMClient(network.chainSelector.selector) + + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) + const aliceAddress = "0xAlice..." as `0x${string}` + const bobAddress = "0xBob..." as `0x${string}` + + return [ + handler( + evmClient.logTrigger({ + addresses: [hexToBase64(config.contractAddress)], + topics: [ + { values: [hexToBase64(transferEventHash)] }, // Topic 0: Event signature (Transfer) + { values: [hexToBase64(padHex(aliceAddress, { size: 32 }))] }, // Topic 1: from = Alice + { values: [hexToBase64(padHex(bobAddress, { size: 32 }))] }, // Topic 2: to = Bob + ], + }), + onLogTrigger + ), + ] +} +``` + +#### Example 3: "OR" filtering -To trigger on `Transfer` events where `from` is Alice **AND** `to` is Bob: +To trigger on `Transfer` events where `from` is **either** Alice **OR** Charlie: ```typescript -import { keccak256, toHex, pad } from "viem" +import { keccak256, toBytes, padHex } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -10926,20 +12423,24 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) - const aliceAddress = "0xAlice..." - const bobAddress = "0xBob..." + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) + const aliceAddress = "0xAlice..." as `0x${string}` + const charlieAddress = "0xCharlie..." as `0x${string}` return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Topic 0: Event signature (Transfer) - { values: [pad(aliceAddress)] }, // Topic 1: from = Alice - { values: [pad(bobAddress)] }, // Topic 2: to = Bob + { values: [hexToBase64(transferEventHash)] }, // Topic 0: Event signature (Transfer) + { + values: [ + hexToBase64(padHex(aliceAddress, { size: 32 })), + hexToBase64(padHex(charlieAddress, { size: 32 })), + ], + }, // Topic 1: from = Alice OR Charlie ], }), onLogTrigger @@ -10948,12 +12449,13 @@ const initWorkflow = (config: Config) => { } ``` -#### Example 3: "OR" filtering +#### Example 4: Multiple event types -To trigger on `Transfer` events where `from` is **either** Alice **OR** Charlie: +To listen for **multiple event types** from a single contract, provide multiple event signature hashes in `Topics[0]`: ```typescript -import { keccak256, toHex, pad } from "viem" +import { keccak256, toBytes } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -10966,19 +12468,17 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) - const aliceAddress = "0xAlice..." - const charlieAddress = "0xCharlie..." + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) + const approvalEventHash = keccak256(toBytes("Approval(address,address,uint256)")) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Topic 0: Event signature (Transfer) - { values: [pad(aliceAddress), pad(charlieAddress)] }, // Topic 1: from = Alice OR Charlie + { values: [hexToBase64(transferEventHash), hexToBase64(approvalEventHash)] }, // Listen for Transfer OR Approval ], }), onLogTrigger @@ -10987,12 +12487,13 @@ const initWorkflow = (config: Config) => { } ``` -#### Example 4: Multiple event types +#### Example 5: Multiple contracts -To listen for **multiple event types** from a single contract, provide multiple event signature hashes in `Topics[0]`: +To listen for the **same event from multiple contracts**, provide multiple addresses: ```typescript -import { keccak256, toHex } from "viem" +import { keccak256, toBytes } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { const network = getNetwork({ @@ -11005,17 +12506,16 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) - const approvalEventHash = keccak256(toHex("Approval(address,address,uint256)")) + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64("0xTokenA..."), hexToBase64("0xTokenB..."), hexToBase64("0xTokenC...")], topics: [ - { values: [transferEventHash, approvalEventHash] }, // Listen for Transfer OR Approval + { values: [hexToBase64(transferEventHash)] }, // Listen for Transfer events from any of these contracts ], }), onLogTrigger @@ -11024,11 +12524,14 @@ const initWorkflow = (config: Config) => { } ``` -#### Example 5: Multiple contracts +#### Example 6: Filtering on uint256 indexed parameter -To listen for the **same event from multiple contracts**, provide multiple addresses: +To filter on indexed `uint256` or other numeric types, convert them to a 32-byte hex value: ```typescript +import { keccak256, toBytes, numberToHex, padHex } from "viem" +import { hexToBase64 } from "@chainlink/cre-sdk" + const initWorkflow = (config: Config) => { const network = getNetwork({ chainFamily: "evm", @@ -11040,16 +12543,21 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) + // Example: event ValueChanged(address indexed user, uint256 indexed newValue) + const eventHash = keccak256(toBytes("ValueChanged(address,uint256)")) + const userAddress = padHex("0xUser..." as `0x${string}`, { size: 32 }) + const targetValue = padHex(numberToHex(12345), { size: 32 }) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: ["0xTokenA...", "0xTokenB...", "0xTokenC..."], + addresses: [hexToBase64(config.contractAddress)], topics: [ - { values: [transferEventHash] }, // Listen for Transfer events from any of these contracts + { values: [hexToBase64(eventHash)] }, // Topic 0: Event signature + { values: [hexToBase64(userAddress)] }, // Topic 1: user address + { values: [hexToBase64(targetValue)] }, // Topic 2: newValue = 12345 ], }), onLogTrigger @@ -11058,13 +12566,19 @@ const initWorkflow = (config: Config) => { } ``` +<Aside type="note" title="Converting Numbers to Topics"> + For indexed `uint256` parameters, use `numberToHex()` to convert the number to hex, then `padHex()` to ensure it's 32 + bytes, and finally `hexToBase64()` to encode it for the trigger configuration. For `bytes32` parameters, ensure + they're already 32 bytes and apply `hexToBase64()` directly. +</Aside> + ### Confidence level You can set the block confirmation level by adding the `confidence` field to the trigger configuration: ```typescript evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], confidence: "CONFIDENCE_LEVEL_FINALIZED", // Wait for finalized blocks }) ``` @@ -11178,7 +12692,7 @@ const onLogTrigger = (runtime: Runtime<Config>, log: EVMLog): string => { The type assertion ``` - as [\`0x${string}\`, ...\`0x${string}\`[]] + as [`0x${string}`, ...`0x${string}`[]] ``` tells TypeScript that `topics` is a non-empty array of @@ -11217,8 +12731,17 @@ const onLogTrigger = (runtime: Runtime<Config>, log: EVMLog): string => { Here's a complete example that listens for ERC20 `Transfer` events and decodes them: ```typescript -import { cre, getNetwork, type Runtime, type EVMLog, Runner, bytesToHex } from "@chainlink/cre-sdk" -import { keccak256, toHex, decodeEventLog, parseAbi } from "viem" +import { + EVMClient, + handler, + getNetwork, + type Runtime, + type EVMLog, + Runner, + bytesToHex, + hexToBase64, +} from "@chainlink/cre-sdk" +import { keccak256, toBytes, decodeEventLog, parseAbi } from "viem" type Config = { chainSelectorName: string @@ -11254,14 +12777,14 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) - const transferEventHash = keccak256(toHex("Transfer(address,address,uint256)")) + const evmClient = new EVMClient(network.chainSelector.selector) + const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.tokenAddress], - topics: [{ values: [transferEventHash] }], + addresses: [hexToBase64(config.tokenAddress)], + topics: [{ values: [hexToBase64(transferEventHash)] }], confidence: "CONFIDENCE_LEVEL_FINALIZED", }), onLogTrigger @@ -11273,8 +12796,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Testing log triggers in simulation @@ -11287,7 +12808,7 @@ For detailed instructions on simulating EVM log triggers, including interactive # HTTP Trigger: Configuration & Handler Source: https://docs.chain.link/cre/guides/workflow/using-triggers/http-trigger/configuration-ts -Last Updated: 2025-11-10 +Last Updated: 2026-01-20 The HTTP trigger fires when an external system makes an HTTP request to the trigger endpoint. @@ -11307,7 +12828,7 @@ You create an HTTP trigger by calling the `HTTPCapability.trigger()` method. Its </Aside> ```typescript -import { cre, type Runtime, type HTTPPayload, Runner } from "@chainlink/cre-sdk" +import { HTTPCapability, handler, type Runtime, type HTTPPayload, Runner } from "@chainlink/cre-sdk" type Config = { authorizedEVMAddress: string @@ -11321,10 +12842,10 @@ const onHttpTrigger = (runtime: Runtime<Config>, payload: HTTPPayload): string = } const initWorkflow = (config: Config) => { - const httpTrigger = new cre.capabilities.HTTPCapability() + const httpTrigger = new HTTPCapability() return [ - cre.handler( + handler( httpTrigger.trigger({ authorizedKeys: [ { @@ -11342,8 +12863,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` **About authorized keys:** @@ -11567,7 +13086,7 @@ The typical project setup flow for TypeScript workflows: # Project Configuration Source: https://docs.chain.link/cre/reference/project-configuration-ts -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 This page explains how to manage configuration within Chainlink Runtime Environment (CRE) projects. It covers the standard project structure, the roles and usage of the configuration files (`project.yaml` and `workflow.yaml`), and the concept of **targets** for handling environment-specific settings. @@ -11656,9 +13175,9 @@ production-settings: ``` <Aside type="note" title="Available chain names"> - For a complete list of supported networks and their chain names, see [Supported - Networks](/cre/guides/workflow/using-evm-client/supported-networks). For details on using chain selectors in your - workflow code, see [Chain Selectors](/cre/reference/sdk/evm-client-ts#chain-selectors). + For a complete list of supported networks and their chain names, see [Supported Networks](/cre/supported-networks). + For details on using chain selectors in your workflow code, see [Chain + Selectors](/cre/reference/sdk/evm-client-ts#chain-selectors). </Aside> #### Configuration fields @@ -11712,92 +13231,441 @@ production-settings: can optionally override project-level settings (like `workflow-owner-address`) for specific workflows. </Aside> -<Aside type="note" title="TypeScript workflow-path"> - For TypeScript workflows, `workflow-path` must point to the specific TypeScript entry file (e.g., `"./main.ts"`), - whereas Go workflows use `"."` to point to the workflow directory. -</Aside> +<Aside type="note" title="TypeScript workflow-path"> + For TypeScript workflows, `workflow-path` must point to the specific TypeScript entry file (e.g., `"./main.ts"`), + whereas Go workflows use `"."` to point to the workflow directory. +</Aside> + +### 3.3. Secrets configuration (`secrets.yaml`) + +`secrets.yaml` is an optional project-level file that maps logical secret names to environment variables. This allows you to decouple the secret names used in your code from the actual environment variable names. + +```yaml +# secrets.yaml (at project root) +secretsNames: + DATA_SOURCE_API_KEY: + - DATA_SOURCE_API_KEY_ENV +``` + +To use secrets in your workflow, reference this file in your `workflow.yaml`: + +```yaml +workflow-artifacts: + secrets-path: "../secrets.yaml" +``` + +For simulation, secret values are loaded from your `.env` file or environment variables. For deployed workflows, secrets are managed through the Vault DON using `cre secrets` commands. + +For complete details on using secrets in your workflows, see [Secrets Management](/cre/guides/workflow/secrets). + +## 4. Targets + +A target is a top-level key inside both `project.yaml` and `workflow.yaml`. It bundles all settings for a single environment or variant. + +The CLI selects the active target using the `--target` flag. Example: + +```sh +# Simulate using the 'staging-settings' target +cre workflow simulate my-workflow --target staging-settings +``` + +Alternatively, the `CRE_TARGET` environment variable can be used to specify the target. The CLI picks the active target in this order: + +1. `--target <name>` flag +2. `CRE_TARGET=<name>` environment variable + +### 4.1. Defining Multiple Targets + +You can store many targets in one file. This is useful for managing different environments (like simulation vs. production) or for testing variations of a workflow. + +```yaml +# In project.yaml + +# Target for simulation and testing +staging-settings: + rpcs: + - chain-name: ethereum-testnet-sepolia + url: https://ethereum-sepolia-rpc.publicnode.com + +# Target for production deployment +production-settings: + account: + workflow-owner-address: "0x123..." # Optional: For multi-sig wallets + rpcs: + - chain-name: ethereum-mainnet + url: https://mainnet.infura.io/v3/<YOUR-PROJECT-ID> +``` + +### 4.2. How Target Resolution Works + +When you run a CLI command with a target, e.g., `--target staging-settings`: + +1. Load the `staging-settings` target from `project.yaml`. +2. Load the same target from `workflow.yaml` (if the file exists and contains a matching target definition). +3. Merge the two objects. + - Keys present in both files → value from `workflow.yaml` wins. + - Keys present in only one file → that value is used. +4. Validate the final object before execution. + +<Aside type="caution" title="Matching target names"> + If your workflow directory contains a `workflow.yaml`, the target you specify must exist in both `project.yaml` and + `workflow.yaml`. A mismatch causes the CLI to abort with a clear error message. +</Aside> + +## 5. Updating dependencies + +When new networks or SDK features are released, you may need to update your project dependencies. + +### Updating the CLI + +Run [cre update](/cre/reference/cli/utilities#cre-update) to download and install the latest CLI version: + +```bash +cre update +``` + +New projects created with an updated CLI automatically use compatible SDK versions. + +### Updating the SDK (existing projects) + +If you created your project with an older CLI version, update the `@chainlink/cre-sdk` dependency in your workflow's `package.json`: + +```json +{ + "dependencies": { + "@chainlink/cre-sdk": "^1.0.7" + } +} +``` + +Then run `bun install` from your workflow directory to update `bun.lock`. + +### Checking your versions + +- **CLI version:** Run `cre version` +- **SDK version:** Check `package.json` or `bun.lock` in your workflow directory + +For a list of which versions support which networks, see [Supported Networks](/cre/supported-networks). + +--- + +# SDK Reference: Confidential HTTP Client +Source: https://docs.chain.link/cre/reference/sdk/confidential-http-client-ts +Last Updated: 2026-02-10 + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The [Confidential HTTP](/cre/capabilities/confidential-http-ts) Client lets you make privacy-preserving requests to external APIs from your workflow. Unlike the regular [`HTTPClient`](/cre/reference/sdk/http-client), the request executes inside a secure enclave, secrets are injected via templates, and responses can be optionally encrypted. + +- For use cases and a conceptual overview, see [The Confidential HTTP Capability](/cre/capabilities/confidential-http-ts) +- **Guide:** [Making Confidential Requests](/cre/guides/workflow/using-confidential-http-client/making-requests-ts) + +## Quick reference + +| Method | Description | +| --------------------------------------------------- | -------------------------------------------------------------------------------------- | +| [`sendRequest` (high-level)](#sendrequest) | **Recommended.** Makes a confidential HTTP request with built-in consensus and typing. | +| [`sendRequest` (low-level)](#low-level-sendrequest) | Makes a confidential HTTP request manually inside a `runInNodeMode` block. | + +## Core types + + +<Aside type="note" title="Runtime types vs JSON types"> + Each core type has a corresponding `Json` variant (e.g., `ConfidentialHTTPRequest` and `ConfidentialHTTPRequestJson`). The `Json` variant is the plain JSON-serializable form of the protobuf message. Both forms are accepted wherever a type is required. +</Aside> + +### `ConfidentialHTTPRequest` / `ConfidentialHTTPRequestJson` + +The top-level request type that combines an HTTP request with Vault DON secrets and encryption settings. + +| Field | Type | Description | +| ----------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `request` | `HTTPRequest` \| `HTTPRequestJson` | The HTTP request to execute inside the enclave. See [`HTTPRequest`](#httprequest--httprequestjson). | +| `vaultDonSecrets` | `SecretIdentifier[]` \| `SecretIdentifierJson[]` | List of secrets to fetch from the Vault DON and make available in the enclave. See [`SecretIdentifier`](#secretidentifier--secretidentifierjson). | +| `encryptOutput` | `boolean` | If `true`, encrypts the response body before it leaves the enclave. See [Response encryption](#response-encryption). Default: `false`. | + +### `HTTPRequest` / `HTTPRequestJson` + +Defines the HTTP request that will be executed inside the enclave. + +| Field | Type | Description | +| ---------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| `url` | `string` | The URL of the API endpoint. | +| `method` | `string` | The HTTP method (e.g., `"GET"`, `"POST"`). | +| `bodyString` | `string` (optional) | The request body as a string template. Use this for secret injection with `{{.secretName}}` placeholders. | +| `bodyBytes` | `Uint8Array` \| `string` (optional) | The request body as raw bytes (base64-encoded in JSON format). | +| `multiHeaders` | `{ [key: string]: HeaderValues }` (optional) | Request headers. Supports multiple values per key and template syntax for secret injection. | +| `templatePublicValues` | `{ [key: string]: string }` (optional) | Public (non-secret) values used to fill template placeholders in the body and headers. | +| `customRootCaCertPem` | `Uint8Array` \| `string` (optional) | Optional custom root CA certificate (PEM format) for verifying the external server's TLS certificate. | +| `timeout` | `Duration` \| `DurationJson` (optional) | Optional request timeout (e.g., `"5s"`). | + + +<Aside type="note" title="bodyString vs bodyBytes"> + The request body is a `oneof` field. Use `bodyString` for string templates with secret injection, or `bodyBytes` for raw binary data. Only one should be provided. +</Aside> + +### `HTTPResponse` / `HTTPResponseJson` + +The response returned from the enclave after the HTTP request completes. + +| Field | Type | Description | +| -------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `statusCode` | `number` | The HTTP status code. | +| `body` | `Uint8Array` \| `string` (base64) | The response body. If `encryptOutput` is `true`, this contains the encrypted body (see [Response encryption](#response-encryption)). | +| `multiHeaders` | `{ [key: string]: HeaderValues }` | The HTTP response headers. | + +### `SecretIdentifier` / `SecretIdentifierJson` + +Identifies a secret stored in the Vault DON. + +| Field | Type | Description | +| ----------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- | +| `key` | `string` | The logical name of the secret. Must match the template placeholder (e.g., `"myApiKey"` matches `{{.myApiKey}}`). | +| `namespace` | `string` | The secret namespace. | +| `owner` | `string` (optional) | Optional. The owner address for the secret. | + +### `HeaderValues` / `HeaderValuesJson` + +Represents multiple values for a single HTTP header key. + +| Field | Type | Description | +| -------- | ---------- | ------------------------------------------------------------------------------------------------ | +| `values` | `string[]` | The header values. Supports template syntax for secret injection (e.g., `"Basic {{.myToken}}"`). | + +### `ConfidentialHTTPSendRequester` + +The object passed to your fetch function when using the [high-level `sendRequest`](#sendrequest) pattern. It wraps the low-level client and provides a single method: + +| Method | Description | +| ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | +| `sendRequest(input: ConfidentialHTTPRequest \| ConfidentialHTTPRequestJson): { result: () => HTTPResponse }` | Sends a confidential HTTP request and returns the response. | + +You don't create this object yourself — it is provided by the SDK when your function is called. + +## Making requests + +### `sendRequest()` + +**Recommended.** The high-level `sendRequest` method handles `runInNodeMode` wrapping and consensus for you. You provide a function that receives a `ConfidentialHTTPSendRequester` and your arguments, and the SDK takes care of the rest. + +**Signature:** + +```typescript +sendRequest<TArgs extends unknown[], TOutput>( + runtime: Runtime<unknown>, + fn: (sendRequester: ConfidentialHTTPSendRequester, ...args: TArgs) => TOutput, + consensusAggregation: ConsensusAggregation<TOutput, true>, + unwrapOptions?: UnwrapOptions<TOutput>, +): (...args: TArgs) => { result: () => TOutput } +``` + +**Parameters:** + +- `runtime`: The `Runtime` instance from your trigger handler. +- `fn`: A function that receives a `ConfidentialHTTPSendRequester` plus any additional arguments you pass. Use the `sendRequester` to make the confidential request and return the parsed result. +- `consensusAggregation`: The consensus strategy (e.g., `consensusIdenticalAggregation()`, `consensusMedianAggregation()`). +- `unwrapOptions` (optional): Advanced option for controlling how complex (non-primitive) output types are unwrapped during consensus. Not needed for most use cases. + +**Returns:** + +A curried function that accepts `...args` and returns an object with a `.result()` method. + +**Example:** + +```typescript +import { + ConfidentialHTTPClient, + consensusIdenticalAggregation, + ok, + json, + type ConfidentialHTTPSendRequester, + type Runtime, +} from "@chainlink/cre-sdk" + +type Config = { url: string; owner: string } +type APIResult = { data: string } + +// 1. Define your fetch function +const fetchData = (sendRequester: ConfidentialHTTPSendRequester, config: Config): APIResult => { + const response = sendRequester + .sendRequest({ + request: { + url: config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.apiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "apiKey", owner: config.owner }], + }) + .result() + + if (!ok(response)) { + throw new Error(`Request failed: ${response.statusCode}`) + } + + return json(response) as APIResult +} + +// 2. Call sendRequest in your trigger handler +const onCronTrigger = (runtime: Runtime<Config>): string => { + const confHTTPClient = new ConfidentialHTTPClient() + + const result = confHTTPClient + .sendRequest(runtime, fetchData, consensusIdenticalAggregation<APIResult>())(runtime.config) + .result() + + return result.data +} +``` + +### Low-level `sendRequest()` + +The low-level overload gives you direct access to the client within a `runtime.runInNodeMode()` block. For Confidential HTTP, this offers minimal practical advantages over the high-level pattern because the API call already executes as a single request inside the enclave. Use this only if you have a specific reason to manage the `runInNodeMode` wrapping manually. + +**Signature:** + +```typescript +sendRequest( + runtime: NodeRuntime<unknown>, + input: ConfidentialHTTPRequest | ConfidentialHTTPRequestJson +): { result: () => HTTPResponse } +``` + +**Parameters:** + +- `runtime`: A `NodeRuntime` instance provided by `runtime.runInNodeMode()`. +- `input`: A `ConfidentialHTTPRequest` or `ConfidentialHTTPRequestJson` object containing the request, secrets, and encryption settings. + +**Returns:** + +An object with a `.result()` method that blocks until the request completes and returns the `HTTPResponse`. + +**Example:** + +```typescript +import { + ConfidentialHTTPClient, + consensusIdenticalAggregation, + type Runtime, + type NodeRuntime, +} from "@chainlink/cre-sdk" + +type Config = { url: string } + +const fetchData = (nodeRuntime: NodeRuntime<Config>): string => { + const client = new ConfidentialHTTPClient() + + const resp = client + .sendRequest(nodeRuntime, { + request: { + url: nodeRuntime.config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.apiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "apiKey" }], + encryptOutput: false, + }) + .result() + + if (resp.statusCode !== 200) { + throw new Error(`Request failed with status: ${resp.statusCode}`) + } + + const bodyText = new TextDecoder().decode(resp.body) + return bodyText +} + +// In your workflow +const onCronTrigger = (runtime: Runtime<Config>): string => { + const result = runtime.runInNodeMode(fetchData, consensusIdenticalAggregation<string>())().result() + + runtime.log(`Result: ${result}`) + return result +} +``` + +## Template syntax -### 3.3. Secrets configuration (`secrets.yaml`) +Secrets are injected into the request body and headers using Go template syntax: `{{.secretName}}`. The placeholder name must match the `key` field in the corresponding `SecretIdentifier`. -`secrets.yaml` is an optional project-level file that maps logical secret names to environment variables. This allows you to decouple the secret names used in your code from the actual environment variable names. +**Body template:** -```yaml -# secrets.yaml (at project root) -secretsNames: - DATA_SOURCE_API_KEY: - - DATA_SOURCE_API_KEY_ENV +```typescript +bodyString: '{"apiKey": "{{.myApiKey}}", "method": "{{.method}}", "params": []}', ``` -To use secrets in your workflow, reference this file in your `workflow.yaml`: +**Header template:** -```yaml -workflow-artifacts: - secrets-path: "../secrets.yaml" +```typescript +multiHeaders: { + "Authorization": { values: ["Basic {{.myCredential}}"] }, +}, ``` -For simulation, secret values are loaded from your `.env` file or environment variables. For deployed workflows, secrets are managed through the Vault DON using `cre secrets` commands. +### `templatePublicValues` (optional) -For complete details on using secrets in your workflows, see [Secrets Management](/cre/guides/workflow/secrets). +Every `{{.placeholder}}` in your body or headers is resolved inside the enclave. By default, placeholders are filled with **secrets** from `vaultDonSecrets`. But sometimes you have a placeholder value that isn't secret — for example, an RPC method name or a public parameter. That's what `templatePublicValues` is for: it lets you inject **non-secret** values into the same template. -## 4. Targets +This is purely a convenience. You could always hardcode the value directly in the body string instead: -A target is a top-level key inside both `project.yaml` and `workflow.yaml`. It bundles all settings for a single environment or variant. +```typescript +// These two are equivalent: -The CLI selects the active target using the `--target` flag. Example: +// Option 1: hardcoded in the body string +bodyString: '{"method": "eth_blockNumber", "auth": "{{.apiKey}}"}' -```sh -# Simulate using the 'staging-settings' target -cre workflow simulate my-workflow --target staging-settings +// Option 2: using templatePublicValues +bodyString: '{"method": "{{.method}}", "auth": "{{.apiKey}}"}' +templatePublicValues: { + method: "eth_blockNumber" +} ``` -Alternatively, the `CRE_TARGET` environment variable can be used to specify the target. The CLI picks the active target in this order: - -1. `--target <name>` flag -2. `CRE_TARGET=<name>` environment variable +`templatePublicValues` is useful when you want to keep the template generic and pass in dynamic values (e.g., from config) without string concatenation. -### 4.1. Defining Multiple Targets +**Example with both secret and public values:** -You can store many targets in one file. This is useful for managing different environments (like simulation vs. production) or for testing variations of a workflow. +```typescript +request: { + url: config.url, + method: "POST", + bodyString: '{"method": "{{.rpcMethod}}", "auth": "{{.apiKey}}"}', + templatePublicValues: { + rpcMethod: config.rpcMethod, // dynamic value from config, not a secret + }, +}, +vaultDonSecrets: [{ key: "apiKey", owner: config.owner }], // secret, from Vault DON +``` -```yaml -# In project.yaml +In this example, `{{.rpcMethod}}` is resolved from `templatePublicValues` (a dynamic, non-secret value from your workflow config) and `{{.apiKey}}` is resolved from the Vault DON (a secret). Both are resolved inside the enclave. -# Target for simulation and testing -staging-settings: - rpcs: - - chain-name: ethereum-testnet-sepolia - url: https://ethereum-sepolia-rpc.publicnode.com +## Response encryption -# Target for production deployment -production-settings: - account: - workflow-owner-address: "0x123..." # Optional: For multi-sig wallets - rpcs: - - chain-name: ethereum-mainnet - url: https://mainnet.infura.io/v3/<YOUR-PROJECT-ID> -``` +The `encryptOutput` field controls whether the response body is encrypted before leaving the enclave. -### 4.2. How Target Resolution Works +| encryptOutput | Secret key provided | Behavior | +| ----------------- | -------------------------------------------------------- | ------------------------------------------------------------- | +| `false` (default) | — | Response returned unencrypted. | +| `true` | `san_marino_aes_gcm_encryption_key` in `vaultDonSecrets` | Response AES-GCM encrypted with your symmetric key. | +| `true` | No key provided | Response TDH2 encrypted with the Vault DON master public key. | -When you run a CLI command with a target, e.g., `--target staging-settings`: +**AES-GCM encryption** is the recommended approach. Store a 256-bit (32-byte) AES key as a Vault DON secret with the identifier `san_marino_aes_gcm_encryption_key`, then decrypt the response in your own backend. -1. Load the `staging-settings` target from `project.yaml`. -2. Load the same target from `workflow.yaml` (if the file exists and contains a matching target definition). -3. Merge the two objects. - - Keys present in both files → value from `workflow.yaml` wins. - - Keys present in only one file → that value is used. -4. Validate the final object before execution. +The encrypted response body is structured as `nonce || ciphertext || tag`. -<Aside type="caution" title="Matching target names"> - If your workflow directory contains a `workflow.yaml`, the target you specify must exist in both `project.yaml` and - `workflow.yaml`. A mismatch causes the CLI to abort with a clear error message. -</Aside> +For a complete example with response encryption, see the [Making Confidential Requests guide](/cre/guides/workflow/using-confidential-http-client/making-requests-ts#response-encryption). --- # SDK Reference: Consensus & Aggregation Source: https://docs.chain.link/cre/reference/sdk/consensus-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 Aggregation is the process of taking many results from individual nodes and reducing them to a single, reliable value. This aggregated value is what the DON reaches consensus on. When you run code on individual nodes using [`runtime.runInNodeMode()`](/cre/reference/sdk/core-ts/#runtimeruninnodemode), you must provide an aggregation strategy to tell the DON how to produce this single, trustworthy outcome. This is achieved using a `ConsensusAggregation`. @@ -11808,7 +13676,7 @@ This is a generic type passed as the second argument to `runtime.runInNodeMode() There are two primary ways to specify an aggregation method: 1. [**Using built-in functions**](/cre/reference/sdk/consensus-ts#1-built-in-aggregation-functions): For simple types, use functions like [`consensusMedianAggregation()`](#consensusmedianaggregationt). -2. [**Using field-based aggregation**](/cre/reference/sdk/consensus-ts#2-field-based-aggregation-for-objects): For complex types (objects), use [`ConsensusAggregationByFields()`](#consensusaggregationbyfields). +2. [**Using field-based aggregation**](/cre/reference/sdk/consensus-ts#2-field-based-aggregation-for-objects): For complex types (objects), use [`ConsensusAggregationByFields()`](#consensusaggregationbyfieldstfields). ## 1. Built-in aggregation functions @@ -11942,6 +13810,7 @@ Creates a consensus aggregation strategy by specifying how to aggregate each fie ```typescript import { + HTTPClient, ConsensusAggregationByFields, median, identical, @@ -11967,7 +13836,7 @@ const fetchReserveData = (sendRequester: HTTPSendRequester, config: Config): Res } const onTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const reserveInfo = httpClient .sendRequest( @@ -11998,7 +13867,9 @@ Here's a complete example demonstrating both simple and field-based aggregation: ```typescript import { - cre, + CronCapability, + HTTPClient, + handler, Runner, consensusMedianAggregation, ConsensusAggregationByFields, @@ -12022,7 +13893,7 @@ type PriceData = { // Simple aggregation example const fetchSimplePrice = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const response = httpClient.sendRequest(nodeRuntime, { url: nodeRuntime.config.apiUrl }).result() const data = JSON.parse(response.body.toString()) return BigInt(data.price) @@ -12047,7 +13918,7 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = runtime.log(`Simple median price: ${simplePrice}`) // Example 2: Field-based aggregation - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const priceData = httpClient .sendRequest( runtime, @@ -12066,17 +13937,15 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: "0 */5 * * * *" }), onCronTrigger)] + return [handler(cron.trigger({ schedule: "0 */5 * * * *" }), onCronTrigger)] } export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Default Values @@ -12093,24 +13962,60 @@ If all nodes fail or consensus cannot be reached, the default value (`0n` in thi # SDK Reference: Core Source: https://docs.chain.link/cre/reference/sdk/core-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 This page provides a reference for the core data structures and functions of the CRE TypeScript SDK. These are the fundamental building blocks that every workflow uses, regardless of trigger types or capabilities. +## Import styles + +The CRE TypeScript SDK supports two equivalent import styles. **Both are fully supported**, produce identical behavior, and can be used interchangeably in your workflows. + +<Aside type="tip" title="Choose the style that fits your codebase"> + Both import patterns are **fully supported** and will continue to work. There are no plans to deprecate either style. + Choose whichever approach better matches your team's conventions. +</Aside> + +**Direct imports (recommended for new projects):** + +```typescript +import { Runner, HTTPClient, EVMClient, CronCapability, handler } from "@chainlink/cre-sdk" + +// Use directly +const httpClient = new HTTPClient() +const evmClient = new EVMClient(chainSelector) +``` + +**Namespace imports:** + +```typescript +import { cre, Runner } from "@chainlink/cre-sdk" + +// Access through cre namespace +const httpClient = new cre.capabilities.HTTPClient() +const evmClient = new cre.capabilities.EVMClient(chainSelector) +``` + +**When to use each style:** + +| Style | Best for | +| --------------------- | ---------------------------------------------------------------------------- | +| **Direct imports** | New projects, cleaner import statements, better tree-shaking | +| **Namespace imports** | Existing codebases already using this pattern, preference for grouped access | + ## Key concepts and components -### `cre.handler()` +### `handler()` -The `cre.handler()` function is the cornerstone of every workflow. It registers a handler that links a specific trigger to a callback function containing your workflow logic. It is typically called within your [`initWorkflow`](#initworkflow) function. +The `handler()` function is the cornerstone of every workflow. It registers a handler that links a specific trigger to a callback function containing your workflow logic. It is typically called within your [`initWorkflow`](#initworkflow) function. **Usage:** ```typescript -import { cre, type Runtime } from "@chainlink/cre-sdk" +import { handler, type Runtime } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { return [ - cre.handler( + handler( // 1. A configured trigger, e.g., cron.trigger(...) // This determines WHEN the workflow runs triggerInstance, @@ -12146,8 +14051,8 @@ To learn more about how to aggregate results from `NodeRuntime`, see the [Consen Both `Runtime` and `NodeRuntime` provide: - **`config`**: Access to your workflow's configuration -- **`now()`**: Returns the current `Date` object -- **`log(message: string)`**: Logs a message (accepts a single string argument) +- **`now()`**: Returns the current `Date` object. See [Time in CRE](/cre/guides/workflow/time-in-workflows-ts) for details. +- **`log(message: string)`**: Logs a message (see [Logging](#logging) below) - **`callCapability(...)`**: Internal method for calling capabilities (used by generated code) `Runtime` additionally provides: @@ -12156,6 +14061,35 @@ Both `Runtime` and `NodeRuntime` provide: - **`getSecret(...)`**: Access to workflow secrets - **`report(...)`**: Generate cryptographically signed reports +### Logging + +Use `runtime.log()` to output messages from your workflow. This is the **only way** to produce visible logs—`console.log` does not work in the WASM environment. + +```typescript +const onCronTrigger = (runtime: Runtime<Config>): string => { + runtime.log("Workflow started") + + const result = someOperation() + runtime.log(`Operation result: ${result}`) + + return "done" +} +``` + +**Where logs appear:** + +| Environment | Location | +| --------------------- | ------------------------------------------------------------------------------------ | +| **Simulation** | Terminal output with `[USER LOG]` prefix | +| **Deployed workflow** | CRE UI → Workflows → select workflow → Execution tab → click an execution → Logs tab | + +See [Monitoring & Debugging Workflows](/cre/guides/operations/monitoring-workflows#logs-tab) for details on viewing logs for deployed workflows. + +**Important notes:** + +- `runtime.log()` accepts a **single string argument**—use template literals to include variables +- Logs are only available inside callback functions where you have access to the `runtime` object + ### Understanding the `.result()` Pattern All SDK capabilities in the TypeScript SDK use a two-step pattern for asynchronous operations: @@ -12175,11 +14109,11 @@ const response = request.result() **Common usage:** These steps are often chained together for simplicity: ```typescript -import { cre, encodeCallMsg, LAST_FINALIZED_BLOCK_NUMBER, type Runtime } from "@chainlink/cre-sdk" +import { EVMClient, encodeCallMsg, LAST_FINALIZED_BLOCK_NUMBER, type Runtime } from "@chainlink/cre-sdk" import { zeroAddress } from "viem" const onCronTrigger = (runtime: Runtime<Config>): string => { - const evmClient = new cre.capabilities.EVMClient(chainSelector) + const evmClient = new EVMClient(chainSelector) // Inline pattern: initiate and get result in one expression const contractCall = evmClient @@ -12270,16 +14204,80 @@ export async function main() { // Run your workflow initialization function await runner.run(initWorkflow) } - -main() ``` +<Aside type="note" title="SDK v1.0.2+ Changes"> + Starting with SDK v1.0.2, the SDK handles `main()` execution automatically: + + - **Calling `main()` is optional**: The SDK automatically executes the `main()` function during compilation. You no longer need to call `main()` at the end of your workflow file. + - **Automatic error handling**: If you don't provide custom error handling, the SDK automatically adds `.catch(sendErrorResponse)` to ensure errors are properly reported instead of silently failing. +</Aside> + +**All of these patterns are valid:** + +- **Pattern 1: Let the SDK handle everything (recommended)** + + ```typescript + export async function main() { + const runner = await Runner.newRunner<Config>() + await runner.run(initWorkflow) + } + // No need to call main() - the SDK automatically appends: + // main().catch(sendErrorResponse) + ``` + +- **Pattern 2: Explicit call without `.catch()` - SDK adds error handling** + + ```typescript + export async function main() { + const runner = await Runner.newRunner<Config>() + await runner.run(initWorkflow) + } + + main() // SDK transforms this to: main().catch(sendErrorResponse) + ``` + +- **Pattern 3: Custom error handling - SDK respects your handler** + + ```typescript + import { sendErrorResponse } from "@chainlink/cre-sdk" + + export async function main() { + const runner = await Runner.newRunner<Config>() + await runner.run(initWorkflow) + } + + // If you provide .catch(), the SDK leaves it untouched + main().catch((error) => { + // Your custom error handling logic + // You should call sendErrorResponse to report the error + sendErrorResponse(error) + }) + ``` + +<Aside type="caution" title="No console access in workflows"> + CRE workflows are compiled to WebAssembly (WASM), where `console.log` and `console.error` **produce no output**. Use + `runtime.log()` for logging within your callback functions—these logs appear in simulation output with the `[USER + LOG]` prefix and in the [CRE UI Logs tab](/cre/guides/operations/monitoring-workflows#logs-tab) for deployed + workflows. For error reporting from `main()`, use the SDK's `sendErrorResponse` function. +</Aside> + +<Aside type="tip" title="When to use custom error handling"> + Most workflows don't need custom error handling—the SDK's default handler reports errors properly. Only add a custom + `.catch()` handler if you need to transform errors, add context, or perform cleanup before reporting. If you provide a + custom handler, remember to call `sendErrorResponse(error)` to ensure the error is properly reported. +</Aside> + +`sendErrorResponse` reports the error to CRE and marks the execution as failed. + +- In **simulation**, the error appears in your terminal output. +- For **deployed workflows**, you'll see it in the [Execution tab](/cre/guides/operations/monitoring-workflows#execution-history) with a `Failure` status and the error message in the Logs tab. + **Key points:** - Must be an `async` function - Must call `Runner.newRunner<Config>()` with an optional `configSchema` parameter for validation - Must call `runner.run(initWorkflow)` to execute your workflow -- Must invoke `main()` at the end of your file ### `initWorkflow` @@ -12288,7 +14286,7 @@ This is the second required entry point. The CRE runner calls this function to i **Required Signature:** ```typescript -import { cre, type Runtime } from "@chainlink/cre-sdk" +import { handler, type Runtime } from "@chainlink/cre-sdk" function initWorkflow(config: Config): Array<HandlerEntry<Config, any, any, any>> ``` @@ -12299,7 +14297,7 @@ function initWorkflow(config: Config): Array<HandlerEntry<Config, any, any, any> **Returns:** -- An array of handlers created with `cre.handler()` +- An array of handlers created with `handler()` <Aside type="note" title="Using secrets"> If your workflow uses secrets, you can add a second parameter `secretsProvider: SecretsProvider` to access the @@ -12309,7 +14307,7 @@ function initWorkflow(config: Config): Array<HandlerEntry<Config, any, any, any> **Example:** ```typescript -import { cre, type Runtime, type CronPayload } from "@chainlink/cre-sdk" +import { CronCapability, handler, type Runtime, type CronPayload } from "@chainlink/cre-sdk" // Callback function executed by the handler const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string => { @@ -12318,9 +14316,9 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } ``` @@ -12354,14 +14352,14 @@ This example uses `runInNodeMode` to fetch data from an API on each node, and th ```typescript import { - cre, + HTTPClient, consensusMedianAggregation, type Runtime, type NodeRuntime, } from "@chainlink/cre-sdk" const fetchPrice = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // Fetch price from API using nodeRuntime return fetchOffchainPrice(nodeRuntime) } @@ -12395,7 +14393,7 @@ const onTrigger = (runtime: Runtime<Config>, ...): string => { # SDK Reference: EVM Client Source: https://docs.chain.link/cre/reference/sdk/evm-client-ts -Last Updated: 2025-11-04 +Last Updated: 2026-02-03 This page provides a reference for the `EVMClient`, the low-level tool for all interactions with EVM-compatible blockchains. The client includes a comprehensive set of read, write, and utility methods for building chain-aware workflows. @@ -12404,7 +14402,7 @@ This page provides a reference for the `EVMClient`, the low-level tool for all i To use the client, you must instantiate it with the numeric `ChainSelector` ID for the blockchain you intend to interact with. ```typescript -import { cre, getNetwork } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork } from "@chainlink/cre-sdk" // Get network information by chain selector name const network = getNetwork({ @@ -12418,7 +14416,7 @@ if (!network) { } // Instantiate a client for Ethereum Sepolia -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) ``` <Aside type="note" title="What is a Chain Selector?"> @@ -12441,9 +14439,9 @@ const network = getNetwork({ }) // Access network properties -console.log(network.chainSelector.selector) // 16015286601757825753n (bigint) -console.log(network.chainSelector.name) // "ethereum-testnet-sepolia" -console.log(network.family) // "evm" +// network.chainSelector.selector → 16015286601757825753n (bigint) +// network.chainSelector.name → "ethereum-testnet-sepolia" +// network.family → "evm" ``` ## Read & query methods @@ -12467,10 +14465,10 @@ callContract( This is the main input object for the `callContract()` method. -| Field | Type | Required | Description | -| ------------- | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `call` | `CallMsgJson` | Yes | Contains the actual details of the function call you want to make. | -| `blockNumber` | `string` | No | The block number to query. Use `LAST_FINALIZED_BLOCK_NUMBER` for finalized blocks or `LATEST_BLOCK_NUMBER` for the most recent block. Defaults to `"latest"`. | +| Field | Type | Required | Description | +| ------------- | ------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `call` | `CallMsgJson` | Yes | Contains the actual details of the function call you want to make. | +| `blockNumber` | `BigIntJson` | No | The block number to query. Accepts:<br />• `LATEST_BLOCK_NUMBER` (default): the most recent block<br />• `LAST_FINALIZED_BLOCK_NUMBER`: a finalized block<br />• **`BigIntJson` object**: an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths) for conversion details).<br /><br />See [Finality and Confidence Levels](/cre/concepts/finality-ts) for finality strategies. | #### `CallMsg` / `CallMsgJson` @@ -12493,7 +14491,7 @@ This is the object returned by `.result()` when the `callContract()` method succ #### Usage example ```typescript -import { cre, getNetwork, encodeCallMsg, bytesToHex, LAST_FINALIZED_BLOCK_NUMBER } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, encodeCallMsg, bytesToHex, LAST_FINALIZED_BLOCK_NUMBER } from "@chainlink/cre-sdk" import { encodeFunctionData, decodeFunctionResult, zeroAddress } from "viem" import { Storage } from "../contracts/abi" @@ -12503,7 +14501,7 @@ const network = getNetwork({ chainSelectorName: "ethereum-testnet-sepolia", isTestnet: true, }) -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) // Encode the contract call data const callData = encodeFunctionData({ @@ -12589,10 +14587,10 @@ balanceAt( #### `BalanceAtRequest` / `BalanceAtRequestJson` -| Field | Type | Required | Description | -| ------------- | -------- | -------- | --------------------------------------------------------- | -| `account` | `string` | Yes | The 20-byte address of the account to query (hex string). | -| `blockNumber` | `string` | No | The block number to query. Defaults to `"latest"`. | +| Field | Type | Required | Description | +| ------------- | ------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `account` | `string` | Yes | The 20-byte address of the account to query (hex string). | +| `blockNumber` | `BigIntJson` | No | The block number to query. Accepts `LATEST_BLOCK_NUMBER` (default), `LAST_FINALIZED_BLOCK_NUMBER`, or a `BigIntJson` object for an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths)). See [Finality and Confidence Levels](/cre/concepts/finality-ts). | #### `BalanceAtReply` @@ -12724,9 +14722,9 @@ headerByNumber( #### `HeaderByNumberRequest` / `HeaderByNumberRequestJson` -| Field | Type | Required | Description | -| ------------- | -------- | -------- | -------------------------------------------------------------------------------- | -| `blockNumber` | `string` | No | The number of the block to retrieve. If `undefined`, retrieves the latest block. | +| Field | Type | Required | Description | +| ------------- | ------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `blockNumber` | `BigIntJson` | No | The number of the block to retrieve. Accepts `undefined` for `latest` (default), `LATEST_BLOCK_NUMBER`, `LAST_FINALIZED_BLOCK_NUMBER`, or a `BigIntJson` object for an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths)). See [Finality and Confidence Levels](/cre/concepts/finality-ts). | #### `HeaderByNumberReply` @@ -12793,7 +14791,7 @@ writeReport( #### Usage example ```typescript -import { cre, getNetwork, hexToBase64, bytesToHex } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, hexToBase64, bytesToHex } from "@chainlink/cre-sdk" import { encodeFunctionData } from "viem" import { ReserveManager } from "../contracts/abi" @@ -12944,6 +14942,86 @@ function hexToBase64(hex: Hex): string *** +### `protoBigIntToBigint()` + +Converts a protobuf `BigInt` (returned by SDK methods like `headerByNumber`) to a native JavaScript `bigint`. Use this when you need to perform arithmetic on block numbers or other numeric values returned from the blockchain. + +**Signature:** + +```typescript +function protoBigIntToBigint(pb: ProtoBigInt): bigint +``` + +**Parameters:** + +- `pb`: A protobuf `BigInt` object with `absVal` (Uint8Array) and `sign` (bigint) fields + +**Returns:** + +A native JavaScript `bigint` value. + +**Usage:** + +```typescript +import { protoBigIntToBigint } from "@chainlink/cre-sdk" + +// Get the latest block number from the blockchain +const latestHeader = evmClient.headerByNumber(runtime, {}).result() + +// Convert the protobuf BigInt to a native bigint for arithmetic +const latestBlockNum = protoBigIntToBigint(latestHeader.header.blockNumber) +const customBlock = latestBlockNum - 500n // Now you can do arithmetic + +// latestBlockNum → e.g., 12345678n +// customBlock → e.g., 12345178n (500 blocks earlier) +``` + +See [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths) for a complete example. + +*** + +### `blockNumber()` + +Converts a native `bigint`, `number`, or `string` to the protobuf `BigInt` JSON format required by SDK methods. This is a convenience alias for `bigintToProtoBigInt`. Use this when specifying an explicit block height for contract calls or other blockchain queries. + +**Signature:** + +```typescript +function blockNumber(n: number | bigint | string): BigIntJson +``` + +**Parameters:** + +- `n`: The block number as a native `bigint`, `number`, or `string` + +**Returns:** + +A `BigIntJson` object in the protobuf format expected by SDK methods. + +**Usage:** + +```typescript +import { blockNumber, encodeCallMsg } from "@chainlink/cre-sdk" +import { zeroAddress } from "viem" + +// Read from a specific historical block +const historicalBlock = 9767655n +const contractCall = evmClient + .callContract(runtime, { + call: encodeCallMsg({ + from: zeroAddress, + to: contractAddress, + data: callData, + }), + blockNumber: blockNumber(historicalBlock), + }) + .result() +``` + +See [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths) for a complete example. + +*** + ### `prepareReportRequest()` Prepares a report request with default EVM encoding parameters for use with `runtime.report()`. This helper simplifies report generation by automatically setting the standard encoding configuration (`evm`, `ecdsa`, `keccak256`) required for EVM-based workflows. @@ -13077,7 +15155,7 @@ if (!network) { } // Access the numeric chain selector (bigint) -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) // network.chainSelector.selector is 16015286601757825753n (bigint) ``` @@ -13086,7 +15164,7 @@ const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) The `EVMClient` class includes a static `SUPPORTED_CHAINS` constant with all available chain selectors: ```typescript -cre.capabilities.EVMClient.SUPPORTED_CHAINS +EVMClient.SUPPORTED_CHAINS // Returns: // { // 'avalanche-mainnet': 6433500567565415381n, @@ -13100,28 +15178,38 @@ cre.capabilities.EVMClient.SUPPORTED_CHAINS This table shows the chain selector names and their numeric IDs. In your configuration files (`project.yaml`, `config.staging.json`, `config.production.json`, etc.), you always use the **String Name**. The numeric ID is used internally by the SDK and is returned by the `getNetwork()` helper function. + <Aside type="note" title="Related resources"> - - **Forwarder addresses**: For network-specific forwarder contract addresses, see [Supported - Networks](/cre/guides/workflow/using-evm-client/supported-networks) - **RPC configuration**: For configuring RPC - endpoints in `project.yaml`, see [Project Configuration](/cre/reference/project-configuration) -</Aside> - -| Chain | String Name | Numeric ID | -| ----------------- | ----------------------------------- | -------------------- | -| Arbitrum One | ethereum-mainnet-arbitrum-1 | 4949039107694359620 | -| Arbitrum Sepolia | ethereum-testnet-sepolia-arbitrum-1 | 3478487238524512106 | -| Avalanche Mainnet | avalanche-mainnet | 6433500567565415381 | -| Avalanche Fuji | avalanche-testnet-fuji | 14767482510784806043 | -| Base Mainnet | ethereum-mainnet-base-1 | 15971525489660198786 | -| Base Sepolia | ethereum-testnet-sepolia-base-1 | 10344971235874465080 | -| BNB Chain Mainnet | binance_smart_chain-mainnet | 11344663589394136015 | -| BNB Chain Testnet | binance_smart_chain-testnet | 5142893604156789321 | -| Ethereum Mainnet | ethereum-mainnet | 5009297550715157269 | -| Ethereum Sepolia | ethereum-testnet-sepolia | 16015286601757825753 | -| OP Mainnet | ethereum-mainnet-optimism-1 | 3734403246176062136 | -| OP Sepolia | ethereum-testnet-sepolia-optimism-1 | 5224473277236331295 | -| Polygon Mainnet | polygon-mainnet | 4051577828743386545 | -| Polygon Amoy | polygon-testnet-amoy | 16281711391670634445 | + - **Forwarder addresses**: For network-specific forwarder contract addresses, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) + - **RPC configuration**: For configuring RPC endpoints in `project.yaml`, see [Project Configuration](/cre/reference/project-configuration) +</Aside> + +| Chain | String Name | Numeric ID | +| ------------------- | ------------------------------------- | -------------------- | +| Apechain Curtis | apechain-testnet-curtis | 9900119385908781505 | +| Arc Testnet | arc-testnet | 3034092155422581607 | +| Arbitrum One | ethereum-mainnet-arbitrum-1 | 4949039107694359620 | +| Arbitrum Sepolia | ethereum-testnet-sepolia-arbitrum-1 | 3478487238524512106 | +| Avalanche Mainnet | avalanche-mainnet | 6433500567565415381 | +| Avalanche Fuji | avalanche-testnet-fuji | 14767482510784806043 | +| Base Mainnet | ethereum-mainnet-base-1 | 15971525489660198786 | +| Base Sepolia | ethereum-testnet-sepolia-base-1 | 10344971235874465080 | +| BNB Chain Mainnet | binance_smart_chain-mainnet | 11344663589394136015 | +| BNB Chain Testnet | binance_smart_chain-testnet | 13264668187771770619 | +| Ethereum Mainnet | ethereum-mainnet | 5009297550715157269 | +| Ethereum Sepolia | ethereum-testnet-sepolia | 16015286601757825753 | +| Hyperliquid Testnet | hyperliquid-testnet | 4286062357653186312 | +| Ink Sepolia | ink-testnet-sepolia | 9763904284804119144 | +| Jovay Testnet | jovay-testnet | 945045181441419236 | +| Linea Sepolia | ethereum-testnet-sepolia-linea-1 | 5719461335882077547 | +| OP Mainnet | ethereum-mainnet-optimism-1 | 3734403246176062136 | +| OP Sepolia | ethereum-testnet-sepolia-optimism-1 | 5224473277236331295 | +| Plasma Testnet | plasma-testnet | 3967220077692964309 | +| Polygon Mainnet | polygon-mainnet | 4051577828743386545 | +| Polygon Amoy | polygon-testnet-amoy | 16281711391670634445 | +| World Chain Sepolia | ethereum-testnet-sepolia-worldchain-1 | 5299555114858065850 | +| ZKSync Era | ethereum-mainnet-zksync-1 | 1562403441176082196 | +| ZKSync Era Sepolia | ethereum-testnet-sepolia-zksync-1 | 6898391096552792247 | ### Usage in configuration files @@ -13164,14 +15252,14 @@ if (!network) { throw new Error(`Network not found: ${config.evms[0].chainName}`) } -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) ``` --- # SDK Reference: HTTP Client Source: https://docs.chain.link/cre/reference/sdk/http-client-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-26 This page provides a reference for making offchain HTTP requests using the `HTTPClient`. This is a "node-level" action capability, meaning it executes on each individual node in the DON. @@ -13211,7 +15299,7 @@ A curried function that accepts your custom arguments and returns an object with **Example:** ```typescript -import { cre, consensusMedianAggregation, type Runtime, type HTTPSendRequester } from "@chainlink/cre-sdk" +import { HTTPClient, consensusMedianAggregation, type Runtime, type HTTPSendRequester } from "@chainlink/cre-sdk" interface Config { apiUrl: string @@ -13233,7 +15321,7 @@ const fetchPrice = (sendRequester: HTTPSendRequester, url: string): number => { // In your workflow const workflow = (runtime: Runtime<Config>) => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // Call the high-level sendRequest with your custom function const price = httpClient @@ -13341,11 +15429,11 @@ An object with a `.result()` method that blocks until the HTTP request completes **Example:** ```typescript -import { cre, consensusMedianAggregation, type Runtime, type NodeRuntime } from "@chainlink/cre-sdk" +import { HTTPClient, consensusMedianAggregation, type Runtime, type NodeRuntime } from "@chainlink/cre-sdk" // Low-level usage with manual node mode const fetchPrice = (nodeRuntime: NodeRuntime<Config>): number => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const response = httpClient .sendRequest(nodeRuntime, { @@ -13550,14 +15638,65 @@ const fetchPrice = (sendRequester: HTTPSendRequester, url: string): number => { Defines the parameters for an outgoing HTTP request. -| Field | Type | Description | -| --------------- | ------------------------------------------------- | --------------------------------------------------------------- | -| `url` | `string` | The URL of the API endpoint. | -| `method` | `string` (optional) | The HTTP method (e.g., `"GET"`, `"POST"`). Defaults to `"GET"`. | -| `headers` | `{ [key: string]: string }` (optional) | Optional HTTP headers. | -| `body` | `string` (base64-encoded) (optional) | Optional raw request body (must be base64-encoded). | -| `timeoutMs` | `number` (optional) | Optional request timeout in milliseconds. | -| `cacheSettings` | `CacheSettings` \| `CacheSettingsJson` (optional) | Optional caching behavior for the request. | + +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + +| Field | Type | Description | +| --------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `url` | `string` | The URL of the API endpoint. | +| `method` | `string` (optional) | The HTTP method (e.g., `"GET"`, `"POST"`). Defaults to `"GET"`. | +| `headers` | `{ [key: string]: string }` (optional) | Optional HTTP headers. | +| `body` | `string` (base64-encoded) (optional) | Optional raw request body (must be base64-encoded). | +| `timeout` | `string` (optional) | Request timeout as a duration string (e.g., `"5s"`, `"8s"`). See [Request Timeout](#request-timeout) below for details. | +| `cacheSettings` | `CacheSettings` \| `CacheSettingsJson` (optional) | Optional caching behavior for the request. | + +### Request Timeout + +The `timeout` field specifies how long to wait for an HTTP request to complete before cancelling it. + +**Format:** + +- Specify timeout as a string ending with `"s"` (seconds) +- Examples: `"5s"` (5 seconds), `"8s"` (8 seconds), `"3.5s"` (3.5 seconds) + + +<Aside type="note" title="Protocol Buffers Duration"> + Under the hood, `timeout` uses the [Protocol Buffers Duration type](https://protobuf.dev/reference/protobuf/google.protobuf/#duration). In JSON format, it's encoded as a string ending with "s", where fractional seconds can represent nanosecond precision if needed. +</Aside> + +**Default and Limits:** + +- **Default**: If not specified, a default timeout of **5 seconds** is applied +- **Maximum**: Default maximum is **10 seconds**. Requests exceeding this limit will error + +**Example:** + +```typescript +type Config = { + apiUrl: string + requestTimeout: string +} + +const httpClient = new HTTPClient() + +const req = { + method: "GET", + url: config.apiUrl, + timeout: config.requestTimeout, // e.g., "8s" +} + +const response = httpClient.sendRequest(nodeRuntime, req).result() +``` + +**Example configuration:** + +```yaml +# config.yaml +apiUrl: "https://api.example.com/data" +requestTimeout: "8s" # Max: 10s +``` ### `CacheSettings` / `CacheSettingsJson` @@ -13649,7 +15788,7 @@ const manualData = JSON.parse(manualText) ### Simple GET request ```typescript -import { cre, consensusMedianAggregation, ok, json, type HTTPSendRequester } from "@chainlink/cre-sdk" +import { HTTPClient, consensusMedianAggregation, ok, json, type HTTPSendRequester } from "@chainlink/cre-sdk" const fetchData = (sendRequester: HTTPSendRequester, url: string): number => { const response = sendRequester.sendRequest({ url }).result() @@ -13663,14 +15802,14 @@ const fetchData = (sendRequester: HTTPSendRequester, url: string): number => { } // In your workflow -const httpClient = new cre.capabilities.HTTPClient() +const httpClient = new HTTPClient() const result = httpClient.sendRequest(runtime, fetchData, consensusMedianAggregation<number>())(apiUrl).result() ``` ### POST request with caching ```typescript -import { cre, consensusIdenticalAggregation, ok, json, type HTTPSendRequester } from "@chainlink/cre-sdk" +import { HTTPClient, consensusIdenticalAggregation, ok, json, type HTTPSendRequester } from "@chainlink/cre-sdk" const createResource = (sendRequester: HTTPSendRequester, payload: { name: string }): { id: string } => { // Encode the body as base64 @@ -13701,7 +15840,7 @@ const createResource = (sendRequester: HTTPSendRequester, payload: { name: strin } // In your workflow -const httpClient = new cre.capabilities.HTTPClient() +const httpClient = new HTTPClient() const resource = httpClient .sendRequest(runtime, createResource, consensusIdenticalAggregation<{ id: string }>())({ name: "My Resource" }) .result() @@ -13713,7 +15852,7 @@ For complex objects with multiple fields, use `ConsensusAggregationByFields()`: ```typescript import { - cre, + HTTPClient, ConsensusAggregationByFields, median, identical, @@ -13745,7 +15884,7 @@ const fetchReserveInfo = (sendRequester: HTTPSendRequester, url: string): Reserv } // In your workflow -const httpClient = new cre.capabilities.HTTPClient() +const httpClient = new HTTPClient() const reserveInfo = httpClient .sendRequest( runtime, @@ -13763,12 +15902,7 @@ const reserveInfo = httpClient # SDK Reference Source: https://docs.chain.link/cre/reference/sdk/overview-ts -Last Updated: 2025-11-04 - -<Aside type="note" title="Required SDK Version: v1.0.0"> - The CRE CLI automatically includes version `v1.0.0` of the `@chainlink/cre-sdk` package when you initialize a new - TypeScript workflow with `cre init`. -</Aside> +Last Updated: 2026-02-03 This section provides a detailed technical reference for the public interfaces of the CRE TypeScript SDK. Use this reference for quick lookups of specific functions, types, and method signatures. @@ -13776,11 +15910,12 @@ This section provides a detailed technical reference for the public interfaces o The SDK Reference is broken down into several pages, each corresponding to a core part of the SDK's functionality: -- **[Core SDK](/cre/reference/sdk/core)**: Covers the fundamental building blocks of any workflow, including `cre.handler`, `Runtime`, and the `.result()` pattern for promise resolution. -- **[Triggers](/cre/reference/sdk/triggers)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). -- **[EVM Client](/cre/reference/sdk/evm-client)**: Provides a reference for the `cre.capabilities.EVMClient`, the primary tool for all EVM interactions, including reads and writes. -- **[HTTP Client](/cre/reference/sdk/http-client)**: Provides a reference for the `cre.capabilities.HTTPClient`, used for making offchain API requests from individual nodes. -- **[Consensus & Aggregation](/cre/reference/sdk/consensus)**: Describes how to use aggregators like `consensusMedianAggregation` and `ConsensusAggregationByFields` with `runtime.runInNodeMode()` to process and consolidate data from multiple nodes. +- **[Core SDK](/cre/reference/sdk/core-ts)**: Covers the fundamental building blocks of any workflow, including `handler`, `Runtime`, and the `.result()` pattern for promise resolution. +- **[Triggers](/cre/reference/sdk/triggers/overview-ts)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). +- **[EVM Client](/cre/reference/sdk/evm-client-ts)**: Provides a reference for the `EVMClient`, the primary tool for all EVM interactions, including reads and writes. +- **[HTTP Client](/cre/reference/sdk/http-client-ts)**: Provides a reference for the `HTTPClient`, used for making offchain API requests from individual nodes. +- **[Confidential HTTP Client](/cre/reference/sdk/confidential-http-client-ts)** *(Experimental)*: Provides a reference for the `ConfidentialHTTPClient`, used for privacy-preserving API requests with enclave execution and optional response encryption. +- **[Consensus & Aggregation](/cre/reference/sdk/consensus-ts)**: Describes how to use aggregators like `consensusMedianAggregation` and `ConsensusAggregationByFields` with `runtime.runInNodeMode()` to process and consolidate data from multiple nodes. ## Package Structure @@ -13788,11 +15923,20 @@ The TypeScript SDK is distributed as a single npm package `@chainlink/cre-sdk` t ```typescript import { - cre, // Main SDK namespace with capabilities + // Capabilities + CronCapability, + HTTPCapability, + HTTPClient, + EVMClient, + // Core functions + handler, // Register handlers Runner, // Workflow runner type Runtime, // Runtime interface type NodeRuntime, // Node-level runtime interface - consensusMedianAggregation, // Consensus aggregators + // Consensus + consensusMedianAggregation, + consensusIdenticalAggregation, + // Utilities getNetwork, // Chain selector utilities bytesToHex, // Data conversion utilities hexToBase64, @@ -13800,6 +15944,12 @@ import { } from "@chainlink/cre-sdk" ``` +<Aside type="note" title="Import styles"> + The SDK supports two import styles: **direct imports** (shown above) and **namespace imports** (e.g., + `cre.capabilities.HTTPClient`). Both are fully supported and produce identical behavior. See the [Core SDK + Reference](/cre/reference/sdk/core-ts#import-styles) for details on both patterns. +</Aside> + ## Understanding TypeScript Types The TypeScript SDK uses Protocol Buffers for type definitions, which generates two type representations for each message: @@ -13846,16 +15996,16 @@ TypeScript workflows are compiled to WebAssembly (WASM) using Javy and QuickJS. # SDK Reference: Cron Trigger Source: https://docs.chain.link/cre/reference/sdk/triggers/cron-trigger-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 The Cron Trigger fires at a specified schedule using standard cron expressions. It is ideal for workflows that need to run at regular intervals. ## Creating the trigger ```typescript -import { cre } from "@chainlink/cre-sdk" +import { CronCapability } from "@chainlink/cre-sdk" -const cron = new cre.capabilities.CronCapability() +const cron = new CronCapability() const trigger = cron.trigger({ schedule: "0 */10 * * * *" }) // Every 10 minutes ``` @@ -13943,7 +16093,7 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = ## Complete Example ```typescript -import { cre, Runner, type Runtime, type CronPayload } from "@chainlink/cre-sdk" +import { CronCapability, handler, Runner, type Runtime, type CronPayload } from "@chainlink/cre-sdk" type Config = { schedule: string @@ -13955,31 +16105,37 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` --- # SDK Reference: EVM Log Trigger Source: https://docs.chain.link/cre/reference/sdk/triggers/evm-log-trigger-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-28 The EVM Log Trigger fires when a specific log (event) is emitted by an onchain smart contract. ## Creating the trigger +<Aside type="note" title="Base64 Encoding Required"> + **All addresses and topic values must be base64 encoded** using the `hexToBase64()` helper function from the CRE SDK. + While the workflow simulator accepts raw hex strings for convenience during development, **deployed workflows require + base64 encoding**. Always use `hexToBase64()` on addresses and topic values to ensure your workflow works in both + simulation and production. +</Aside> + ```typescript -import { cre } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, hexToBase64 } from "@chainlink/cre-sdk" +import { keccak256, toBytes } from "viem" // Create an EVMClient instance with a chain selector const network = getNetwork({ @@ -13988,22 +16144,16 @@ const network = getNetwork({ isTestnet: true, }) -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) -// Basic log trigger for a contract address -const trigger = evmClient.logTrigger({ - addresses: ["0x123...abc"], -}) +// Create a log trigger with address and event signature +const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) -// With topics for event filtering const trigger = evmClient.logTrigger({ - addresses: ["0x123...abc"], + addresses: [hexToBase64("0x123...abc")], topics: [ { - values: [ - // Keccak256 hash of "Transfer(address,address,uint256)" - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - ], + values: [hexToBase64(transferEventHash)], }, ], }) @@ -14015,22 +16165,22 @@ The `logTrigger()` method accepts a configuration object with the following fiel | Field | Type | Description | | ------------ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `addresses` | `string[]` | A list of contract addresses to monitor (as hex strings, e.g., `"0x..."`). At least one address is required. | -| `topics` | `TopicValues[]` | Optional. A fixed 4-element array to filter event topics. The first element contains event signatures, and the next three elements contain indexed argument values. An empty array element acts as a wildcard. | +| `addresses` | `string[]` | **Required.** A list of contract addresses to monitor. **Must be base64 encoded** using `hexToBase64()`. At least one address is required. | +| `topics` | `TopicValues[]` | **Required.** An array to filter event topics. The first element must contain at least one event signature. The next three elements can contain indexed argument values (optional). An empty array element acts as a wildcard for indexed arguments. **All topic values must be base64 encoded** using `hexToBase64()`. | | `confidence` | `string` | Optional. The block confirmation level to monitor. Can be: <ul><li>**`"CONFIDENCE_LEVEL_LATEST"`**: The most recent block (fastest but least secure).</li><li>**`"CONFIDENCE_LEVEL_SAFE"` (default)**: A block unlikely to be reorged but not yet irreversible.</li><li>**`"CONFIDENCE_LEVEL_FINALIZED"`**: A block considered irreversible (safest, but requires waiting longer for finality).</li></ul> | - -<Aside type="caution" title="SAFE block tag fallback"> - **Some chains do not support the SAFE block tag** (e.g., Shibarium). When you specify `"CONFIDENCE_LEVEL_SAFE"` on chains that don't support it, CRE automatically falls back to `"CONFIDENCE_LEVEL_FINALIZED"` for safety. Users are responsible for knowing which chains support the SAFE tag. If you need consistent behavior across all chains, explicitly use `"CONFIDENCE_LEVEL_FINALIZED"` or `"CONFIDENCE_LEVEL_LATEST"`. +<Aside type="note" title="Finality details"> + For details on how each confidence level maps to specific chains and estimated wait times, see [Finality and + Confidence Levels](/cre/concepts/finality). </Aside> ### `TopicValues` The `topics` array uses a special format for filtering events: -| Field | Type | Description | -| -------- | ---------- | --------------------------------------------------- | -| `values` | `string[]` | Array of possible values for a topic (hex strings). | +| Field | Type | Description | +| -------- | ---------- | --------------------------------------------------------------------------------------- | +| `values` | `string[]` | Array of possible values for a topic. **Must be base64 encoded** using `hexToBase64()`. | **Topic array structure:** @@ -14039,19 +16189,36 @@ The `topics` array uses a special format for filtering events: - **`topics[2]`**: Optional. Values for the second indexed argument. Can be empty (wildcard). - **`topics[3]`**: Optional. Values for the third indexed argument. Can be empty (wildcard). +<Aside type="caution" title="Topic values must be padded to 32 bytes and base64 encoded"> + EVM logs always store indexed parameters as **32-byte values**. When filtering on topics 1, 2, or 3: + + 1. **Pad your values to 32 bytes** using `padHex(value, { size: 32 })` from viem (e.g., addresses are 20 bytes and must be padded) + 2. **Convert to base64** using `hexToBase64()` from the CRE SDK + + If you don't pad correctly, your filter won't match the actual log topics and the trigger will not fire. + + Topic 0 (the event signature from `keccak256`) is already 32 bytes and doesn't need padding. +</Aside> + **Example:** ```typescript +import { hexToBase64 } from "@chainlink/cre-sdk" +import { keccak256, toBytes, padHex } from "viem" + +const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) +const fromAddress = "0xabcdef..." as `0x${string}` + const trigger = evmClient.logTrigger({ - addresses: ["0x1234567890abcdef..."], + addresses: [hexToBase64("0x1234567890abcdef...")], topics: [ - // Topic 0: Event signature (Transfer event) + // Topic 0: Event signature (Transfer event) - already 32 bytes { - values: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"], + values: [hexToBase64(transferEventHash)], }, - // Topic 1: From address (indexed parameter 1) + // Topic 1: From address (indexed parameter 1) - must pad from 20 to 32 bytes { - values: ["0x000000000000000000000000abcdef..."], + values: [hexToBase64(padHex(fromAddress, { size: 32 }))], }, // Topic 2: Empty (wildcard for any "to" address) { @@ -14158,7 +16325,16 @@ const onLogTrigger = (runtime: Runtime<Config>, log: EVMLog): string => { ## Complete Example ```typescript -import { cre, bytesToHex, getNetwork, Runner, type Runtime, type EVMLog } from "@chainlink/cre-sdk" +import { + EVMClient, + handler, + bytesToHex, + getNetwork, + Runner, + hexToBase64, + type Runtime, + type EVMLog, +} from "@chainlink/cre-sdk" type Config = { chainSelectorName: string @@ -14193,12 +16369,12 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], }), onLogTrigger ), @@ -14209,8 +16385,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Decoding Log Data @@ -14237,27 +16411,20 @@ const onLogTrigger = (runtime: Runtime<Config>, log: EVMLog): string => { } ``` -<Aside type="note" title="Using contract ABIs"> - For type-safe event handling, organize your contract ABIs in separate TypeScript files (e.g., - `contracts/abi/MyContract.ts`) as demonstrated in the [demo - workflow](https://github.com/smartcontractkit/cre-cli/tree/main/examples/proof-of-reserve). Define ABIs as `const` - arrays with full JSON ABI structures for optimal TypeScript type inference with viem. -</Aside> - --- # SDK Reference: HTTP Trigger Source: https://docs.chain.link/cre/reference/sdk/triggers/http-trigger-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 The HTTP Trigger fires when an HTTP request is made to the workflow's designated endpoint. This allows you to start workflows from external systems. ## Creating the trigger ```typescript -import { cre } from "@chainlink/cre-sdk" +import { HTTPCapability } from "@chainlink/cre-sdk" -const http = new cre.capabilities.HTTPCapability() +const http = new HTTPCapability() // Basic trigger (no authorization) const trigger = http.trigger({}) @@ -14392,7 +16559,7 @@ const onHttpTrigger = (runtime: Runtime<Config>, payload: HTTPPayload): string = ## Complete Example ```typescript -import { cre, decodeJson, Runner, type Runtime, type HTTPPayload } from "@chainlink/cre-sdk" +import { HTTPCapability, handler, decodeJson, Runner, type Runtime, type HTTPPayload } from "@chainlink/cre-sdk" type Config = { publicKey: string @@ -14410,10 +16577,10 @@ const onHttpTrigger = (runtime: Runtime<Config>, payload: HTTPPayload): string = } const initWorkflow = (config: Config) => { - const http = new cre.capabilities.HTTPCapability() + const http = new HTTPCapability() return [ - cre.handler( + handler( http.trigger({ authorizedKeys: [ { @@ -14431,8 +16598,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Testing HTTP Triggers @@ -14463,9 +16628,62 @@ This section provides a reference for the built-in trigger capabilities of the C --- +# Supported Networks +Source: https://docs.chain.link/cre/supported-networks-ts +Last Updated: 2026-02-03 + +This page lists all EVM-compatible networks supported by CRE workflows, along with the minimum CLI and SDK versions required for each network. + +## Version Requirements + +Network support depends on your CLI and SDK versions. The tables below show the minimum versions required for each network. + +- **New projects:** Run `cre update` to get the latest CLI, which includes compatible SDK versions. +- **Existing projects:** You may need to update your SDK dependency. See [Updating Dependencies](/cre/reference/project-configuration-ts#5-updating-dependencies) for instructions. + +## Mainnets + +| Network | CLI | Go SDK | TS SDK | +| ------------ | ------ | ------ | ------ | +| Arbitrum One | v1.0.0 | v1.0.0 | v1.0.1 | +| Avalanche | v1.0.0 | v1.0.0 | v1.0.1 | +| Base | v1.0.0 | v1.0.0 | v1.0.1 | +| BNB Chain | v1.0.0 | v1.0.0 | v1.0.1 | +| Ethereum | v1.0.0 | v1.0.0 | v1.0.1 | +| OP Mainnet | v1.0.0 | v1.0.0 | v1.0.1 | +| Polygon | v1.0.0 | v1.0.0 | v1.0.1 | +| ZKSync Era | v1.0.6 | v1.1.3 | v1.0.7 | + +## Testnets + +| Network | CLI | Go SDK | TS SDK | +| ------------------- | ------ | ------ | ------ | +| Apechain Curtis | v1.0.7 | v1.1.4 | v1.0.7 | +| Arc Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Arbitrum Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Avalanche Fuji | v1.0.0 | v1.0.0 | v1.0.1 | +| Base Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| BNB Chain Testnet | v1.0.0 | v1.0.0 | v1.0.1 | +| Ethereum Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Hyperliquid Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Ink Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| Jovay Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Linea Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| OP Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Plasma Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Polygon Amoy | v1.0.0 | v1.0.0 | v1.0.1 | +| World Chain Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| ZKSync Era Sepolia | v1.0.6 | v1.1.2 | v1.0.7 | + +## Forwarder Addresses + +For forwarder contract addresses and chain names, see the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). Forwarder addresses are used when building consumer contracts that receive workflow reports onchain. Learn more about [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview). + +--- + # Running a Demo Workflow Source: https://docs.chain.link/cre/templates/running-demo-workflow-ts -Last Updated: 2025-11-04 +Last Updated: 2026-01-20 This guide walks you through the core developer loop of CRE: initializing a project from a template and running it locally using the [simulator](/cre/guides/operations/simulating-workflows). By the end, you will have run the Custom Data Feed demo workflow and tested its two distinct behaviors: a **proactive** path where it fetches data from an API to write a result onchain, and a **reactive** path where it listens for onchain events to trigger new actions. @@ -14482,7 +16700,7 @@ Before you begin, ensure you have the necessary tools installed: - **CRE CLI**: You must have the CRE CLI installed. See [Install the CLI](/cre/getting-started/cli-installation) for instructions. - **CRE account & authentication**: You must have a CRE account and be logged in with the CLI. Run cre whoami in your terminal to verify you're logged in, or run cre login to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging in with the CLI](/cre/account/cli-login) for instructions. -- **Bun**: You must have Bun version 1.2.21 or higher installed. Check your version with bun --version. See [Install Bun](https://bun.sh/docs/installation) for instructions. +- **Bun**: You must have Bun version 1.2.21 or higher installed. Check your version with bun --version. See [Install Bun](https://bun.com/docs/installation) for instructions. - **Sepolia Testnet Account**: You need a private key for an account funded with Sepolia ETH. This is required because the demo workflow performs a write transaction. Go to <a href="https://faucets.chain.link" target="blank">faucets.chain.link</a> to get some Sepolia ETH. ## 2. Initialize the demo project @@ -14578,7 +16796,7 @@ Now you are ready to compile and run the workflow. The single `main.ts` file you <Aside type="note" title="Onchain Writes are Dry Runs by Default"> The `--broadcast` flag is included here because this workflow performs an onchain write. By default, the `simulate` command performs a dry run and will not broadcast the transaction without this flag. For more details, see the `cre - workflow simulate` [reference](/cre/reference/cli#cre-workflow-simulate). + workflow simulate` [reference](/cre/reference/cli/workflow#cre-workflow-simulate). </Aside> You will first see a `Workflow compiled` message, followed by the trigger selection menu. @@ -14724,7 +16942,7 @@ The `main.ts` file is a great example of how a single workflow can contain multi - **`main()` and `Runner`**: The entry point of the workflow. It creates a new `Runner` instance with your config schema using `Runner.newRunner()`, then calls `runner.run()` with the `initWorkflow` function. This is the standard pattern for initializing CRE workflows in the TypeScript SDK. -- **`initWorkflow`**: This function initializes the trigger capabilities and returns an array of two handlers: one for the cron trigger and one for the EVM log trigger. Each handler is created using `cre.handler()`, which pairs a trigger configuration with a callback function. +- **`initWorkflow`**: This function initializes the trigger capabilities and returns an array of two handlers: one for the cron trigger and one for the EVM log trigger. Each handler is created using `handler()`, which pairs a trigger configuration with a callback function. - **`onCronTrigger`**: The entry point for **Path A**. It's a lightweight callback that immediately delegates to the shared `doPOR` function, demonstrating how you can reuse core logic. @@ -14740,7 +16958,7 @@ This demo showcases several important patterns and features of the TypeScript SD - **Runner Pattern**: The workflow uses the `Runner.newRunner()` pattern to initialize the workflow with a config schema and run it. - **Zod Schema Validation**: The workflow uses Zod to define and validate the configuration schema, ensuring type safety at runtime. -- **Multiple Trigger Handlers**: A single workflow can register multiple handlers for different trigger types using `cre.handler()`. +- **Multiple Trigger Handlers**: A single workflow can register multiple handlers for different trigger types using `handler()`. - **Viem Integration**: All EVM interactions use viem's `encodeFunctionData` and `decodeFunctionResult` for type-safe contract calls. - **Manual ABI Management**: TypeScript workflows use manually defined ABI constants from the `contracts/abi/` directory. - **Consensus Aggregation**: The HTTP capability uses `ConsensusAggregationByFields` to aggregate offchain data from multiple nodes. diff --git a/src/content/cre/organization/linking-keys.mdx b/src/content/cre/organization/linking-keys.mdx index 213045c1307..cf1bd48b878 100644 --- a/src/content/cre/organization/linking-keys.mdx +++ b/src/content/cre/organization/linking-keys.mdx @@ -221,6 +221,95 @@ To unlink a key: The CLI will submit an onchain transaction to remove the address from the Workflow Registry. After the transaction is confirmed, the address and all its associated workflows will be deleted. +## Unlinking a key without the original private key + +If you need to unlink a key but no longer have access to the original private key (for example, the key owner left your organization), you can still complete the unlinking process using a different wallet. + +{/* prettier-ignore */} +<Aside type="caution" title="Destructive operation"> + **Unlinking a key will permanently delete all workflows registered under that address.** This action cannot be undone. Make sure you want to permanently remove all associated workflows before proceeding. +</Aside> + +### How it works + +When you run `cre account unlink-key --unsigned` while logged into your CRE organization, the CLI generates: + +1. An authorization signature proving you have permission to unlink the key (through your CRE organization membership) +1. Raw transaction data that any funded wallet can submit to the blockchain + +{/* prettier-ignore */} +<Aside type="note" title="Security"> + The authorization is tied to the **organization**, not to the individual who originally linked the key. Any authenticated member of the CRE organization can generate valid unlink authorization for keys linked to that organization. +</Aside> + +### Prerequisites + +- **Logged in to CRE CLI**: You must be authenticated as a member of the CRE organization that owns the key +- **`workflow-owner-address` configured**: Set this in your `project.yaml` to the address you want to unlink +- **A funded wallet**: Any wallet with ETH on Ethereum Mainnet to submit the transaction and pay gas fees + +### Steps + +1. **Configure your `project.yaml`** with the address you want to unlink: + + ```yaml + production-settings: + account: + workflow-owner-address: "<address_to_unlink>" + # ... other settings + ``` + +1. **Generate the unsigned transaction**: + + ```bash + cre account unlink-key --unsigned --target production-settings + ``` + + **Example output:** + + ```bash + Unlinking web3 key from your CRE organization + Target : production-settings + ✔ Using Address : 0x.... + + Starting unlinking: owner=0x.... + ✔ Yes + Contract address validation passed + --unsigned flag detected: transaction not sent on-chain. + Generating call data for offline signing and submission in your preferred tool: + + Ownership unlinking initialized successfully! + + Next steps: + + 1. Submit the following transaction on the target chain: + + Chain: ethereum-mainnet + Contract Address: 0x4Ac54353FA4Fa961AfcC5ec4B118596d3305E7e5 + + 2. Use the following transaction data: + + 39d68c6a000000000000000000... + + Unlinked successfully + ``` + +1. **Submit the transaction** using any wallet that supports sending transactions with custom data. + + {/* prettier-ignore */} + <Aside type="caution" title="Destructive operation"> + **Unlinking a key will permanently delete all workflows registered under that address.** This action cannot be undone. Make sure you want to permanently remove all associated workflows before proceeding. + </Aside> + + Here's an example using MetaMask: + 1. In MetaMask, go to **Settings → Advanced** and enable **"Show hex data"** + 1. Click **Send** and enter the contract address as the recipient <CopyText text="0x4Ac54353FA4Fa961AfcC5ec4B118596d3305E7e5" code /> + 1. Set the amount to **0 ETH** + 1. Paste the transaction data in the **Hex data** field (add `0x` prefix) + 1. Review and confirm the transaction + + The unlink operation completes once the transaction is confirmed onchain. All workflows registered under that address will be permanently deleted. + ## Non-interactive mode For automation or CI/CD pipelines, use the `--yes` flag to skip confirmation prompts: diff --git a/src/content/cre/reference/cli/index.mdx b/src/content/cre/reference/cli/index.mdx index 844c71d2e24..4cf23eff7f7 100644 --- a/src/content/cre/reference/cli/index.mdx +++ b/src/content/cre/reference/cli/index.mdx @@ -6,13 +6,13 @@ isIndex: true metadata: description: "Explore all CRE CLI commands: complete reference for project setup, workflow deployment, account management, and development tools." datePublished: "2025-11-04" - lastModified: "2025-11-20" + lastModified: "2026-02-10" --- import { Aside } from "@components" -<Aside type="note" title="Required CLI Version: v1.0.2"> - To ensure compatibility with the guides and examples in this documentation, please use version `v1.0.2` of the CRE +<Aside type="note" title="Required CLI Version: v1.0.10"> + To ensure compatibility with the guides and examples in this documentation, please use version `v1.0.10` of the CRE CLI. You can check your installed version by running `cre version`. Refer to the [CLI Installation](/cre/getting-started/cli-installation/macos-linux) guide for more information. </Aside> diff --git a/src/content/cre/reference/cli/utilities.mdx b/src/content/cre/reference/cli/utilities.mdx index 7b6ed3b64db..0b90e62e32b 100644 --- a/src/content/cre/reference/cli/utilities.mdx +++ b/src/content/cre/reference/cli/utilities.mdx @@ -5,7 +5,7 @@ title: "Utility Commands" metadata: description: "Find CLI utility commands: reference for version checking, binding generation, and helpful development tools." datePublished: "2025-11-04" - lastModified: "2025-11-20" + lastModified: "2026-02-03" --- import { Aside } from "@components" @@ -40,6 +40,11 @@ cre update The CLI automatically checks if your version is outdated when you run certain commands. If a newer version is available, you'll see a warning message encouraging you to run `cre update`. </Aside> +{/* prettier-ignore */} +<Aside type="note" title="Updating existing projects"> + Running `cre update` updates the CLI itself. For existing projects, you may also need to update your SDK dependency to access new features. See [Updating Dependencies](/cre/reference/project-configuration#updating-dependencies) for instructions. +</Aside> + ## `cre version` Prints the current version of the CRE CLI. @@ -53,12 +58,12 @@ cre version **Example output:** ```bash -cre version v1.0.2 +cre version v1.0.10 ``` {/* prettier-ignore */} <Aside type="note" title="Version compatibility"> - Always check that your CLI version matches the version recommended in the documentation. The current recommended version is **v1.0.2**. See the [CLI Installation guide](/cre/getting-started/cli-installation) for more information. + Always check that your CLI version matches the version recommended in the documentation. The current recommended version is **v1.0.10**. See the [CLI Installation guide](/cre/getting-started/cli-installation) for more information. </Aside> ## Learn more diff --git a/src/content/cre/reference/cli/workflow.mdx b/src/content/cre/reference/cli/workflow.mdx index 8129ef0f319..94fa9ce86ab 100644 --- a/src/content/cre/reference/cli/workflow.mdx +++ b/src/content/cre/reference/cli/workflow.mdx @@ -34,15 +34,15 @@ cre workflow simulate <workflow-name-or-path> [flags] **Flags:** -| <div style={{ width: "200px" }}>Flag</div> | Description | -| ------------------------------------------ | -------------------------------------------------------------------------------------------------- | -| `--broadcast` | Broadcast onchain write transactions (default: `false`). Without this flag, a dry run is performed | -| `-g, --engine-logs` | Enable non-fatal engine logging | -| `--non-interactive` | Run without prompts; requires `--trigger-index` and inputs for the selected trigger type | -| `--trigger-index <int>` | Index of the trigger to run (0-based). Required when using `--non-interactive` | -| `--http-payload <string>` | HTTP trigger payload as JSON string or path to JSON file (with or without `@` prefix) | -| `--evm-tx-hash <string>` | EVM trigger transaction hash (`0x...`). For EVM log triggers | -| `--evm-event-index <int>` | EVM trigger log index (0-based). For EVM log triggers | +| <div style={{ width: "200px" }}>Flag</div> | Description | +| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--broadcast` | Broadcast onchain write transactions (default: `false`). Without this flag, a dry run is performed | +| `-g, --engine-logs` | Enable non-fatal engine logging | +| `--non-interactive` | Run without prompts; requires `--trigger-index` (see the line below) and inputs for the selected trigger type | +| `--trigger-index <int>` | Selects which handler to run (0-based position). If your workflow has multiple handlers, `0` is the first, `1` is the second, etc. Required with `--non-interactive` | +| `--http-payload <string>` | HTTP trigger payload as JSON string or path to JSON file (with or without `@` prefix). For HTTP triggers only | +| `--evm-tx-hash <string>` | Transaction hash (`0x...`) containing the event that triggered your workflow. For EVM log triggers only | +| `--evm-event-index <int>` | Which log/event within the transaction to use (0-based position). If the transaction emitted multiple events, `0` is the first, `1` is the second, etc. For EVM log triggers only | **Examples:** @@ -58,6 +58,21 @@ cre workflow simulate <workflow-name-or-path> [flags] cre workflow simulate ./my-workflow --broadcast --target local-simulation ``` +- Non-interactive mode with HTTP trigger + + ```bash + # If your HTTP trigger handler is the first handler in your workflow, use --trigger-index 0 + cre workflow simulate my-workflow --non-interactive --trigger-index 0 --http-payload '{"key":"value"}' --target staging-settings + ``` + +- Non-interactive mode with EVM log trigger + + ```bash + # If your EVM log trigger handler is the second handler in your workflow, use --trigger-index 1 + # --evm-event-index 0 means you want the first event from that transaction + cre workflow simulate my-workflow --non-interactive --trigger-index 1 --evm-tx-hash 0x420721d7d00130a03c5b525b2dbfd42550906ddb3075e8377f9bb5d1a5992f8e --evm-event-index 0 --target staging-settings + ``` + {/* prettier-ignore */} <Aside type="note" title="Dry run by default"> By default, `cre workflow simulate` performs a **dry run** for onchain write operations. It simulates the transaction to confirm it would succeed, but does not broadcast it to the network. This results in a successful log with an empty transaction hash (`0x`). To send a real transaction, use the `--broadcast` flag. diff --git a/src/content/cre/reference/project-configuration-go.mdx b/src/content/cre/reference/project-configuration-go.mdx index 9b77dc2141f..fe8e8197422 100644 --- a/src/content/cre/reference/project-configuration-go.mdx +++ b/src/content/cre/reference/project-configuration-go.mdx @@ -7,7 +7,7 @@ date: Last Modified metadata: description: "Configure your Go project: learn to manage project.yaml, workflow.yaml, and targets for different environments." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { ClickToZoom, Aside } from "@components" @@ -94,9 +94,9 @@ production-settings: ``` <Aside type="note" title="Available chain names"> - For a complete list of supported networks and their chain names, see [Supported - Networks](/cre/guides/workflow/using-evm-client/supported-networks). For details on using chain selectors in your - workflow code, see [Chain Selectors](/cre/reference/sdk/evm-client-go#chain-selectors). + For a complete list of supported networks and their chain names, see [Supported Networks](/cre/supported-networks). + For details on using chain selectors in your workflow code, see [Chain + Selectors](/cre/reference/sdk/evm-client-go#chain-selectors). </Aside> #### Configuration fields @@ -231,3 +231,34 @@ When you run a CLI command with a target, e.g., `--target staging-settings`: If your workflow directory contains a `workflow.yaml`, the target you specify must exist in both `project.yaml` and `workflow.yaml`. A mismatch causes the CLI to abort with a clear error message. </Aside> + +## 5. Updating dependencies + +When new networks or SDK features are released, you may need to update your project dependencies. + +### Updating the CLI + +Run [cre update](/cre/reference/cli/utilities#cre-update) to download and install the latest CLI version: + +```bash +cre update +``` + +New projects created with an updated CLI automatically use compatible SDK versions. + +### Updating the SDK (existing projects) + +If you created your project with an older CLI version, update the SDK in your `go.mod`: + +```bash +go get github.com/smartcontractkit/cre-sdk-go@v1.1.4 +``` + +Then run `go mod tidy` to clean up dependencies. + +### Checking your versions + +- **CLI version:** Run `cre version` +- **SDK version:** Check `go.mod` for the `cre-sdk-go` dependency version + +For a list of which versions support which networks, see [Supported Networks](/cre/supported-networks). diff --git a/src/content/cre/reference/project-configuration-ts.mdx b/src/content/cre/reference/project-configuration-ts.mdx index ec8f344e95e..d8b4f2ffacb 100644 --- a/src/content/cre/reference/project-configuration-ts.mdx +++ b/src/content/cre/reference/project-configuration-ts.mdx @@ -7,7 +7,7 @@ date: Last Modified metadata: description: "Configure your TypeScript project: learn to manage project.yaml, workflow.yaml, and targets for different environments." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { ClickToZoom, Aside } from "@components" @@ -99,9 +99,9 @@ production-settings: ``` <Aside type="note" title="Available chain names"> - For a complete list of supported networks and their chain names, see [Supported - Networks](/cre/guides/workflow/using-evm-client/supported-networks). For details on using chain selectors in your - workflow code, see [Chain Selectors](/cre/reference/sdk/evm-client-ts#chain-selectors). + For a complete list of supported networks and their chain names, see [Supported Networks](/cre/supported-networks). + For details on using chain selectors in your workflow code, see [Chain + Selectors](/cre/reference/sdk/evm-client-ts#chain-selectors). </Aside> #### Configuration fields @@ -241,3 +241,38 @@ When you run a CLI command with a target, e.g., `--target staging-settings`: If your workflow directory contains a `workflow.yaml`, the target you specify must exist in both `project.yaml` and `workflow.yaml`. A mismatch causes the CLI to abort with a clear error message. </Aside> + +## 5. Updating dependencies + +When new networks or SDK features are released, you may need to update your project dependencies. + +### Updating the CLI + +Run [cre update](/cre/reference/cli/utilities#cre-update) to download and install the latest CLI version: + +```bash +cre update +``` + +New projects created with an updated CLI automatically use compatible SDK versions. + +### Updating the SDK (existing projects) + +If you created your project with an older CLI version, update the `@chainlink/cre-sdk` dependency in your workflow's `package.json`: + +```json +{ + "dependencies": { + "@chainlink/cre-sdk": "^1.0.7" + } +} +``` + +Then run `bun install` from your workflow directory to update `bun.lock`. + +### Checking your versions + +- **CLI version:** Run `cre version` +- **SDK version:** Check `package.json` or `bun.lock` in your workflow directory + +For a list of which versions support which networks, see [Supported Networks](/cre/supported-networks). diff --git a/src/content/cre/reference/sdk/confidential-http-client-go.mdx b/src/content/cre/reference/sdk/confidential-http-client-go.mdx new file mode 100644 index 00000000000..1142cf808a6 --- /dev/null +++ b/src/content/cre/reference/sdk/confidential-http-client-go.mdx @@ -0,0 +1,284 @@ +--- +section: cre +title: "SDK Reference: Confidential HTTP Client" +date: Last Modified +sdkLang: "go" +pageId: "reference-sdk-confidential-http-client" +metadata: + description: "Reference for Go Confidential HTTP Client: complete API for privacy-preserving requests with enclave execution, secret injection, and response encryption." + datePublished: "2026-02-10" + lastModified: "2026-02-10" +--- + +import { Aside } from "@components" + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The [Confidential HTTP](/cre/capabilities/confidential-http-go) Client lets you make privacy-preserving requests to external APIs from your workflow. Unlike the regular [`http.Client`](/cre/reference/sdk/http-client), the request executes inside a secure enclave, secrets are injected via templates, and responses can be optionally encrypted. + +- For use cases and a conceptual overview, see [The Confidential HTTP Capability](/cre/capabilities/confidential-http-go) +- **Guide:** [Making Confidential Requests](/cre/guides/workflow/using-confidential-http-client/making-requests-go) + +## Quick reference + +| Method | Description | +| -------------------------------------------------------------- | ---------------------------------------------------------- | +| [`confidentialhttp.SendRequest`](#confidentialhttpsendrequest) | High-level helper with automatic `RunInNodeMode` wrapping | +| [`client.SendRequest`](#clientsendrequest) | Low-level method requiring manual `RunInNodeMode` wrapping | + +## Core types + +### `confidentialhttp.ConfidentialHTTPRequest` + +The top-level request type that combines an HTTP request with Vault DON secrets and encryption settings. + +| <div style="width: 140px;">Field</div> | <div style="width: 200px;">Type</div> | Description | +| -------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `Request` | `*HTTPRequest` | The HTTP request to execute inside the enclave. See [`HTTPRequest`](#confidentialhttphttprequest). | +| `VaultDonSecrets` | `[]*SecretIdentifier` | List of secrets to fetch from the Vault DON and make available in the enclave. See [`SecretIdentifier`](#confidentialhttpsecretidentifier). | +| `EncryptOutput` | `bool` | If `true`, encrypts the response body before it leaves the enclave. See [Response encryption](#response-encryption). Default: `false`. | + +### `confidentialhttp.HTTPRequest` + +Defines the HTTP request that will be executed inside the enclave. + +| <div style="width: 150px;">Field</div> | <div style="width: 250px;">Type</div> | Description | +| -------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| `Url` | `string` | The URL of the API endpoint. | +| `Method` | `string` | The HTTP method (e.g., `"GET"`, `"POST"`). | +| `Body` | `isHTTPRequest_Body` | The request body. Use `HTTPRequest_BodyString` for string templates or `HTTPRequest_BodyBytes` for raw bytes. | +| `MultiHeaders` | `map[string]*HeaderValues` | Request headers. Supports multiple values per key and template syntax for secret injection. | +| `TemplatePublicValues` | `map[string]string` | Public (non-secret) values used to fill template placeholders in the body and headers. | +| `CustomRootCaCertPem` | `[]byte` | Optional custom root CA certificate (PEM format) for verifying the external server's TLS certificate. | +| `Timeout` | `*durationpb.Duration` | Optional request timeout. | + +#### Setting the request body + +The `Body` field is a `oneof` type with two options: + +**String template (recommended for secret injection):** + +```go +Body: &confidentialhttp.HTTPRequest_BodyString{ + BodyString: `{"auth": "{{.myApiKey}}", "action": "getData"}`, +}, +``` + +**Raw bytes:** + +```go +Body: &confidentialhttp.HTTPRequest_BodyBytes{ + BodyBytes: []byte(`{"action": "getData"}`), +}, +``` + +### `confidentialhttp.HTTPResponse` + +The response returned from the enclave after the HTTP request completes. + +| Field | Type | Description | +| -------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `StatusCode` | `uint32` | The HTTP status code. | +| `Body` | `[]byte` | The response body. If `EncryptOutput` is `true`, this contains the encrypted body (see [Response encryption](#response-encryption)). | +| `MultiHeaders` | `map[string]*HeaderValues` | The HTTP response headers. | + +### `confidentialhttp.SecretIdentifier` + +Identifies a secret stored in the Vault DON. + +| Field | Type | Description | +| ----------- | --------- | ----------------------------------------------------------------------------------------------------------------- | +| `Key` | `string` | The logical name of the secret. Must match the template placeholder (e.g., `"myApiKey"` matches `{{.myApiKey}}`). | +| `Namespace` | `string` | The secret namespace. | +| `Owner` | `*string` | Optional. The owner address for the secret. | + +### `confidentialhttp.HeaderValues` + +Represents multiple values for a single HTTP header key. + +| Field | Type | Description | +| -------- | ---------- | ------------------------------------------------------------------------------------------------ | +| `Values` | `[]string` | The header values. Supports template syntax for secret injection (e.g., `"Basic {{.myToken}}"`). | + +## Making requests + +### `confidentialhttp.SendRequest` + +The high-level helper function for making confidential HTTP requests. Automatically handles the `cre.RunInNodeMode` pattern. + +**Signature:** + +```go +func SendRequest[C, T any]( + config C, + runtime cre.Runtime, + client *Client, + fn func(config C, logger *slog.Logger, sendRequester *SendRequester) (T, error), + ca cre.ConsensusAggregation[T], +) cre.Promise[T] +``` + +**Parameters:** + +- `config`: Your workflow's configuration struct, passed to `fn`. +- `runtime`: The top-level `cre.Runtime` from your trigger callback. +- `client`: An initialized `*confidentialhttp.Client`. +- `fn`: Your request logic function that receives `config`, `logger`, and `sendRequester`. +- `ca`: The [consensus aggregation method](/cre/reference/sdk/consensus). + +**Example:** + +```go +func fetchData(config *Config, logger *slog.Logger, sendRequester *confidentialhttp.SendRequester) (*Result, error) { + resp, err := sendRequester.SendRequest(&confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "GET", + MultiHeaders: map[string]*confidentialhttp.HeaderValues{ + "Authorization": {Values: []string{"Basic {{.apiKey}}"}}, + }, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "apiKey"}, + }, + }).Await() + if err != nil { + return nil, err + } + // Parse resp.Body... + return &Result{}, nil +} + +// In your trigger callback +client := &confidentialhttp.Client{} +result, err := confidentialhttp.SendRequest(config, runtime, client, + fetchData, + cre.ConsensusIdenticalAggregation[*Result](), +).Await() +``` + +### `client.SendRequest` + +The lower-level method for making confidential HTTP requests. Must be manually wrapped in `cre.RunInNodeMode`. + +**Signature:** + +```go +func (c *Client) SendRequest(runtime cre.NodeRuntime, input *ConfidentialHTTPRequest) cre.Promise[*HTTPResponse] +``` + +**Parameters:** + +- `runtime`: A `cre.NodeRuntime` provided by `cre.RunInNodeMode`. +- `input`: A `*ConfidentialHTTPRequest` containing the request, secrets, and encryption settings. + +**Returns:** + +- `cre.Promise[*HTTPResponse]` + +**Example:** + +```go +result, err := cre.RunInNodeMode(config, runtime, + func(config Config, nodeRuntime cre.NodeRuntime) (Result, error) { + client := confidentialhttp.Client{} + resp, err := client.SendRequest(nodeRuntime, &confidentialhttp.ConfidentialHTTPRequest{ + Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"auth": "{{.apiKey}}"}`}, + MultiHeaders: map[string]*confidentialhttp.HeaderValues{ + "Content-Type": {Values: []string{"application/json"}}, + }, + }, + VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "apiKey"}, + }, + }).Await() + if err != nil { + return Result{}, err + } + // Parse and return... + return Result{}, nil + }, + cre.ConsensusIdenticalAggregation[Result](), +).Await() +``` + +**Guide:** [Making Confidential Requests](/cre/guides/workflow/using-confidential-http-client/making-requests-go) + +## Template syntax + +Secrets are injected into the request body and headers using Go template syntax: `{{.secretName}}`. The placeholder name must match the `Key` field in the corresponding `SecretIdentifier`. + +**Body template:** + +```go +Body: &confidentialhttp.HTTPRequest_BodyString{ + BodyString: `{"apiKey": "{{.myApiKey}}", "method": "{{.method}}", "params": []}`, +}, +``` + +**Header template:** + +```go +MultiHeaders: map[string]*confidentialhttp.HeaderValues{ + "Authorization": {Values: []string{"Basic {{.myCredential}}"}}, +}, +``` + +### `TemplatePublicValues` (optional) + +Every `{{.placeholder}}` in your body or headers is resolved inside the enclave. By default, placeholders are filled with **secrets** from `VaultDonSecrets`. But sometimes you have a placeholder value that isn't secret — for example, an RPC method name or a public parameter. That's what `TemplatePublicValues` is for: it lets you inject **non-secret** values into the same template. + +This is purely a convenience. You could always hardcode the value directly in the body string instead: + +```go +// These two are equivalent: + +// Option 1: hardcoded in the body string +Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"method": "eth_blockNumber", "auth": "{{.apiKey}}"}`} + +// Option 2: using TemplatePublicValues +Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"method": "{{.method}}", "auth": "{{.apiKey}}"}`} +TemplatePublicValues: map[string]string{"method": "eth_blockNumber"} +``` + +`TemplatePublicValues` is useful when you want to keep the template generic and pass in dynamic values (e.g., from config) without string concatenation. + +**Example with both secret and public values:** + +```go +Request: &confidentialhttp.HTTPRequest{ + Url: config.URL, + Method: "POST", + Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"method": "{{.rpcMethod}}", "auth": "{{.apiKey}}"}`}, + TemplatePublicValues: map[string]string{ + "rpcMethod": config.RPCMethod, // dynamic value from config, not a secret + }, +}, +VaultDonSecrets: []*confidentialhttp.SecretIdentifier{ + {Key: "apiKey"}, // secret, from Vault DON +}, +``` + +In this example, `{{.rpcMethod}}` is resolved from `TemplatePublicValues` (a dynamic, non-secret value from your workflow config) and `{{.apiKey}}` is resolved from the Vault DON (a secret). Both are resolved inside the enclave. + +## Response encryption + +The `EncryptOutput` field controls whether the response body is encrypted before leaving the enclave. + +| `EncryptOutput` | Secret key provided | Behavior | +| ----------------- | -------------------------------------------------------- | ------------------------------------------------------------- | +| `false` (default) | — | Response returned unencrypted. | +| `true` | `san_marino_aes_gcm_encryption_key` in `VaultDonSecrets` | Response AES-GCM encrypted with your symmetric key. | +| `true` | No key provided | Response TDH2 encrypted with the Vault DON master public key. | + +**AES-GCM encryption** is the recommended approach. Store a 256-bit (32-byte) AES key as a Vault DON secret with the identifier `san_marino_aes_gcm_encryption_key`, then decrypt the response in your own secure backend. + +The encrypted response body is structured as `nonce || ciphertext || tag`. + +For a complete decryption example, see the [Making Confidential Requests guide](/cre/guides/workflow/using-confidential-http-client/making-requests-go#response-encryption). diff --git a/src/content/cre/reference/sdk/confidential-http-client-ts.mdx b/src/content/cre/reference/sdk/confidential-http-client-ts.mdx new file mode 100644 index 00000000000..c9b4fae9165 --- /dev/null +++ b/src/content/cre/reference/sdk/confidential-http-client-ts.mdx @@ -0,0 +1,321 @@ +--- +section: cre +title: "SDK Reference: Confidential HTTP Client" +date: Last Modified +sdkLang: "ts" +pageId: "reference-sdk-confidential-http-client" +metadata: + description: "Reference for TypeScript Confidential HTTP Client: complete API for privacy-preserving requests with enclave execution, secret injection, and response encryption." + datePublished: "2026-02-10" + lastModified: "2026-02-10" +--- + +import { Aside } from "@components" + +<Aside type="caution" title="Experimental — Simulation only"> + Confidential HTTP is an **experimental** capability available for `cre workflow simulate` only. It cannot be used with + `cre workflow deploy` at this time. +</Aside> + +The [Confidential HTTP](/cre/capabilities/confidential-http-ts) Client lets you make privacy-preserving requests to external APIs from your workflow. Unlike the regular [`HTTPClient`](/cre/reference/sdk/http-client), the request executes inside a secure enclave, secrets are injected via templates, and responses can be optionally encrypted. + +- For use cases and a conceptual overview, see [The Confidential HTTP Capability](/cre/capabilities/confidential-http-ts) +- **Guide:** [Making Confidential Requests](/cre/guides/workflow/using-confidential-http-client/making-requests-ts) + +## Quick reference + +| Method | Description | +| --------------------------------------------------- | -------------------------------------------------------------------------------------- | +| [`sendRequest` (high-level)](#sendrequest) | **Recommended.** Makes a confidential HTTP request with built-in consensus and typing. | +| [`sendRequest` (low-level)](#low-level-sendrequest) | Makes a confidential HTTP request manually inside a `runInNodeMode` block. | + +## Core types + +{/* prettier-ignore */} +<Aside type="note" title="Runtime types vs JSON types"> + Each core type has a corresponding `Json` variant (e.g., `ConfidentialHTTPRequest` and `ConfidentialHTTPRequestJson`). The `Json` variant is the plain JSON-serializable form of the protobuf message. Both forms are accepted wherever a type is required. +</Aside> + +### `ConfidentialHTTPRequest` / `ConfidentialHTTPRequestJson` + +The top-level request type that combines an HTTP request with Vault DON secrets and encryption settings. + +| <div style="width: 140px;">Field</div> | <div style="width: 230px;">Type</div> | Description | +| -------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `request` | `HTTPRequest` \| `HTTPRequestJson` | The HTTP request to execute inside the enclave. See [`HTTPRequest`](#httprequest--httprequestjson). | +| `vaultDonSecrets` | `SecretIdentifier[]` \| `SecretIdentifierJson[]` | List of secrets to fetch from the Vault DON and make available in the enclave. See [`SecretIdentifier`](#secretidentifier--secretidentifierjson). | +| `encryptOutput` | `boolean` | If `true`, encrypts the response body before it leaves the enclave. See [Response encryption](#response-encryption). Default: `false`. | + +### `HTTPRequest` / `HTTPRequestJson` + +Defines the HTTP request that will be executed inside the enclave. + +| <div style="width: 170px;">Field</div> | <div style="width: 250px;">Type</div> | Description | +| -------------------------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| `url` | `string` | The URL of the API endpoint. | +| `method` | `string` | The HTTP method (e.g., `"GET"`, `"POST"`). | +| `bodyString` | `string` (optional) | The request body as a string template. Use this for secret injection with `{{.secretName}}` placeholders. | +| `bodyBytes` | `Uint8Array` \| `string` (optional) | The request body as raw bytes (base64-encoded in JSON format). | +| `multiHeaders` | `{ [key: string]: HeaderValues }` (optional) | Request headers. Supports multiple values per key and template syntax for secret injection. | +| `templatePublicValues` | `{ [key: string]: string }` (optional) | Public (non-secret) values used to fill template placeholders in the body and headers. | +| `customRootCaCertPem` | `Uint8Array` \| `string` (optional) | Optional custom root CA certificate (PEM format) for verifying the external server's TLS certificate. | +| `timeout` | `Duration` \| `DurationJson` (optional) | Optional request timeout (e.g., `"5s"`). | + +{/* prettier-ignore */} +<Aside type="note" title="bodyString vs bodyBytes"> + The request body is a `oneof` field. Use `bodyString` for string templates with secret injection, or `bodyBytes` for raw binary data. Only one should be provided. +</Aside> + +### `HTTPResponse` / `HTTPResponseJson` + +The response returned from the enclave after the HTTP request completes. + +| <div style="width: 130px;">Field</div> | <div style="width: 260px;">Type</div> | Description | +| -------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `statusCode` | `number` | The HTTP status code. | +| `body` | `Uint8Array` \| `string` (base64) | The response body. If `encryptOutput` is `true`, this contains the encrypted body (see [Response encryption](#response-encryption)). | +| `multiHeaders` | `{ [key: string]: HeaderValues }` | The HTTP response headers. | + +### `SecretIdentifier` / `SecretIdentifierJson` + +Identifies a secret stored in the Vault DON. + +| Field | Type | Description | +| ----------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- | +| `key` | `string` | The logical name of the secret. Must match the template placeholder (e.g., `"myApiKey"` matches `{{.myApiKey}}`). | +| `namespace` | `string` | The secret namespace. | +| `owner` | `string` (optional) | Optional. The owner address for the secret. | + +### `HeaderValues` / `HeaderValuesJson` + +Represents multiple values for a single HTTP header key. + +| <div style="width: 130px;">Field</div> | <div style="width: 130px;">Type</div> | Description | +| -------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------ | +| `values` | `string[]` | The header values. Supports template syntax for secret injection (e.g., `"Basic {{.myToken}}"`). | + +### `ConfidentialHTTPSendRequester` + +The object passed to your fetch function when using the [high-level `sendRequest`](#sendrequest) pattern. It wraps the low-level client and provides a single method: + +| Method | Description | +| ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | +| `sendRequest(input: ConfidentialHTTPRequest \| ConfidentialHTTPRequestJson): { result: () => HTTPResponse }` | Sends a confidential HTTP request and returns the response. | + +You don't create this object yourself — it is provided by the SDK when your function is called. + +## Making requests + +### `sendRequest()` + +**Recommended.** The high-level `sendRequest` method handles `runInNodeMode` wrapping and consensus for you. You provide a function that receives a `ConfidentialHTTPSendRequester` and your arguments, and the SDK takes care of the rest. + +**Signature:** + +```typescript +sendRequest<TArgs extends unknown[], TOutput>( + runtime: Runtime<unknown>, + fn: (sendRequester: ConfidentialHTTPSendRequester, ...args: TArgs) => TOutput, + consensusAggregation: ConsensusAggregation<TOutput, true>, + unwrapOptions?: UnwrapOptions<TOutput>, +): (...args: TArgs) => { result: () => TOutput } +``` + +**Parameters:** + +- `runtime`: The `Runtime` instance from your trigger handler. +- `fn`: A function that receives a `ConfidentialHTTPSendRequester` plus any additional arguments you pass. Use the `sendRequester` to make the confidential request and return the parsed result. +- `consensusAggregation`: The consensus strategy (e.g., `consensusIdenticalAggregation()`, `consensusMedianAggregation()`). +- `unwrapOptions` (optional): Advanced option for controlling how complex (non-primitive) output types are unwrapped during consensus. Not needed for most use cases. + +**Returns:** + +A curried function that accepts `...args` and returns an object with a `.result()` method. + +**Example:** + +```typescript +import { + ConfidentialHTTPClient, + consensusIdenticalAggregation, + ok, + json, + type ConfidentialHTTPSendRequester, + type Runtime, +} from "@chainlink/cre-sdk" + +type Config = { url: string; owner: string } +type APIResult = { data: string } + +// 1. Define your fetch function +const fetchData = (sendRequester: ConfidentialHTTPSendRequester, config: Config): APIResult => { + const response = sendRequester + .sendRequest({ + request: { + url: config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.apiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "apiKey", owner: config.owner }], + }) + .result() + + if (!ok(response)) { + throw new Error(`Request failed: ${response.statusCode}`) + } + + return json(response) as APIResult +} + +// 2. Call sendRequest in your trigger handler +const onCronTrigger = (runtime: Runtime<Config>): string => { + const confHTTPClient = new ConfidentialHTTPClient() + + const result = confHTTPClient + .sendRequest(runtime, fetchData, consensusIdenticalAggregation<APIResult>())(runtime.config) + .result() + + return result.data +} +``` + +### Low-level `sendRequest()` + +The low-level overload gives you direct access to the client within a `runtime.runInNodeMode()` block. For Confidential HTTP, this offers minimal practical advantages over the high-level pattern because the API call already executes as a single request inside the enclave. Use this only if you have a specific reason to manage the `runInNodeMode` wrapping manually. + +**Signature:** + +```typescript +sendRequest( + runtime: NodeRuntime<unknown>, + input: ConfidentialHTTPRequest | ConfidentialHTTPRequestJson +): { result: () => HTTPResponse } +``` + +**Parameters:** + +- `runtime`: A `NodeRuntime` instance provided by `runtime.runInNodeMode()`. +- `input`: A `ConfidentialHTTPRequest` or `ConfidentialHTTPRequestJson` object containing the request, secrets, and encryption settings. + +**Returns:** + +An object with a `.result()` method that blocks until the request completes and returns the `HTTPResponse`. + +**Example:** + +```typescript +import { + ConfidentialHTTPClient, + consensusIdenticalAggregation, + type Runtime, + type NodeRuntime, +} from "@chainlink/cre-sdk" + +type Config = { url: string } + +const fetchData = (nodeRuntime: NodeRuntime<Config>): string => { + const client = new ConfidentialHTTPClient() + + const resp = client + .sendRequest(nodeRuntime, { + request: { + url: nodeRuntime.config.url, + method: "GET", + multiHeaders: { + Authorization: { values: ["Basic {{.apiKey}}"] }, + }, + }, + vaultDonSecrets: [{ key: "apiKey" }], + encryptOutput: false, + }) + .result() + + if (resp.statusCode !== 200) { + throw new Error(`Request failed with status: ${resp.statusCode}`) + } + + const bodyText = new TextDecoder().decode(resp.body) + return bodyText +} + +// In your workflow +const onCronTrigger = (runtime: Runtime<Config>): string => { + const result = runtime.runInNodeMode(fetchData, consensusIdenticalAggregation<string>())().result() + + runtime.log(`Result: ${result}`) + return result +} +``` + +## Template syntax + +Secrets are injected into the request body and headers using Go template syntax: `{{.secretName}}`. The placeholder name must match the `key` field in the corresponding `SecretIdentifier`. + +**Body template:** + +```typescript +bodyString: '{"apiKey": "{{.myApiKey}}", "method": "{{.method}}", "params": []}', +``` + +**Header template:** + +```typescript +multiHeaders: { + "Authorization": { values: ["Basic {{.myCredential}}"] }, +}, +``` + +### `templatePublicValues` (optional) + +Every `{{.placeholder}}` in your body or headers is resolved inside the enclave. By default, placeholders are filled with **secrets** from `vaultDonSecrets`. But sometimes you have a placeholder value that isn't secret — for example, an RPC method name or a public parameter. That's what `templatePublicValues` is for: it lets you inject **non-secret** values into the same template. + +This is purely a convenience. You could always hardcode the value directly in the body string instead: + +```typescript +// These two are equivalent: + +// Option 1: hardcoded in the body string +bodyString: '{"method": "eth_blockNumber", "auth": "{{.apiKey}}"}' + +// Option 2: using templatePublicValues +bodyString: '{"method": "{{.method}}", "auth": "{{.apiKey}}"}' +templatePublicValues: { + method: "eth_blockNumber" +} +``` + +`templatePublicValues` is useful when you want to keep the template generic and pass in dynamic values (e.g., from config) without string concatenation. + +**Example with both secret and public values:** + +```typescript +request: { + url: config.url, + method: "POST", + bodyString: '{"method": "{{.rpcMethod}}", "auth": "{{.apiKey}}"}', + templatePublicValues: { + rpcMethod: config.rpcMethod, // dynamic value from config, not a secret + }, +}, +vaultDonSecrets: [{ key: "apiKey", owner: config.owner }], // secret, from Vault DON +``` + +In this example, `{{.rpcMethod}}` is resolved from `templatePublicValues` (a dynamic, non-secret value from your workflow config) and `{{.apiKey}}` is resolved from the Vault DON (a secret). Both are resolved inside the enclave. + +## Response encryption + +The `encryptOutput` field controls whether the response body is encrypted before leaving the enclave. + +| encryptOutput | Secret key provided | Behavior | +| ----------------- | -------------------------------------------------------- | ------------------------------------------------------------- | +| `false` (default) | — | Response returned unencrypted. | +| `true` | `san_marino_aes_gcm_encryption_key` in `vaultDonSecrets` | Response AES-GCM encrypted with your symmetric key. | +| `true` | No key provided | Response TDH2 encrypted with the Vault DON master public key. | + +**AES-GCM encryption** is the recommended approach. Store a 256-bit (32-byte) AES key as a Vault DON secret with the identifier `san_marino_aes_gcm_encryption_key`, then decrypt the response in your own backend. + +The encrypted response body is structured as `nonce || ciphertext || tag`. + +For a complete example with response encryption, see the [Making Confidential Requests guide](/cre/guides/workflow/using-confidential-http-client/making-requests-ts#response-encryption). diff --git a/src/content/cre/reference/sdk/consensus-go.mdx b/src/content/cre/reference/sdk/consensus-go.mdx index 994a0747eef..f7e31fb9fed 100644 --- a/src/content/cre/reference/sdk/consensus-go.mdx +++ b/src/content/cre/reference/sdk/consensus-go.mdx @@ -20,8 +20,8 @@ This is a generic interface passed as the final argument to `cre.RunInNodeMode`. There are two primary ways to specify an aggregation method: -1. [**Using Built-in Functions**](/cre/reference/sdk/consensus-go/#1-built-in-aggregation-functions): For simple types, you can use functions like [`ConsensusMedianAggregation`](/cre/reference/sdk/consensus/#consensusmedianaggregationt). -1. [**Using Struct Tags**](/cre/reference/sdk/consensus-go/#2-aggregation-via-struct-tags): For complex types (structs), you can use [`ConsensusAggregationFromTags`](/cre/reference/sdk/consensus/#aggregation-via-struct-tags). +1. [**Using Built-in Functions**](/cre/reference/sdk/consensus-go/#1-built-in-aggregation-functions): For simple types, you can use functions like [`ConsensusMedianAggregation`](/cre/reference/sdk/consensus-go#consensusmedianaggregationt). +1. [**Using Struct Tags**](/cre/reference/sdk/consensus-go/#2-aggregation-via-struct-tags): For complex types (structs), you can use [`ConsensusAggregationFromTags`](/cre/reference/sdk/consensus-go#2-aggregation-via-struct-tags). ## 1. Built-in aggregation functions diff --git a/src/content/cre/reference/sdk/consensus-ts.mdx b/src/content/cre/reference/sdk/consensus-ts.mdx index 2ee9cfcce98..1769b35d657 100644 --- a/src/content/cre/reference/sdk/consensus-ts.mdx +++ b/src/content/cre/reference/sdk/consensus-ts.mdx @@ -7,7 +7,7 @@ pageId: "reference-sdk-consensus" metadata: description: "Reference for TypeScript consensus methods: explore median, mode, and custom aggregation algorithms for multi-node workflows." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside } from "@components" @@ -21,7 +21,7 @@ This is a generic type passed as the second argument to `runtime.runInNodeMode() There are two primary ways to specify an aggregation method: 1. [**Using built-in functions**](/cre/reference/sdk/consensus-ts#1-built-in-aggregation-functions): For simple types, use functions like [`consensusMedianAggregation()`](#consensusmedianaggregationt). -1. [**Using field-based aggregation**](/cre/reference/sdk/consensus-ts#2-field-based-aggregation-for-objects): For complex types (objects), use [`ConsensusAggregationByFields()`](#consensusaggregationbyfields). +1. [**Using field-based aggregation**](/cre/reference/sdk/consensus-ts#2-field-based-aggregation-for-objects): For complex types (objects), use [`ConsensusAggregationByFields()`](#consensusaggregationbyfieldstfields). ## 1. Built-in aggregation functions @@ -155,6 +155,7 @@ Creates a consensus aggregation strategy by specifying how to aggregate each fie ```typescript import { + HTTPClient, ConsensusAggregationByFields, median, identical, @@ -180,7 +181,7 @@ const fetchReserveData = (sendRequester: HTTPSendRequester, config: Config): Res } const onTrigger = (runtime: Runtime<Config>): string => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const reserveInfo = httpClient .sendRequest( @@ -211,7 +212,9 @@ Here's a complete example demonstrating both simple and field-based aggregation: ```typescript import { - cre, + CronCapability, + HTTPClient, + handler, Runner, consensusMedianAggregation, ConsensusAggregationByFields, @@ -235,7 +238,7 @@ type PriceData = { // Simple aggregation example const fetchSimplePrice = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const response = httpClient.sendRequest(nodeRuntime, { url: nodeRuntime.config.apiUrl }).result() const data = JSON.parse(response.body.toString()) return BigInt(data.price) @@ -260,7 +263,7 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = runtime.log(`Simple median price: ${simplePrice}`) // Example 2: Field-based aggregation - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const priceData = httpClient .sendRequest( runtime, @@ -279,17 +282,15 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: "0 */5 * * * *" }), onCronTrigger)] + return [handler(cron.trigger({ schedule: "0 */5 * * * *" }), onCronTrigger)] } export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Default Values diff --git a/src/content/cre/reference/sdk/core-go.mdx b/src/content/cre/reference/sdk/core-go.mdx index 1d48367c108..3e22abf709f 100644 --- a/src/content/cre/reference/sdk/core-go.mdx +++ b/src/content/cre/reference/sdk/core-go.mdx @@ -50,7 +50,7 @@ These interfaces provide access to capabilities and manage the execution context - **`cre.Runtime` ("Easy Mode")**: Passed to your main trigger callback, this represents the **DON's (Decentralized Oracle Network) execution context**. It is used for operations that are already guaranteed to be Byzantine Fault Tolerant (BFT). When you use the `Runtime`, you ask the network to execute something, and CRE handles the underlying complexity to ensure you get back one final, secure, and trustworthy result. A common use case is writing a transaction to a blockchain with the EVM client. -- **`cre.NodeRuntime` ("Manual Mode")**: Represents an **individual node's execution context**. This is used when a BFT guarantee cannot be provided automatically (e.g., calling a third-party API). You tell each node to perform a task on its own, and each node returns its own individual answer. You are then responsible for telling the SDK how to combine them into a single, trusted result by providing a consensus and aggregation algorithm. It is used exclusively inside a [`RunInNodeMode`](#sdkruninnodemode) block and is provided by that function—you do not get this type directly in your handler's callback. +- **`cre.NodeRuntime` ("Manual Mode")**: Represents an **individual node's execution context**. This is used when a BFT guarantee cannot be provided automatically (e.g., calling a third-party API). You tell each node to perform a task on its own, and each node returns its own individual answer. You are then responsible for telling the SDK how to combine them into a single, trusted result by providing a consensus and aggregation algorithm. It is used exclusively inside a [`RunInNodeMode`](#creruninnodemode) block and is provided by that function—you do not get this type directly in your handler's callback. To learn more about how to aggregate results from `NodeRuntime`, see the [Consensus & Aggregation](/cre/reference/sdk/consensus) reference. diff --git a/src/content/cre/reference/sdk/core-ts.mdx b/src/content/cre/reference/sdk/core-ts.mdx index 2f3d2dea960..cb9a1011c3a 100644 --- a/src/content/cre/reference/sdk/core-ts.mdx +++ b/src/content/cre/reference/sdk/core-ts.mdx @@ -7,27 +7,63 @@ pageId: "reference-sdk-core" metadata: description: "Reference for core TypeScript SDK: Workflow, Handler, Runtime, and essential functions every CRE workflow uses." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside } from "@components" This page provides a reference for the core data structures and functions of the CRE TypeScript SDK. These are the fundamental building blocks that every workflow uses, regardless of trigger types or capabilities. +## Import styles + +The CRE TypeScript SDK supports two equivalent import styles. **Both are fully supported**, produce identical behavior, and can be used interchangeably in your workflows. + +<Aside type="tip" title="Choose the style that fits your codebase"> + Both import patterns are **fully supported** and will continue to work. There are no plans to deprecate either style. + Choose whichever approach better matches your team's conventions. +</Aside> + +**Direct imports (recommended for new projects):** + +```typescript +import { Runner, HTTPClient, EVMClient, CronCapability, handler } from "@chainlink/cre-sdk" + +// Use directly +const httpClient = new HTTPClient() +const evmClient = new EVMClient(chainSelector) +``` + +**Namespace imports:** + +```typescript +import { cre, Runner } from "@chainlink/cre-sdk" + +// Access through cre namespace +const httpClient = new cre.capabilities.HTTPClient() +const evmClient = new cre.capabilities.EVMClient(chainSelector) +``` + +**When to use each style:** + +| Style | Best for | +| --------------------- | ---------------------------------------------------------------------------- | +| **Direct imports** | New projects, cleaner import statements, better tree-shaking | +| **Namespace imports** | Existing codebases already using this pattern, preference for grouped access | + ## Key concepts and components -### `cre.handler()` +### `handler()` -The `cre.handler()` function is the cornerstone of every workflow. It registers a handler that links a specific trigger to a callback function containing your workflow logic. It is typically called within your [`initWorkflow`](#initworkflow) function. +The `handler()` function is the cornerstone of every workflow. It registers a handler that links a specific trigger to a callback function containing your workflow logic. It is typically called within your [`initWorkflow`](#initworkflow) function. **Usage:** ```typescript -import { cre, type Runtime } from "@chainlink/cre-sdk" +import { handler, type Runtime } from "@chainlink/cre-sdk" const initWorkflow = (config: Config) => { return [ - cre.handler( + handler( // 1. A configured trigger, e.g., cron.trigger(...) // This determines WHEN the workflow runs triggerInstance, @@ -63,8 +99,8 @@ To learn more about how to aggregate results from `NodeRuntime`, see the [Consen Both `Runtime` and `NodeRuntime` provide: - **`config`**: Access to your workflow's configuration -- **`now()`**: Returns the current `Date` object -- **`log(message: string)`**: Logs a message (accepts a single string argument) +- **`now()`**: Returns the current `Date` object. See [Time in CRE](/cre/guides/workflow/time-in-workflows-ts) for details. +- **`log(message: string)`**: Logs a message (see [Logging](#logging) below) - **`callCapability(...)`**: Internal method for calling capabilities (used by generated code) `Runtime` additionally provides: @@ -73,6 +109,35 @@ Both `Runtime` and `NodeRuntime` provide: - **`getSecret(...)`**: Access to workflow secrets - **`report(...)`**: Generate cryptographically signed reports +### Logging + +Use `runtime.log()` to output messages from your workflow. This is the **only way** to produce visible logs—`console.log` does not work in the WASM environment. + +```typescript +const onCronTrigger = (runtime: Runtime<Config>): string => { + runtime.log("Workflow started") + + const result = someOperation() + runtime.log(`Operation result: ${result}`) + + return "done" +} +``` + +**Where logs appear:** + +| Environment | Location | +| --------------------- | ------------------------------------------------------------------------------------ | +| **Simulation** | Terminal output with `[USER LOG]` prefix | +| **Deployed workflow** | CRE UI → Workflows → select workflow → Execution tab → click an execution → Logs tab | + +See [Monitoring & Debugging Workflows](/cre/guides/operations/monitoring-workflows#logs-tab) for details on viewing logs for deployed workflows. + +**Important notes:** + +- `runtime.log()` accepts a **single string argument**—use template literals to include variables +- Logs are only available inside callback functions where you have access to the `runtime` object + ### Understanding the `.result()` Pattern All SDK capabilities in the TypeScript SDK use a two-step pattern for asynchronous operations: @@ -92,11 +157,11 @@ const response = request.result() **Common usage:** These steps are often chained together for simplicity: ```typescript -import { cre, encodeCallMsg, LAST_FINALIZED_BLOCK_NUMBER, type Runtime } from "@chainlink/cre-sdk" +import { EVMClient, encodeCallMsg, LAST_FINALIZED_BLOCK_NUMBER, type Runtime } from "@chainlink/cre-sdk" import { zeroAddress } from "viem" const onCronTrigger = (runtime: Runtime<Config>): string => { - const evmClient = new cre.capabilities.EVMClient(chainSelector) + const evmClient = new EVMClient(chainSelector) // Inline pattern: initiate and get result in one expression const contractCall = evmClient @@ -187,16 +252,81 @@ export async function main() { // Run your workflow initialization function await runner.run(initWorkflow) } - -main() ``` +<Aside type="note" title="SDK v1.0.2+ Changes"> + Starting with SDK v1.0.2, the SDK handles `main()` execution automatically: + +- **Calling `main()` is optional**: The SDK automatically executes the `main()` function during compilation. You no longer need to call `main()` at the end of your workflow file. +- **Automatic error handling**: If you don't provide custom error handling, the SDK automatically adds `.catch(sendErrorResponse)` to ensure errors are properly reported instead of silently failing. + +</Aside> + +**All of these patterns are valid:** + +- **Pattern 1: Let the SDK handle everything (recommended)** + + ```typescript + export async function main() { + const runner = await Runner.newRunner<Config>() + await runner.run(initWorkflow) + } + // No need to call main() - the SDK automatically appends: + // main().catch(sendErrorResponse) + ``` + +- **Pattern 2: Explicit call without `.catch()` - SDK adds error handling** + + ```typescript + export async function main() { + const runner = await Runner.newRunner<Config>() + await runner.run(initWorkflow) + } + + main() // SDK transforms this to: main().catch(sendErrorResponse) + ``` + +- **Pattern 3: Custom error handling - SDK respects your handler** + + ```typescript + import { sendErrorResponse } from "@chainlink/cre-sdk" + + export async function main() { + const runner = await Runner.newRunner<Config>() + await runner.run(initWorkflow) + } + + // If you provide .catch(), the SDK leaves it untouched + main().catch((error) => { + // Your custom error handling logic + // You should call sendErrorResponse to report the error + sendErrorResponse(error) + }) + ``` + +<Aside type="caution" title="No console access in workflows"> + CRE workflows are compiled to WebAssembly (WASM), where `console.log` and `console.error` **produce no output**. Use + `runtime.log()` for logging within your callback functions—these logs appear in simulation output with the `[USER + LOG]` prefix and in the [CRE UI Logs tab](/cre/guides/operations/monitoring-workflows#logs-tab) for deployed + workflows. For error reporting from `main()`, use the SDK's `sendErrorResponse` function. +</Aside> + +<Aside type="tip" title="When to use custom error handling"> + Most workflows don't need custom error handling—the SDK's default handler reports errors properly. Only add a custom + `.catch()` handler if you need to transform errors, add context, or perform cleanup before reporting. If you provide a + custom handler, remember to call `sendErrorResponse(error)` to ensure the error is properly reported. +</Aside> + +`sendErrorResponse` reports the error to CRE and marks the execution as failed. + +- In **simulation**, the error appears in your terminal output. +- For **deployed workflows**, you'll see it in the [Execution tab](/cre/guides/operations/monitoring-workflows#execution-history) with a `Failure` status and the error message in the Logs tab. + **Key points:** - Must be an `async` function - Must call `Runner.newRunner<Config>()` with an optional `configSchema` parameter for validation - Must call `runner.run(initWorkflow)` to execute your workflow -- Must invoke `main()` at the end of your file ### `initWorkflow` @@ -205,7 +335,7 @@ This is the second required entry point. The CRE runner calls this function to i **Required Signature:** ```typescript -import { cre, type Runtime } from "@chainlink/cre-sdk" +import { handler, type Runtime } from "@chainlink/cre-sdk" function initWorkflow(config: Config): Array<HandlerEntry<Config, any, any, any>> ``` @@ -216,7 +346,7 @@ function initWorkflow(config: Config): Array<HandlerEntry<Config, any, any, any> **Returns:** -- An array of handlers created with `cre.handler()` +- An array of handlers created with `handler()` <Aside type="note" title="Using secrets"> If your workflow uses secrets, you can add a second parameter `secretsProvider: SecretsProvider` to access the @@ -226,7 +356,7 @@ function initWorkflow(config: Config): Array<HandlerEntry<Config, any, any, any> **Example:** ```typescript -import { cre, type Runtime, type CronPayload } from "@chainlink/cre-sdk" +import { CronCapability, handler, type Runtime, type CronPayload } from "@chainlink/cre-sdk" // Callback function executed by the handler const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string => { @@ -235,9 +365,9 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } ``` @@ -271,14 +401,14 @@ This example uses `runInNodeMode` to fetch data from an API on each node, and th ```typescript import { - cre, + HTTPClient, consensusMedianAggregation, type Runtime, type NodeRuntime, } from "@chainlink/cre-sdk" const fetchPrice = (nodeRuntime: NodeRuntime<Config>): bigint => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // Fetch price from API using nodeRuntime return fetchOffchainPrice(nodeRuntime) } diff --git a/src/content/cre/reference/sdk/evm-client-go.mdx b/src/content/cre/reference/sdk/evm-client-go.mdx index ad932af37ff..0c68c7ad60f 100644 --- a/src/content/cre/reference/sdk/evm-client-go.mdx +++ b/src/content/cre/reference/sdk/evm-client-go.mdx @@ -7,7 +7,7 @@ pageId: "reference-sdk-evm-client" metadata: description: "Reference for Go EVM Client: complete API for smart contract interactions, reads, writes, report generation, and chain configuration." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside, CopyText } from "@components" @@ -69,10 +69,10 @@ func (c *Client) CallContract(runtime cre.Runtime, input *CallContractRequest) c This is the main input object for the `CallContract` function. It acts as a wrapper for the call message and an optional block number. -| <div style="width:100px">Field</div> | <div style="width:110px">Type</div> | Description | -| ------------------------------------ | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Call` | `*evm.CallMsg` | Contains the actual details of the function call you want to make. | -| `BlockNumber` | `*pb.BigInt` | Optional. The block number to query. Defaults to `latest`. Use `-2` for `latest` (the most recent block, which may be subject to re-orgs) or `-3` for `finalized` (a block that is considered immutable and safe from re-orgs). | +| <div style="width:100px">Field</div> | <div style="width:110px">Type</div> | Description | +| ------------------------------------ | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Call` | `*evm.CallMsg` | Contains the actual details of the function call you want to make. | +| `BlockNumber` | `*pb.BigInt` | Optional. The block number to query. Accepts:<br/>• `nil` or `-2` (default): `latest` — the most recent block<br/>• `-3`: `finalized` — an immutable block<br/>• **Any positive integer**: an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-go#custom-block-depths) for examples)<br/><br/>See [Finality and Confidence Levels](/cre/concepts/finality-go) for finality strategies. | #### `evm.CallMsg` @@ -104,10 +104,10 @@ func (c *Client) BalanceAt(runtime cre.Runtime, input *BalanceAtRequest) cre.Pro #### `evm.BalanceAtRequest` -| Field | Type | Description | -| ------------- | ------------ | ---------------------------------------------------------- | -| `Account` | `[]byte` | The 20-byte address of the account to query. | -| `BlockNumber` | `*pb.BigInt` | Optional. The block number to query. Defaults to `latest`. | +| Field | Type | Description | +| ------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Account` | `[]byte` | The 20-byte address of the account to query. | +| `BlockNumber` | `*pb.BigInt` | Optional. The block number to query. Accepts `nil` or `-2` for `latest` (default), `-3` for `finalized`, or any positive integer for an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-go#custom-block-depths)). See [Finality and Confidence Levels](/cre/concepts/finality-go). | #### `evm.BalanceAtReply` @@ -193,9 +193,9 @@ func (c *Client) HeaderByNumber(runtime cre.Runtime, input *HeaderByNumberReques #### `evm.HeaderByNumberRequest` -| Field | Type | Description | -| ------------- | ------------ | -------------------------------------------------------------------------- | -| `BlockNumber` | `*pb.BigInt` | The number of the block to retrieve. If `nil`, retrieves the latest block. | +| Field | Type | Description | +| ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `BlockNumber` | `*pb.BigInt` | The number of the block to retrieve. Accepts `nil` for `latest` (default), `-2` for `latest`, `-3` for `finalized`, or any positive integer for an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-go#custom-block-depths)). See [Finality and Confidence Levels](/cre/concepts/finality-go). | #### `evm.HeaderByNumberReply` @@ -259,10 +259,10 @@ func (c *Client) WriteReport(runtime cre.Runtime, input *WriteCreReportRequest) A **chain selector** is a unique identifier for a blockchain network used throughout the CRE platform. The same chain can be referenced in three different ways depending on the context. All three formats are equivalent and refer to the same blockchain. +{/* prettier-ignore */} <Aside type="note" title="Related resources"> - - **Forwarder addresses**: For network-specific forwarder contract addresses, see [Supported - Networks](/cre/guides/workflow/using-evm-client/supported-networks) - **RPC configuration**: For configuring RPC - endpoints in `project.yaml`, see [Project Configuration](/cre/reference/project-configuration) + - **Forwarder addresses**: For network-specific forwarder contract addresses, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) + - **RPC configuration**: For configuring RPC endpoints in `project.yaml`, see [Project Configuration](/cre/reference/project-configuration) </Aside> ### Understanding the three formats @@ -283,22 +283,32 @@ A **chain selector** is a unique identifier for a blockchain network used throug This table shows all three equivalent formats for each supported chain: -| <div style="width: 180px;">Chain</div> | String Name | <div style="width: 110px;">Go Constant</div> | <div style="width: 100px;">Numeric ID</div> | -| -------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | --------------------------------------------- | -| Arbitrum One | <CopyText text="ethereum-mainnet-arbitrum-1" code /> | <CopyText text="evm.EthereumMainnetArbitrum1" code /> | <CopyText text="4949039107694359620" code /> | -| Arbitrum Sepolia | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code /> | <CopyText text="evm.EthereumTestnetSepoliaArbitrum1" code /> | <CopyText text="3478487238524512106" code /> | -| Avalanche Mainnet | <CopyText text="avalanche-mainnet" code /> | <CopyText text="evm.AvalancheMainnet" code /> | <CopyText text="6433500567565415381" code /> | -| Avalanche Fuji | <CopyText text="avalanche-testnet-fuji" code /> | <CopyText text="evm.AvalancheTestnetFuji" code /> | <CopyText text="14767482510784806043" code /> | -| Base Mainnet | <CopyText text="ethereum-mainnet-base-1" code /> | <CopyText text="evm.EthereumMainnetBase1" code /> | <CopyText text="15971525489660198786" code /> | -| Base Sepolia | <CopyText text="ethereum-testnet-sepolia-base-1" code /> | <CopyText text="evm.EthereumTestnetSepoliaBase1" code /> | <CopyText text="10344971235874465080" code /> | -| BNB Chain Mainnet | <CopyText text="binance_smart_chain-mainnet" code /> | <CopyText text="evm.BinanceSmartChainMainnet" code /> | <CopyText text="11344663589394136015" code /> | -| BNB Chain Testnet | <CopyText text="binance_smart_chain-testnet" code /> | <CopyText text="evm.BinanceSmartChainTestnet" code /> | <CopyText text="5142893604156789321" code /> | -| Ethereum Mainnet | <CopyText text="ethereum-mainnet" code /> | <CopyText text="evm.EthereumMainnet" code /> | <CopyText text="5009297550715157269" code /> | -| Ethereum Sepolia | <CopyText text="ethereum-testnet-sepolia" code /> | <CopyText text="evm.EthereumTestnetSepolia" code /> | <CopyText text="16015286601757825753" code /> | -| OP Mainnet | <CopyText text="ethereum-mainnet-optimism-1" code /> | <CopyText text="evm.EthereumMainnetOptimism1" code /> | <CopyText text="3734403246176062136" code /> | -| OP Sepolia | <CopyText text="ethereum-testnet-sepolia-optimism-1" code /> | <CopyText text="evm.EthereumTestnetSepoliaOptimism1" code /> | <CopyText text="5224473277236331295" code /> | -| Polygon Mainnet | <CopyText text="polygon-mainnet" code /> | <CopyText text="evm.PolygonMainnet" code /> | <CopyText text="4051577828743386545" code /> | -| Polygon Amoy | <CopyText text="polygon-testnet-amoy" code /> | <CopyText text="evm.PolygonTestnetAmoy" code /> | <CopyText text="16281711391670634445" code /> | +| <div style="width: 180px;">Chain</div> | String Name | <div style="width: 110px;">Go Constant</div> | <div style="width: 100px;">Numeric ID</div> | +| -------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------- | --------------------------------------------- | +| Apechain Curtis | <CopyText text="apechain-testnet-curtis" code /> | <CopyText text="evm.ApechainTestnetCurtis" code /> | <CopyText text="9900119385908781505" code /> | +| Arc Testnet | <CopyText text="arc-testnet" code /> | <CopyText text="evm.ArcTestnet" code /> | <CopyText text="3034092155422581607" code /> | +| Arbitrum One | <CopyText text="ethereum-mainnet-arbitrum-1" code /> | <CopyText text="evm.EthereumMainnetArbitrum1" code /> | <CopyText text="4949039107694359620" code /> | +| Arbitrum Sepolia | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code /> | <CopyText text="evm.EthereumTestnetSepoliaArbitrum1" code /> | <CopyText text="3478487238524512106" code /> | +| Avalanche Mainnet | <CopyText text="avalanche-mainnet" code /> | <CopyText text="evm.AvalancheMainnet" code /> | <CopyText text="6433500567565415381" code /> | +| Avalanche Fuji | <CopyText text="avalanche-testnet-fuji" code /> | <CopyText text="evm.AvalancheTestnetFuji" code /> | <CopyText text="14767482510784806043" code /> | +| Base Mainnet | <CopyText text="ethereum-mainnet-base-1" code /> | <CopyText text="evm.EthereumMainnetBase1" code /> | <CopyText text="15971525489660198786" code /> | +| Base Sepolia | <CopyText text="ethereum-testnet-sepolia-base-1" code /> | <CopyText text="evm.EthereumTestnetSepoliaBase1" code /> | <CopyText text="10344971235874465080" code /> | +| BNB Chain Mainnet | <CopyText text="binance_smart_chain-mainnet" code /> | <CopyText text="evm.BinanceSmartChainMainnet" code /> | <CopyText text="11344663589394136015" code /> | +| BNB Chain Testnet | <CopyText text="binance_smart_chain-testnet" code /> | <CopyText text="evm.BinanceSmartChainTestnet" code /> | <CopyText text="13264668187771770619" code /> | +| Ethereum Mainnet | <CopyText text="ethereum-mainnet" code /> | <CopyText text="evm.EthereumMainnet" code /> | <CopyText text="5009297550715157269" code /> | +| Ethereum Sepolia | <CopyText text="ethereum-testnet-sepolia" code /> | <CopyText text="evm.EthereumTestnetSepolia" code /> | <CopyText text="16015286601757825753" code /> | +| Hyperliquid Testnet | <CopyText text="hyperliquid-testnet" code /> | <CopyText text="evm.HyperliquidTestnet" code /> | <CopyText text="4286062357653186312" code /> | +| Ink Sepolia | <CopyText text="ink-testnet-sepolia" code /> | <CopyText text="evm.InkTestnetSepolia" code /> | <CopyText text="9763904284804119144" code /> | +| Jovay Testnet | <CopyText text="jovay-testnet" code /> | <CopyText text="evm.JovayTestnet" code /> | <CopyText text="945045181441419236" code /> | +| Linea Sepolia | <CopyText text="ethereum-testnet-sepolia-linea-1" code /> | <CopyText text="evm.EthereumTestnetSepoliaLinea1" code /> | <CopyText text="5719461335882077547" code /> | +| OP Mainnet | <CopyText text="ethereum-mainnet-optimism-1" code /> | <CopyText text="evm.EthereumMainnetOptimism1" code /> | <CopyText text="3734403246176062136" code /> | +| OP Sepolia | <CopyText text="ethereum-testnet-sepolia-optimism-1" code /> | <CopyText text="evm.EthereumTestnetSepoliaOptimism1" code /> | <CopyText text="5224473277236331295" code /> | +| Plasma Testnet | <CopyText text="plasma-testnet" code /> | <CopyText text="evm.PlasmaTestnet" code /> | <CopyText text="3967220077692964309" code /> | +| Polygon Mainnet | <CopyText text="polygon-mainnet" code /> | <CopyText text="evm.PolygonMainnet" code /> | <CopyText text="4051577828743386545" code /> | +| Polygon Amoy | <CopyText text="polygon-testnet-amoy" code /> | <CopyText text="evm.PolygonTestnetAmoy" code /> | <CopyText text="16281711391670634445" code /> | +| World Chain Sepolia | <CopyText text="ethereum-testnet-sepolia-worldchain-1" code /> | <CopyText text="evm.EthereumTestnetSepoliaWorldchain1" code /> | <CopyText text="5299555114858065850" code /> | +| ZKSync Era | <CopyText text="ethereum-mainnet-zksync-1" code /> | <CopyText text="evm.EthereumMainnetZksync1" code /> | <CopyText text="1562403441176082196" code /> | +| ZKSync Era Sepolia | <CopyText text="ethereum-testnet-sepolia-zksync-1" code /> | <CopyText text="evm.EthereumTestnetSepoliaZksync1" code /> | <CopyText text="6898391096552792247" code /> | ### Usage examples diff --git a/src/content/cre/reference/sdk/evm-client-ts.mdx b/src/content/cre/reference/sdk/evm-client-ts.mdx index 3cea5e8c36c..53e52ca12a6 100644 --- a/src/content/cre/reference/sdk/evm-client-ts.mdx +++ b/src/content/cre/reference/sdk/evm-client-ts.mdx @@ -7,7 +7,7 @@ pageId: "reference-sdk-evm-client" metadata: description: "Reference for TypeScript EVM Client: complete API for smart contract interactions, reads, writes, and report generation with Viem." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside, CopyText } from "@components" @@ -19,7 +19,7 @@ This page provides a reference for the `EVMClient`, the low-level tool for all i To use the client, you must instantiate it with the numeric `ChainSelector` ID for the blockchain you intend to interact with. ```typescript -import { cre, getNetwork } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork } from "@chainlink/cre-sdk" // Get network information by chain selector name const network = getNetwork({ @@ -33,7 +33,7 @@ if (!network) { } // Instantiate a client for Ethereum Sepolia -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) ``` <Aside type="note" title="What is a Chain Selector?"> @@ -56,9 +56,9 @@ const network = getNetwork({ }) // Access network properties -console.log(network.chainSelector.selector) // 16015286601757825753n (bigint) -console.log(network.chainSelector.name) // "ethereum-testnet-sepolia" -console.log(network.family) // "evm" +// network.chainSelector.selector → 16015286601757825753n (bigint) +// network.chainSelector.name → "ethereum-testnet-sepolia" +// network.family → "evm" ``` ## Read & query methods @@ -82,10 +82,10 @@ callContract( This is the main input object for the `callContract()` method. -| <div style="width:110px">Field</div> | <div style="width:110px">Type</div> | Required | Description | -| ------------------------------------ | ----------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `call` | `CallMsgJson` | Yes | Contains the actual details of the function call you want to make. | -| `blockNumber` | `string` | No | The block number to query. Use `LAST_FINALIZED_BLOCK_NUMBER` for finalized blocks or `LATEST_BLOCK_NUMBER` for the most recent block. Defaults to `"latest"`. | +| <div style="width:110px">Field</div> | <div style="width:110px">Type</div> | Required | Description | +| ------------------------------------ | ----------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `call` | `CallMsgJson` | Yes | Contains the actual details of the function call you want to make. | +| `blockNumber` | `BigIntJson` | No | The block number to query. Accepts:<br/>• `LATEST_BLOCK_NUMBER` (default): the most recent block<br/>• `LAST_FINALIZED_BLOCK_NUMBER`: a finalized block<br/>• **`BigIntJson` object**: an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths) for conversion details).<br/><br/>See [Finality and Confidence Levels](/cre/concepts/finality-ts) for finality strategies. | #### `CallMsg` / `CallMsgJson` @@ -108,7 +108,7 @@ This is the object returned by `.result()` when the `callContract()` method succ #### Usage example ```typescript -import { cre, getNetwork, encodeCallMsg, bytesToHex, LAST_FINALIZED_BLOCK_NUMBER } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, encodeCallMsg, bytesToHex, LAST_FINALIZED_BLOCK_NUMBER } from "@chainlink/cre-sdk" import { encodeFunctionData, decodeFunctionResult, zeroAddress } from "viem" import { Storage } from "../contracts/abi" @@ -118,7 +118,7 @@ const network = getNetwork({ chainSelectorName: "ethereum-testnet-sepolia", isTestnet: true, }) -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) // Encode the contract call data const callData = encodeFunctionData({ @@ -204,10 +204,10 @@ balanceAt( #### `BalanceAtRequest` / `BalanceAtRequestJson` -| Field | Type | Required | Description | -| ------------- | -------- | -------- | --------------------------------------------------------- | -| `account` | `string` | Yes | The 20-byte address of the account to query (hex string). | -| `blockNumber` | `string` | No | The block number to query. Defaults to `"latest"`. | +| <div style="width:110px">Field</div> | <div style="width:110px">Type</div> | Required | Description | +| ------------------------------------ | ----------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `account` | `string` | Yes | The 20-byte address of the account to query (hex string). | +| `blockNumber` | `BigIntJson` | No | The block number to query. Accepts `LATEST_BLOCK_NUMBER` (default), `LAST_FINALIZED_BLOCK_NUMBER`, or a `BigIntJson` object for an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths)). See [Finality and Confidence Levels](/cre/concepts/finality-ts). | #### `BalanceAtReply` @@ -339,9 +339,9 @@ headerByNumber( #### `HeaderByNumberRequest` / `HeaderByNumberRequestJson` -| <div style="width: 100px;">Field</div> | <div style="width: 100px;">Type</div> | Required | Description | -| -------------------------------------- | ------------------------------------- | -------- | -------------------------------------------------------------------------------- | -| `blockNumber` | `string` | No | The number of the block to retrieve. If `undefined`, retrieves the latest block. | +| <div style="width: 100px;">Field</div> | <div style="width: 100px;">Type</div> | Required | Description | +| -------------------------------------- | ------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `blockNumber` | `BigIntJson` | No | The number of the block to retrieve. Accepts `undefined` for `latest` (default), `LATEST_BLOCK_NUMBER`, `LAST_FINALIZED_BLOCK_NUMBER`, or a `BigIntJson` object for an explicit block height (see [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths)). See [Finality and Confidence Levels](/cre/concepts/finality-ts). | #### `HeaderByNumberReply` @@ -408,7 +408,7 @@ writeReport( #### Usage example ```typescript -import { cre, getNetwork, hexToBase64, bytesToHex } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, hexToBase64, bytesToHex } from "@chainlink/cre-sdk" import { encodeFunctionData } from "viem" import { ReserveManager } from "../contracts/abi" @@ -559,6 +559,86 @@ function hexToBase64(hex: Hex): string --- +### `protoBigIntToBigint()` + +Converts a protobuf `BigInt` (returned by SDK methods like `headerByNumber`) to a native JavaScript `bigint`. Use this when you need to perform arithmetic on block numbers or other numeric values returned from the blockchain. + +**Signature:** + +```typescript +function protoBigIntToBigint(pb: ProtoBigInt): bigint +``` + +**Parameters:** + +- `pb`: A protobuf `BigInt` object with `absVal` (Uint8Array) and `sign` (bigint) fields + +**Returns:** + +A native JavaScript `bigint` value. + +**Usage:** + +```typescript +import { protoBigIntToBigint } from "@chainlink/cre-sdk" + +// Get the latest block number from the blockchain +const latestHeader = evmClient.headerByNumber(runtime, {}).result() + +// Convert the protobuf BigInt to a native bigint for arithmetic +const latestBlockNum = protoBigIntToBigint(latestHeader.header.blockNumber) +const customBlock = latestBlockNum - 500n // Now you can do arithmetic + +// latestBlockNum → e.g., 12345678n +// customBlock → e.g., 12345178n (500 blocks earlier) +``` + +See [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths) for a complete example. + +--- + +### `blockNumber()` + +Converts a native `bigint`, `number`, or `string` to the protobuf `BigInt` JSON format required by SDK methods. This is a convenience alias for `bigintToProtoBigInt`. Use this when specifying an explicit block height for contract calls or other blockchain queries. + +**Signature:** + +```typescript +function blockNumber(n: number | bigint | string): BigIntJson +``` + +**Parameters:** + +- `n`: The block number as a native `bigint`, `number`, or `string` + +**Returns:** + +A `BigIntJson` object in the protobuf format expected by SDK methods. + +**Usage:** + +```typescript +import { blockNumber, encodeCallMsg } from "@chainlink/cre-sdk" +import { zeroAddress } from "viem" + +// Read from a specific historical block +const historicalBlock = 9767655n +const contractCall = evmClient + .callContract(runtime, { + call: encodeCallMsg({ + from: zeroAddress, + to: contractAddress, + data: callData, + }), + blockNumber: blockNumber(historicalBlock), + }) + .result() +``` + +See [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths) for a complete example. + +--- + ### `prepareReportRequest()` Prepares a report request with default EVM encoding parameters for use with `runtime.report()`. This helper simplifies report generation by automatically setting the standard encoding configuration (`evm`, `ecdsa`, `keccak256`) required for EVM-based workflows. @@ -692,7 +772,7 @@ if (!network) { } // Access the numeric chain selector (bigint) -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) // network.chainSelector.selector is 16015286601757825753n (bigint) ``` @@ -701,7 +781,7 @@ const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) The `EVMClient` class includes a static `SUPPORTED_CHAINS` constant with all available chain selectors: ```typescript -cre.capabilities.EVMClient.SUPPORTED_CHAINS +EVMClient.SUPPORTED_CHAINS // Returns: // { // 'avalanche-mainnet': 6433500567565415381n, @@ -715,28 +795,38 @@ cre.capabilities.EVMClient.SUPPORTED_CHAINS This table shows the chain selector names and their numeric IDs. In your configuration files (`project.yaml`, `config.staging.json`, `config.production.json`, etc.), you always use the **String Name**. The numeric ID is used internally by the SDK and is returned by the `getNetwork()` helper function. +{/* prettier-ignore */} <Aside type="note" title="Related resources"> - - **Forwarder addresses**: For network-specific forwarder contract addresses, see [Supported - Networks](/cre/guides/workflow/using-evm-client/supported-networks) - **RPC configuration**: For configuring RPC - endpoints in `project.yaml`, see [Project Configuration](/cre/reference/project-configuration) + - **Forwarder addresses**: For network-specific forwarder contract addresses, see [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory) + - **RPC configuration**: For configuring RPC endpoints in `project.yaml`, see [Project Configuration](/cre/reference/project-configuration) </Aside> -| <div style="width: 220px;">Chain</div> | String Name | <div style="width: 100px;">Numeric ID</div> | -| -------------------------------------- | ------------------------------------------------------------ | --------------------------------------------- | -| Arbitrum One | <CopyText text="ethereum-mainnet-arbitrum-1" code /> | <CopyText text="4949039107694359620" code /> | -| Arbitrum Sepolia | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code /> | <CopyText text="3478487238524512106" code /> | -| Avalanche Mainnet | <CopyText text="avalanche-mainnet" code /> | <CopyText text="6433500567565415381" code /> | -| Avalanche Fuji | <CopyText text="avalanche-testnet-fuji" code /> | <CopyText text="14767482510784806043" code /> | -| Base Mainnet | <CopyText text="ethereum-mainnet-base-1" code /> | <CopyText text="15971525489660198786" code /> | -| Base Sepolia | <CopyText text="ethereum-testnet-sepolia-base-1" code /> | <CopyText text="10344971235874465080" code /> | -| BNB Chain Mainnet | <CopyText text="binance_smart_chain-mainnet" code /> | <CopyText text="11344663589394136015" code /> | -| BNB Chain Testnet | <CopyText text="binance_smart_chain-testnet" code /> | <CopyText text="5142893604156789321" code /> | -| Ethereum Mainnet | <CopyText text="ethereum-mainnet" code /> | <CopyText text="5009297550715157269" code /> | -| Ethereum Sepolia | <CopyText text="ethereum-testnet-sepolia" code /> | <CopyText text="16015286601757825753" code /> | -| OP Mainnet | <CopyText text="ethereum-mainnet-optimism-1" code /> | <CopyText text="3734403246176062136" code /> | -| OP Sepolia | <CopyText text="ethereum-testnet-sepolia-optimism-1" code /> | <CopyText text="5224473277236331295" code /> | -| Polygon Mainnet | <CopyText text="polygon-mainnet" code /> | <CopyText text="4051577828743386545" code /> | -| Polygon Amoy | <CopyText text="polygon-testnet-amoy" code /> | <CopyText text="16281711391670634445" code /> | +| <div style="width: 220px;">Chain</div> | String Name | <div style="width: 100px;">Numeric ID</div> | +| -------------------------------------- | -------------------------------------------------------------- | --------------------------------------------- | +| Apechain Curtis | <CopyText text="apechain-testnet-curtis" code /> | <CopyText text="9900119385908781505" code /> | +| Arc Testnet | <CopyText text="arc-testnet" code /> | <CopyText text="3034092155422581607" code /> | +| Arbitrum One | <CopyText text="ethereum-mainnet-arbitrum-1" code /> | <CopyText text="4949039107694359620" code /> | +| Arbitrum Sepolia | <CopyText text="ethereum-testnet-sepolia-arbitrum-1" code /> | <CopyText text="3478487238524512106" code /> | +| Avalanche Mainnet | <CopyText text="avalanche-mainnet" code /> | <CopyText text="6433500567565415381" code /> | +| Avalanche Fuji | <CopyText text="avalanche-testnet-fuji" code /> | <CopyText text="14767482510784806043" code /> | +| Base Mainnet | <CopyText text="ethereum-mainnet-base-1" code /> | <CopyText text="15971525489660198786" code /> | +| Base Sepolia | <CopyText text="ethereum-testnet-sepolia-base-1" code /> | <CopyText text="10344971235874465080" code /> | +| BNB Chain Mainnet | <CopyText text="binance_smart_chain-mainnet" code /> | <CopyText text="11344663589394136015" code /> | +| BNB Chain Testnet | <CopyText text="binance_smart_chain-testnet" code /> | <CopyText text="13264668187771770619" code /> | +| Ethereum Mainnet | <CopyText text="ethereum-mainnet" code /> | <CopyText text="5009297550715157269" code /> | +| Ethereum Sepolia | <CopyText text="ethereum-testnet-sepolia" code /> | <CopyText text="16015286601757825753" code /> | +| Hyperliquid Testnet | <CopyText text="hyperliquid-testnet" code /> | <CopyText text="4286062357653186312" code /> | +| Ink Sepolia | <CopyText text="ink-testnet-sepolia" code /> | <CopyText text="9763904284804119144" code /> | +| Jovay Testnet | <CopyText text="jovay-testnet" code /> | <CopyText text="945045181441419236" code /> | +| Linea Sepolia | <CopyText text="ethereum-testnet-sepolia-linea-1" code /> | <CopyText text="5719461335882077547" code /> | +| OP Mainnet | <CopyText text="ethereum-mainnet-optimism-1" code /> | <CopyText text="3734403246176062136" code /> | +| OP Sepolia | <CopyText text="ethereum-testnet-sepolia-optimism-1" code /> | <CopyText text="5224473277236331295" code /> | +| Plasma Testnet | <CopyText text="plasma-testnet" code /> | <CopyText text="3967220077692964309" code /> | +| Polygon Mainnet | <CopyText text="polygon-mainnet" code /> | <CopyText text="4051577828743386545" code /> | +| Polygon Amoy | <CopyText text="polygon-testnet-amoy" code /> | <CopyText text="16281711391670634445" code /> | +| World Chain Sepolia | <CopyText text="ethereum-testnet-sepolia-worldchain-1" code /> | <CopyText text="5299555114858065850" code /> | +| ZKSync Era | <CopyText text="ethereum-mainnet-zksync-1" code /> | <CopyText text="1562403441176082196" code /> | +| ZKSync Era Sepolia | <CopyText text="ethereum-testnet-sepolia-zksync-1" code /> | <CopyText text="6898391096552792247" code /> | ### Usage in configuration files @@ -779,5 +869,5 @@ if (!network) { throw new Error(`Network not found: ${config.evms[0].chainName}`) } -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) ``` diff --git a/src/content/cre/reference/sdk/http-client-go.mdx b/src/content/cre/reference/sdk/http-client-go.mdx index cdb2f2078c5..2db1b44cf90 100644 --- a/src/content/cre/reference/sdk/http-client-go.mdx +++ b/src/content/cre/reference/sdk/http-client-go.mdx @@ -7,7 +7,7 @@ pageId: "reference-sdk-http-client" metadata: description: "Reference for Go HTTP Client: complete API for GET/POST requests, headers, authentication, and consensus aggregation methods." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-26" --- import { Aside } from "@components" @@ -35,14 +35,100 @@ The HTTP Client lets you make requests to external APIs from your workflow. Each Defines the parameters for an outgoing HTTP request. -| <div style="width: 120px;">Field</div> | <div style="width: 200px;">Type</div> | Description | -| -------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | -| `Url` | `string` | The URL of the API endpoint. | -| `Method` | `string` | The HTTP method (e.g., `"GET"`, `"POST"`). | -| `Headers` | `map[string]string` | Optional HTTP headers. | -| `Body` | `[]byte` | Optional raw request body. | -| `Timeout` | `*durationpb.Duration` | Optional request timeout duration. Set using `durationpb.New()`, e.g., `durationpb.New(30 * time.Second)` for 30 seconds. | -| `CacheSettings` | `*CacheSettings` | Optional caching behavior for the request. | +{/* prettier-ignore */} +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + +| <div style="width: 120px;">Field</div> | <div style="width: 200px;">Type</div> | Description | +| -------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| `Url` | `string` | The URL of the API endpoint. | +| `Method` | `string` | The HTTP method (e.g., `"GET"`, `"POST"`). | +| `Headers` | `map[string]string` | Optional HTTP headers. | +| `Body` | `[]byte` | Optional raw request body. | +| `Timeout` | `*durationpb.Duration` | Optional request timeout. See [Request Timeout](#request-timeout) below for usage, defaults, and limits. | +| `CacheSettings` | `*CacheSettings` | Optional caching behavior for the request. | + +### Request Timeout + +The `Timeout` field specifies how long to wait for an HTTP request to complete before cancelling it. + +**Format:** + +- Use `*durationpb.Duration` from the [`google.golang.org/protobuf/types/known/durationpb` package](https://pkg.go.dev/google.golang.org/protobuf/types/known/durationpb) +- Create using `durationpb.New()` with a `time.Duration` value +- Or manually construct with `&durationpb.Duration{Seconds: int64}` + +**Default and Limits:** + +- **Default**: If not specified, a default timeout of **5 seconds** is applied. +- **Maximum**: Default maximum is **10 seconds**. Requests exceeding this limit will error. + +**Pattern 1: Using `durationpb.New()`:** + +```go +import ( + "time" + "google.golang.org/protobuf/types/known/durationpb" +) + +resp, err := sendRequester.SendRequest(&http.Request{ + Url: config.ApiUrl, + Method: "GET", + Timeout: durationpb.New(8 * time.Second), // 8 second timeout +}).Await() +``` + +**Pattern 2: Parsing from config:** + +```go +import ( + "time" + "fmt" + "google.golang.org/protobuf/types/known/durationpb" +) + +type Config struct { + ApiUrl string `yaml:"apiUrl"` + TimeoutMs string `yaml:"timeout"` // e.g., "5s", "10s" +} + +func fetchData(config *Config, logger *slog.Logger, sendRequester *http.SendRequester) (string, error) { + // Parse duration string from config + t, err := time.ParseDuration(config.TimeoutMs) + if err != nil { + return "", fmt.Errorf("failed to parse duration (%s): %w", config.TimeoutMs, err) + } + + logger.Info("parsed timeout", "seconds", t.Seconds(), "raw", config.TimeoutMs) + + // Create Duration from parsed time + timeout := &durationpb.Duration{ + Seconds: int64(t.Seconds()), + } + + resp, err := sendRequester.SendRequest(&http.Request{ + Url: config.ApiUrl, + Method: "GET", + Timeout: timeout, + }).Await() + + if err != nil { + logger.Info("http request failed", "error", err) + return "", err + } + + return string(resp.Body), nil +} +``` + +**Example configuration:** + +```yaml +# config.yaml +apiUrl: "https://api.example.com/data" +timeout: "8s" # Go's time.ParseDuration format (max: 10s) +``` ### `http.Response` diff --git a/src/content/cre/reference/sdk/http-client-ts.mdx b/src/content/cre/reference/sdk/http-client-ts.mdx index eb5822a9787..1506ca5bfe9 100644 --- a/src/content/cre/reference/sdk/http-client-ts.mdx +++ b/src/content/cre/reference/sdk/http-client-ts.mdx @@ -7,7 +7,7 @@ pageId: "reference-sdk-http-client" metadata: description: "Reference for TypeScript HTTP Client: complete API for GET/POST requests, headers, authentication, and consensus aggregation." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-26" --- import { Aside } from "@components" @@ -50,7 +50,7 @@ A curried function that accepts your custom arguments and returns an object with **Example:** ```typescript -import { cre, consensusMedianAggregation, type Runtime, type HTTPSendRequester } from "@chainlink/cre-sdk" +import { HTTPClient, consensusMedianAggregation, type Runtime, type HTTPSendRequester } from "@chainlink/cre-sdk" interface Config { apiUrl: string @@ -72,7 +72,7 @@ const fetchPrice = (sendRequester: HTTPSendRequester, url: string): number => { // In your workflow const workflow = (runtime: Runtime<Config>) => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() // Call the high-level sendRequest with your custom function const price = httpClient @@ -180,11 +180,11 @@ An object with a `.result()` method that blocks until the HTTP request completes **Example:** ```typescript -import { cre, consensusMedianAggregation, type Runtime, type NodeRuntime } from "@chainlink/cre-sdk" +import { HTTPClient, consensusMedianAggregation, type Runtime, type NodeRuntime } from "@chainlink/cre-sdk" // Low-level usage with manual node mode const fetchPrice = (nodeRuntime: NodeRuntime<Config>): number => { - const httpClient = new cre.capabilities.HTTPClient() + const httpClient = new HTTPClient() const response = httpClient .sendRequest(nodeRuntime, { @@ -389,14 +389,65 @@ const fetchPrice = (sendRequester: HTTPSendRequester, url: string): number => { Defines the parameters for an outgoing HTTP request. -| Field | Type | Description | -| --------------- | ------------------------------------------------- | --------------------------------------------------------------- | -| `url` | `string` | The URL of the API endpoint. | -| `method` | `string` (optional) | The HTTP method (e.g., `"GET"`, `"POST"`). Defaults to `"GET"`. | -| `headers` | `{ [key: string]: string }` (optional) | Optional HTTP headers. | -| `body` | `string` (base64-encoded) (optional) | Optional raw request body (must be base64-encoded). | -| `timeoutMs` | `number` (optional) | Optional request timeout in milliseconds. | -| `cacheSettings` | `CacheSettings` \| `CacheSettingsJson` (optional) | Optional caching behavior for the request. | +{/* prettier-ignore */} +<Aside type="caution" title="Redirects are not supported"> + HTTP requests to URLs that return redirects (3xx status codes) will fail. Ensure the URL you provide is the final destination and does not redirect to another URL. +</Aside> + +| Field | Type | Description | +| --------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `url` | `string` | The URL of the API endpoint. | +| `method` | `string` (optional) | The HTTP method (e.g., `"GET"`, `"POST"`). Defaults to `"GET"`. | +| `headers` | `{ [key: string]: string }` (optional) | Optional HTTP headers. | +| `body` | `string` (base64-encoded) (optional) | Optional raw request body (must be base64-encoded). | +| `timeout` | `string` (optional) | Request timeout as a duration string (e.g., `"5s"`, `"8s"`). See [Request Timeout](#request-timeout) below for details. | +| `cacheSettings` | `CacheSettings` \| `CacheSettingsJson` (optional) | Optional caching behavior for the request. | + +### Request Timeout + +The `timeout` field specifies how long to wait for an HTTP request to complete before cancelling it. + +**Format:** + +- Specify timeout as a string ending with `"s"` (seconds) +- Examples: `"5s"` (5 seconds), `"8s"` (8 seconds), `"3.5s"` (3.5 seconds) + +{/* prettier-ignore */} +<Aside type="note" title="Protocol Buffers Duration"> + Under the hood, `timeout` uses the [Protocol Buffers Duration type](https://protobuf.dev/reference/protobuf/google.protobuf/#duration). In JSON format, it's encoded as a string ending with "s", where fractional seconds can represent nanosecond precision if needed. +</Aside> + +**Default and Limits:** + +- **Default**: If not specified, a default timeout of **5 seconds** is applied +- **Maximum**: Default maximum is **10 seconds**. Requests exceeding this limit will error + +**Example:** + +```typescript +type Config = { + apiUrl: string + requestTimeout: string +} + +const httpClient = new HTTPClient() + +const req = { + method: "GET", + url: config.apiUrl, + timeout: config.requestTimeout, // e.g., "8s" +} + +const response = httpClient.sendRequest(nodeRuntime, req).result() +``` + +**Example configuration:** + +```yaml +# config.yaml +apiUrl: "https://api.example.com/data" +requestTimeout: "8s" # Max: 10s +``` ### `CacheSettings` / `CacheSettingsJson` @@ -488,7 +539,7 @@ const manualData = JSON.parse(manualText) ### Simple GET request ```typescript -import { cre, consensusMedianAggregation, ok, json, type HTTPSendRequester } from "@chainlink/cre-sdk" +import { HTTPClient, consensusMedianAggregation, ok, json, type HTTPSendRequester } from "@chainlink/cre-sdk" const fetchData = (sendRequester: HTTPSendRequester, url: string): number => { const response = sendRequester.sendRequest({ url }).result() @@ -502,14 +553,14 @@ const fetchData = (sendRequester: HTTPSendRequester, url: string): number => { } // In your workflow -const httpClient = new cre.capabilities.HTTPClient() +const httpClient = new HTTPClient() const result = httpClient.sendRequest(runtime, fetchData, consensusMedianAggregation<number>())(apiUrl).result() ``` ### POST request with caching ```typescript -import { cre, consensusIdenticalAggregation, ok, json, type HTTPSendRequester } from "@chainlink/cre-sdk" +import { HTTPClient, consensusIdenticalAggregation, ok, json, type HTTPSendRequester } from "@chainlink/cre-sdk" const createResource = (sendRequester: HTTPSendRequester, payload: { name: string }): { id: string } => { // Encode the body as base64 @@ -540,7 +591,7 @@ const createResource = (sendRequester: HTTPSendRequester, payload: { name: strin } // In your workflow -const httpClient = new cre.capabilities.HTTPClient() +const httpClient = new HTTPClient() const resource = httpClient .sendRequest(runtime, createResource, consensusIdenticalAggregation<{ id: string }>())({ name: "My Resource" }) .result() @@ -552,7 +603,7 @@ For complex objects with multiple fields, use `ConsensusAggregationByFields()`: ```typescript import { - cre, + HTTPClient, ConsensusAggregationByFields, median, identical, @@ -584,7 +635,7 @@ const fetchReserveInfo = (sendRequester: HTTPSendRequester, url: string): Reserv } // In your workflow -const httpClient = new cre.capabilities.HTTPClient() +const httpClient = new HTTPClient() const reserveInfo = httpClient .sendRequest( runtime, diff --git a/src/content/cre/reference/sdk/overview-go.mdx b/src/content/cre/reference/sdk/overview-go.mdx index 6e4c27b4e4e..9179fe665b6 100644 --- a/src/content/cre/reference/sdk/overview-go.mdx +++ b/src/content/cre/reference/sdk/overview-go.mdx @@ -7,20 +7,11 @@ pageId: "reference-sdk-overview" metadata: description: "Explore the Go SDK API: complete technical reference for workflows, handlers, triggers, capabilities, and runtime methods." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside } from "@components" -<Aside type="note" title="Required SDK Version: v1.0.0"> - To ensure compatibility, please use version `v1.0.0` for the core `cre-sdk-go` package and `v1.0.0-beta.0` for capability packages. - - Always use `go get` with an explicit version tag to add dependencies:<br/> - - Core SDK: `go get github.com/smartcontractkit/cre-sdk-go@v1.0.0`<br/> - - Capabilities: `go get github.com/smartcontractkit/cre-sdk-go/capabilities/networking/http@v1.0.0-beta.0` - -</Aside> - This section provides a detailed technical reference for the public interfaces of the CRE Go SDK. Use this reference for quick lookups of specific functions, types, and method signatures. ## How to read this section @@ -31,6 +22,7 @@ The SDK Reference is broken down into several pages, each corresponding to a cor - **[Triggers](/cre/reference/sdk/triggers)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). - **[EVM Client](/cre/reference/sdk/evm-client)**: Provides a reference for the `evm.Client`, the primary tool for all EVM interactions, including reads and writes. - **[HTTP Client](/cre/reference/sdk/http-client)**: Provides a reference for the `http.Client`, used for making offchain API requests from individual nodes. +- **[Confidential HTTP Client](/cre/reference/sdk/confidential-http-client)** _(Experimental)_: Provides a reference for the `confidentialhttp.Client`, used for privacy-preserving API requests with enclave execution and optional response encryption. - **[Consensus & Aggregation](/cre/reference/sdk/consensus)**: Describes how to use aggregators like `ConsensusMedianAggregation` and `ConsensusAggregationFromTags` with `RunInNodeMode` to process and consolidate data from multiple nodes. ## Contract Bindings diff --git a/src/content/cre/reference/sdk/overview-ts.mdx b/src/content/cre/reference/sdk/overview-ts.mdx index 1e40071364c..39d4f1b7ceb 100644 --- a/src/content/cre/reference/sdk/overview-ts.mdx +++ b/src/content/cre/reference/sdk/overview-ts.mdx @@ -7,27 +7,23 @@ pageId: "reference-sdk-overview" metadata: description: "Explore the TypeScript SDK API: complete technical reference for workflows, handlers, triggers, capabilities, and runtime methods." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-02-03" --- import { Aside } from "@components" -<Aside type="note" title="Required SDK Version: v1.0.0"> - The CRE CLI automatically includes version `v1.0.0` of the `@chainlink/cre-sdk` package when you initialize a new - TypeScript workflow with `cre init`. -</Aside> - This section provides a detailed technical reference for the public interfaces of the CRE TypeScript SDK. Use this reference for quick lookups of specific functions, types, and method signatures. ## How to read this section The SDK Reference is broken down into several pages, each corresponding to a core part of the SDK's functionality: -- **[Core SDK](/cre/reference/sdk/core)**: Covers the fundamental building blocks of any workflow, including `cre.handler`, `Runtime`, and the `.result()` pattern for promise resolution. -- **[Triggers](/cre/reference/sdk/triggers)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). -- **[EVM Client](/cre/reference/sdk/evm-client)**: Provides a reference for the `cre.capabilities.EVMClient`, the primary tool for all EVM interactions, including reads and writes. -- **[HTTP Client](/cre/reference/sdk/http-client)**: Provides a reference for the `cre.capabilities.HTTPClient`, used for making offchain API requests from individual nodes. -- **[Consensus & Aggregation](/cre/reference/sdk/consensus)**: Describes how to use aggregators like `consensusMedianAggregation` and `ConsensusAggregationByFields` with `runtime.runInNodeMode()` to process and consolidate data from multiple nodes. +- **[Core SDK](/cre/reference/sdk/core-ts)**: Covers the fundamental building blocks of any workflow, including `handler`, `Runtime`, and the `.result()` pattern for promise resolution. +- **[Triggers](/cre/reference/sdk/triggers/overview-ts)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). +- **[EVM Client](/cre/reference/sdk/evm-client-ts)**: Provides a reference for the `EVMClient`, the primary tool for all EVM interactions, including reads and writes. +- **[HTTP Client](/cre/reference/sdk/http-client-ts)**: Provides a reference for the `HTTPClient`, used for making offchain API requests from individual nodes. +- **[Confidential HTTP Client](/cre/reference/sdk/confidential-http-client-ts)** _(Experimental)_: Provides a reference for the `ConfidentialHTTPClient`, used for privacy-preserving API requests with enclave execution and optional response encryption. +- **[Consensus & Aggregation](/cre/reference/sdk/consensus-ts)**: Describes how to use aggregators like `consensusMedianAggregation` and `ConsensusAggregationByFields` with `runtime.runInNodeMode()` to process and consolidate data from multiple nodes. ## Package Structure @@ -35,11 +31,20 @@ The TypeScript SDK is distributed as a single npm package `@chainlink/cre-sdk` t ```typescript import { - cre, // Main SDK namespace with capabilities + // Capabilities + CronCapability, + HTTPCapability, + HTTPClient, + EVMClient, + // Core functions + handler, // Register handlers Runner, // Workflow runner type Runtime, // Runtime interface type NodeRuntime, // Node-level runtime interface - consensusMedianAggregation, // Consensus aggregators + // Consensus + consensusMedianAggregation, + consensusIdenticalAggregation, + // Utilities getNetwork, // Chain selector utilities bytesToHex, // Data conversion utilities hexToBase64, @@ -47,6 +52,12 @@ import { } from "@chainlink/cre-sdk" ``` +<Aside type="note" title="Import styles"> + The SDK supports two import styles: **direct imports** (shown above) and **namespace imports** (e.g., + `cre.capabilities.HTTPClient`). Both are fully supported and produce identical behavior. See the [Core SDK + Reference](/cre/reference/sdk/core-ts#import-styles) for details on both patterns. +</Aside> + ## Understanding TypeScript Types The TypeScript SDK uses Protocol Buffers for type definitions, which generates two type representations for each message: diff --git a/src/content/cre/reference/sdk/triggers/cron-trigger-ts.mdx b/src/content/cre/reference/sdk/triggers/cron-trigger-ts.mdx index c2d15bf216d..9c55c43ed19 100644 --- a/src/content/cre/reference/sdk/triggers/cron-trigger-ts.mdx +++ b/src/content/cre/reference/sdk/triggers/cron-trigger-ts.mdx @@ -7,7 +7,7 @@ pageId: "reference-sdk-cron-trigger" metadata: description: "Reference for TypeScript Cron Trigger: Config interface, Payload fields, and cron expression syntax for time-based workflows." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside } from "@components" @@ -17,9 +17,9 @@ The Cron Trigger fires at a specified schedule using standard cron expressions. ## Creating the trigger ```typescript -import { cre } from "@chainlink/cre-sdk" +import { CronCapability } from "@chainlink/cre-sdk" -const cron = new cre.capabilities.CronCapability() +const cron = new CronCapability() const trigger = cron.trigger({ schedule: "0 */10 * * * *" }) // Every 10 minutes ``` @@ -107,7 +107,7 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = ## Complete Example ```typescript -import { cre, Runner, type Runtime, type CronPayload } from "@chainlink/cre-sdk" +import { CronCapability, handler, Runner, type Runtime, type CronPayload } from "@chainlink/cre-sdk" type Config = { schedule: string @@ -119,15 +119,13 @@ const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): string = } const initWorkflow = (config: Config) => { - const cron = new cre.capabilities.CronCapability() + const cron = new CronCapability() - return [cre.handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] + return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)] } export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` diff --git a/src/content/cre/reference/sdk/triggers/evm-log-trigger-go.mdx b/src/content/cre/reference/sdk/triggers/evm-log-trigger-go.mdx index 7e910e653db..40b7ce80bae 100644 --- a/src/content/cre/reference/sdk/triggers/evm-log-trigger-go.mdx +++ b/src/content/cre/reference/sdk/triggers/evm-log-trigger-go.mdx @@ -61,9 +61,9 @@ The configuration struct for the EVM log trigger. | `Topics` | `[]*evm.TopicValues` | A fixed 4-element array to filter event topics. The first element contains event signatures, and the next three elements contain indexed argument values. An empty array element acts as a wildcard. | | `Confidence` | `ConfidenceLevel` | The block confirmation level to monitor. Can be: <ul><li>**`evm.ConfidenceLevel_CONFIDENCE_LEVEL_SAFE` (default):** A block that is considered unlikely to be reorged but is not yet irreversible.</li><li>**`evm.ConfidenceLevel_CONFIDENCE_LEVEL_LATEST`:** The most recent block. This is the fastest but least secure, as the block could be orphaned. Best for non-critical, time-sensitive actions.</li><li>**`evm.ConfidenceLevel_CONFIDENCE_LEVEL_FINALIZED`:** A block that is considered irreversible. This is the safest option, as the event is guaranteed to be on the canonical chain, but it requires waiting longer for finality.</li></ul> | -{/* prettier-ignore */} -<Aside type="caution" title="SAFE block tag fallback"> - **Some chains do not support the SAFE block tag** (e.g., Shibarium). When you specify `CONFIDENCE_LEVEL_SAFE` on chains that don't support it, CRE automatically falls back to `CONFIDENCE_LEVEL_FINALIZED` for safety. Users are responsible for knowing which chains support the SAFE tag. If you need consistent behavior across all chains, explicitly use `CONFIDENCE_LEVEL_FINALIZED` or `CONFIDENCE_LEVEL_LATEST`. +<Aside type="note" title="Finality details"> + For details on how each confidence level maps to specific chains and estimated wait times, see [Finality and + Confidence Levels](/cre/concepts/finality). </Aside> ### `evm.Log` diff --git a/src/content/cre/reference/sdk/triggers/evm-log-trigger-ts.mdx b/src/content/cre/reference/sdk/triggers/evm-log-trigger-ts.mdx index 5bdfc650768..8caccb57096 100644 --- a/src/content/cre/reference/sdk/triggers/evm-log-trigger-ts.mdx +++ b/src/content/cre/reference/sdk/triggers/evm-log-trigger-ts.mdx @@ -7,7 +7,7 @@ pageId: "reference-sdk-evm-log-trigger" metadata: description: "Reference for TypeScript EVM Log Trigger: Config interface, Payload fields, and topic filtering for event-driven workflows." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-28" --- import { Aside } from "@components" @@ -16,8 +16,16 @@ The EVM Log Trigger fires when a specific log (event) is emitted by an onchain s ## Creating the trigger +<Aside type="note" title="Base64 Encoding Required"> + **All addresses and topic values must be base64 encoded** using the `hexToBase64()` helper function from the CRE SDK. + While the workflow simulator accepts raw hex strings for convenience during development, **deployed workflows require + base64 encoding**. Always use `hexToBase64()` on addresses and topic values to ensure your workflow works in both + simulation and production. +</Aside> + ```typescript -import { cre } from "@chainlink/cre-sdk" +import { EVMClient, getNetwork, hexToBase64 } from "@chainlink/cre-sdk" +import { keccak256, toBytes } from "viem" // Create an EVMClient instance with a chain selector const network = getNetwork({ @@ -26,22 +34,16 @@ const network = getNetwork({ isTestnet: true, }) -const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) +const evmClient = new EVMClient(network.chainSelector.selector) -// Basic log trigger for a contract address -const trigger = evmClient.logTrigger({ - addresses: ["0x123...abc"], -}) +// Create a log trigger with address and event signature +const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) -// With topics for event filtering const trigger = evmClient.logTrigger({ - addresses: ["0x123...abc"], + addresses: [hexToBase64("0x123...abc")], topics: [ { - values: [ - // Keccak256 hash of "Transfer(address,address,uint256)" - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - ], + values: [hexToBase64(transferEventHash)], }, ], }) @@ -53,22 +55,22 @@ The `logTrigger()` method accepts a configuration object with the following fiel | <div style="width: 100px;">Field</div> | <div style="width: 140px;">Type</div> | Description | | -------------------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `addresses` | `string[]` | A list of contract addresses to monitor (as hex strings, e.g., `"0x..."`). At least one address is required. | -| `topics` | `TopicValues[]` | Optional. A fixed 4-element array to filter event topics. The first element contains event signatures, and the next three elements contain indexed argument values. An empty array element acts as a wildcard. | +| `addresses` | `string[]` | **Required.** A list of contract addresses to monitor. **Must be base64 encoded** using `hexToBase64()`. At least one address is required. | +| `topics` | `TopicValues[]` | **Required.** An array to filter event topics. The first element must contain at least one event signature. The next three elements can contain indexed argument values (optional). An empty array element acts as a wildcard for indexed arguments. **All topic values must be base64 encoded** using `hexToBase64()`. | | `confidence` | `string` | Optional. The block confirmation level to monitor. Can be: <ul><li>**`"CONFIDENCE_LEVEL_LATEST"`**: The most recent block (fastest but least secure).</li><li>**`"CONFIDENCE_LEVEL_SAFE"` (default)**: A block unlikely to be reorged but not yet irreversible.</li><li>**`"CONFIDENCE_LEVEL_FINALIZED"`**: A block considered irreversible (safest, but requires waiting longer for finality).</li></ul> | -{/* prettier-ignore */} -<Aside type="caution" title="SAFE block tag fallback"> - **Some chains do not support the SAFE block tag** (e.g., Shibarium). When you specify `"CONFIDENCE_LEVEL_SAFE"` on chains that don't support it, CRE automatically falls back to `"CONFIDENCE_LEVEL_FINALIZED"` for safety. Users are responsible for knowing which chains support the SAFE tag. If you need consistent behavior across all chains, explicitly use `"CONFIDENCE_LEVEL_FINALIZED"` or `"CONFIDENCE_LEVEL_LATEST"`. +<Aside type="note" title="Finality details"> + For details on how each confidence level maps to specific chains and estimated wait times, see [Finality and + Confidence Levels](/cre/concepts/finality). </Aside> ### `TopicValues` The `topics` array uses a special format for filtering events: -| Field | Type | Description | -| -------- | ---------- | --------------------------------------------------- | -| `values` | `string[]` | Array of possible values for a topic (hex strings). | +| Field | Type | Description | +| -------- | ---------- | --------------------------------------------------------------------------------------- | +| `values` | `string[]` | Array of possible values for a topic. **Must be base64 encoded** using `hexToBase64()`. | **Topic array structure:** @@ -77,19 +79,37 @@ The `topics` array uses a special format for filtering events: - **`topics[2]`**: Optional. Values for the second indexed argument. Can be empty (wildcard). - **`topics[3]`**: Optional. Values for the third indexed argument. Can be empty (wildcard). +<Aside type="caution" title="Topic values must be padded to 32 bytes and base64 encoded"> +EVM logs always store indexed parameters as **32-byte values**. When filtering on topics 1, 2, or 3: + +1. **Pad your values to 32 bytes** using `padHex(value, { size: 32 })` from viem (e.g., addresses are 20 bytes and must be padded) +1. **Convert to base64** using `hexToBase64()` from the CRE SDK + +If you don't pad correctly, your filter won't match the actual log topics and the trigger will not fire. + +Topic 0 (the event signature from `keccak256`) is already 32 bytes and doesn't need padding. + +</Aside> + **Example:** ```typescript +import { hexToBase64 } from "@chainlink/cre-sdk" +import { keccak256, toBytes, padHex } from "viem" + +const transferEventHash = keccak256(toBytes("Transfer(address,address,uint256)")) +const fromAddress = "0xabcdef..." as `0x${string}` + const trigger = evmClient.logTrigger({ - addresses: ["0x1234567890abcdef..."], + addresses: [hexToBase64("0x1234567890abcdef...")], topics: [ - // Topic 0: Event signature (Transfer event) + // Topic 0: Event signature (Transfer event) - already 32 bytes { - values: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"], + values: [hexToBase64(transferEventHash)], }, - // Topic 1: From address (indexed parameter 1) + // Topic 1: From address (indexed parameter 1) - must pad from 20 to 32 bytes { - values: ["0x000000000000000000000000abcdef..."], + values: [hexToBase64(padHex(fromAddress, { size: 32 }))], }, // Topic 2: Empty (wildcard for any "to" address) { @@ -196,7 +216,16 @@ const onLogTrigger = (runtime: Runtime<Config>, log: EVMLog): string => { ## Complete Example ```typescript -import { cre, bytesToHex, getNetwork, Runner, type Runtime, type EVMLog } from "@chainlink/cre-sdk" +import { + EVMClient, + handler, + bytesToHex, + getNetwork, + Runner, + hexToBase64, + type Runtime, + type EVMLog, +} from "@chainlink/cre-sdk" type Config = { chainSelectorName: string @@ -231,12 +260,12 @@ const initWorkflow = (config: Config) => { throw new Error(`Network not found: ${config.chainSelectorName}`) } - const evmClient = new cre.capabilities.EVMClient(network.chainSelector.selector) + const evmClient = new EVMClient(network.chainSelector.selector) return [ - cre.handler( + handler( evmClient.logTrigger({ - addresses: [config.contractAddress], + addresses: [hexToBase64(config.contractAddress)], }), onLogTrigger ), @@ -247,8 +276,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Decoding Log Data @@ -274,10 +301,3 @@ const onLogTrigger = (runtime: Runtime<Config>, log: EVMLog): string => { return "Log decoded" } ``` - -<Aside type="note" title="Using contract ABIs"> - For type-safe event handling, organize your contract ABIs in separate TypeScript files (e.g., - `contracts/abi/MyContract.ts`) as demonstrated in the [demo - workflow](https://github.com/smartcontractkit/cre-cli/tree/main/examples/proof-of-reserve). Define ABIs as `const` - arrays with full JSON ABI structures for optimal TypeScript type inference with viem. -</Aside> diff --git a/src/content/cre/reference/sdk/triggers/http-trigger-ts.mdx b/src/content/cre/reference/sdk/triggers/http-trigger-ts.mdx index 0163df73013..ad8530e6cb9 100644 --- a/src/content/cre/reference/sdk/triggers/http-trigger-ts.mdx +++ b/src/content/cre/reference/sdk/triggers/http-trigger-ts.mdx @@ -7,7 +7,7 @@ pageId: "reference-sdk-http-trigger" metadata: description: "Reference for TypeScript HTTP Trigger: Config interface, Payload fields, and authorization setup for request-based workflows." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside } from "@components" @@ -17,9 +17,9 @@ The HTTP Trigger fires when an HTTP request is made to the workflow's designated ## Creating the trigger ```typescript -import { cre } from "@chainlink/cre-sdk" +import { HTTPCapability } from "@chainlink/cre-sdk" -const http = new cre.capabilities.HTTPCapability() +const http = new HTTPCapability() // Basic trigger (no authorization) const trigger = http.trigger({}) @@ -154,7 +154,7 @@ const onHttpTrigger = (runtime: Runtime<Config>, payload: HTTPPayload): string = ## Complete Example ```typescript -import { cre, decodeJson, Runner, type Runtime, type HTTPPayload } from "@chainlink/cre-sdk" +import { HTTPCapability, handler, decodeJson, Runner, type Runtime, type HTTPPayload } from "@chainlink/cre-sdk" type Config = { publicKey: string @@ -172,10 +172,10 @@ const onHttpTrigger = (runtime: Runtime<Config>, payload: HTTPPayload): string = } const initWorkflow = (config: Config) => { - const http = new cre.capabilities.HTTPCapability() + const http = new HTTPCapability() return [ - cre.handler( + handler( http.trigger({ authorizedKeys: [ { @@ -193,8 +193,6 @@ export async function main() { const runner = await Runner.newRunner<Config>() await runner.run(initWorkflow) } - -main() ``` ## Testing HTTP Triggers diff --git a/src/content/cre/release-notes.mdx b/src/content/cre/release-notes.mdx index 60e6f9893c4..847b2bac97b 100644 --- a/src/content/cre/release-notes.mdx +++ b/src/content/cre/release-notes.mdx @@ -5,18 +5,176 @@ date: Last Modified metadata: description: "Discover what's new in CRE: latest features, changes, and improvements in each release of the Chainlink Runtime Environment." datePublished: "2025-11-04" - lastModified: "2025-11-20" + lastModified: "2026-02-10" --- import { Aside } from "@components" This page provides detailed release notes for CRE. It includes information on new features, significant changes, and known limitations. +## CLI v1.0.10 - February 9, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.10" target="_blank">CRE CLI version 1.0.10</a> is now available.** + +- **Bug Fix**: Fixed secret injection for the [Confidential HTTP](/cre/capabilities/confidential-http) capability in the simulator — template placeholders (`{{.secretName}}`) now resolve correctly during `cre workflow simulate` +- **Bug Fix**: Fixed project context not being set before writing changeset files + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.9...v1.0.10) + +## CLI v1.0.9 - February 6, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.9" target="_blank">CRE CLI version 1.0.9</a> is now available.** + +- **Confidential HTTP (Experimental)**: Added [Confidential HTTP](/cre/capabilities/confidential-http) capability support in the simulator. You can now simulate workflows that use privacy-preserving API calls with secret injection and optional response encryption. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.8...v1.0.9) + +## CLI v1.0.8 - February 6, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.8" target="_blank">CRE CLI version 1.0.8</a> is now available.** + +- Changed `chain-id` to `chain-selector` in simulator settings +- Support for longer workflow names +- Fixed a logic bug in the template contract `MessageEmitter.sol` + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.7...v1.0.8) + +## New Networks Support - January 29, 2026 + +CRE now supports additional testnets for workflow simulation and production deployment: + +- Apechain Curtis +- Arc Testnet +- Hyperliquid Testnet +- Ink Sepolia +- Jovay Testnet +- Linea Sepolia +- Plasma Testnet +- World Chain Sepolia + +**Required versions:** CLI v1.0.7+, Go SDK v1.1.4+, TS SDK v1.0.7+ + +## CLI v1.0.7 - January 29, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.7" target="_blank">CRE CLI version 1.0.7</a> is now available.** + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.0.6...v1.0.7) + +## TS SDK v1.0.7 - January 29, 2026 + +**TypeScript SDK version 1.0.7** includes internal improvements. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.5...v1.0.7) + +## TS SDK v1.0.5 - January 28, 2026 + +- **Bug Fix**: Fixed an issue with `runtime.now()` returning incorrect timestamps + +For details on using time in workflows, see [Time in CRE](/cre/guides/workflow/time-in-workflows-ts). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.4...v1.0.5) + +## ZKSync Era Support - January 26, 2026 + +CRE now supports **ZKSync Era mainnet and testnet** for workflow simulation and production deployment. You can now build and test workflows that interact with ZKSync Era chains. + +**Required versions:** CLI v1.0.6+, Go SDK v1.1.3+ (mainnet) / v1.1.2+ (testnet), TS SDK v1.0.7+ + +## TS SDK v1.0.4 - January 26, 2026 + +**TypeScript SDK version 1.0.4** includes internal improvements. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.3...v1.0.4) + +## CLI v1.0.6 - January 21, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.6" target="_blank">CRE CLI version 1.0.6</a> is now available.** + +- **ZKSync Era support**: Added ZKSync Era testnet and mainnet to the simulator + +This release also includes various small improvements and bug fixes, such as better error messages when hitting workflow limits. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +## TS SDK v1.0.3 - January 19, 2026 + +- **Bug Fixes**: Fixed issue where workflows could execute twice during simulation + +- **Examples Updated**: All workflow examples in the SDK repository now use **direct imports** (e.g., `import { HTTPClient } from "@chainlink/cre-sdk"`) instead of the namespace pattern (e.g., `cre.capabilities.HTTPClient`). Both patterns remain fully supported—choose whichever fits your coding style. See [Import styles](/cre/reference/sdk/core-ts#import-styles) for details. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.2...v1.0.3) + +## TS SDK v1.0.2 - January 16, 2026 + +**TypeScript SDK version 1.0.2** introduces several improvements to developer experience: + +**New features:** + +- **Optional `main()` call**: You no longer need to call `main()` at the end of your workflow files. The SDK now automatically executes the `main()` function during compilation. See [`main()` reference](/cre/reference/sdk/core-ts#main) for details. +- **Automatic error handling**: If you don't provide custom error handling, the SDK automatically adds `.catch(sendErrorResponse)` to your workflow's `main()` function. This ensures errors are properly reported instead of silently failing. +- **Direct imports**: You can now import SDK components directly (e.g., `import { HTTPClient } from "@chainlink/cre-sdk"`) instead of accessing them through the `cre` namespace (e.g., `cre.capabilities.HTTPClient`). Both import styles remain supported for backward compatibility. See [Import styles](/cre/reference/sdk/core-ts#import-styles) for details and guidance on when to use each pattern. + +**Migration notes:** + +- **Custom error handling**: If you need custom error handling, you can still add your own `.catch()` handler: `main().catch(myCustomHandler)`. The SDK will respect your custom handler and not override it. See [`main()` reference](/cre/reference/sdk/core-ts#main) for examples. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.1...v1.0.2) + +## CLI v1.0.5 - January 13, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.5" target="_blank">CRE CLI version 1.0.5</a> is now available.** This release includes various small improvements and bug fixes. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +## CLI v1.0.4 - January 9, 2026 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.4" target="_blank">CRE CLI version 1.0.4</a> is now available.** This release includes various small improvements and bug fixes. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +## CLI v1.0.3 - December 12, 2025 + +**<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.3" target="_blank">CRE CLI version 1.0.3</a> is now available.** This release includes various small improvements and bug fixes. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + ## CLI v1.0.2 - November 20, 2025 **<a href="https://github.com/smartcontractkit/cre-cli/releases/tag/v1.0.2" target="_blank">CRE CLI version 1.0.2</a> is now available.** This release includes various improvements based on user feedback. -### How to update +**How to update:** - **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. - **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). diff --git a/src/content/cre/service-quotas.mdx b/src/content/cre/service-quotas.mdx index 28ad41142f0..630beb53a6e 100644 --- a/src/content/cre/service-quotas.mdx +++ b/src/content/cre/service-quotas.mdx @@ -5,7 +5,7 @@ date: Last Modified metadata: description: "Understand CRE service quotas for your workflows: execution timeouts, trigger rates, WASM resources, and organization constraints." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2025-12-18" --- import { Aside } from "@components" @@ -20,15 +20,10 @@ This page documents the service quotas for Chainlink Runtime Environment (CRE) w These quotas apply to each workflow owner (user account) within an organization. -| Quota | Description | <div style="width: 150px;">Value</div> | -| ------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------- | -| Workflow Deployment Rate | Maximum rate at which an organization can deploy new workflows | Rate: 1 per minute <br/> Burst: 1 | -| Concurrent Workflow Executions | Maximum number of workflows that can execute simultaneously | 5 | -| Workflow Trigger Rate | Maximum rate at which triggers can fire for all workflows owned by a single owner (user account) | Rate: 5 per second <br /> Burst: 5 | -| Workflow Binary Size | Maximum size of the compiled WASM binary | 100 MB | -| Workflow Compressed Binary Size | Maximum size of the compressed WASM binary | 20 MB | -| Workflow Configuration Size | Maximum size of the workflow configuration | 1 MB | -| Secrets Size | Maximum total size of secrets accessible to a workflow | 1 MB | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | ----- | +| <a href="#perowner-workflowexecutionconcurrencylimit" id="perowner-workflowexecutionconcurrencylimit">`PerOwner.WorkflowExecutionConcurrencyLimit`</a> | Maximum number of workflows that can execute simultaneously | 5 | +| <a href="#perowner-vaultsecretslimit" id="perowner-vaultsecretslimit">`PerOwner.VaultSecretsLimit`</a> | Maximum number of secrets that can be stored per owner | 100 | <Aside type="note" title="Quota enforcement"> When workflow executions exceed the quotas defined above, they are queued and automatically retried for up to 10 @@ -39,57 +34,64 @@ These quotas apply to each workflow owner (user account) within an organization. These quotas apply to each individual workflow. +### Workflow deployment quotas + +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------ | +| <a href="#perworkflow-wasmbinarysizelimit" id="perworkflow-wasmbinarysizelimit">`PerWorkflow.WASMBinarySizeLimit`</a> | Maximum size of the compiled WASM binary | 100 MB | +| <a href="#perworkflow-wasmcompressedbinarysizelimit" id="perworkflow-wasmcompressedbinarysizelimit">`PerWorkflow.WASMCompressedBinarySizeLimit`</a> | Maximum size of the compressed WASM binary | 20 MB | +| <a href="#perworkflow-wasmconfigsizelimit" id="perworkflow-wasmconfigsizelimit">`PerWorkflow.WASMConfigSizeLimit`</a> | Maximum size of the workflow configuration | 1 MB | + ### Trigger quotas -| Quota | Description | <div style="width: 160px;">Value</div> | -| ----------------------------- | ---------------------------------------------------------------------- | -------------------------------------- | -| Trigger Rate | Maximum rate at which a workflow's triggers can fire | Rate: 1 per 30 seconds <br /> Burst: 3 | -| Maximum Triggers per Workflow | Maximum number of triggers that can be registered to a single workflow | 10 | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | ----- | +| <a href="#perworkflow-triggersubscriptionlimit" id="perworkflow-triggersubscriptionlimit">`PerWorkflow.TriggerSubscriptionLimit`</a> | Maximum number of triggers that can be registered to a single workflow | 10 | ### Execution quotas -| Quota | Description | <div style="width: 150px;">Value</div> | -| ----------------------------- | --------------------------------------------------------------- | -------------------------------------- | -| Concurrent Workflow Instances | Maximum number of concurrent executions for a specific workflow | 5 <br /> Burst: 5 | -| Workflow Timeout | Maximum total execution time for a single workflow run | 5 minutes | -| Workflow Memory Allocation | Maximum memory allocated to a workflow | 100 MB | -| Response Size | Maximum size of the data a workflow can return | 100 KB | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | --------- | +| <a href="#perworkflow-executionconcurrencylimit" id="perworkflow-executionconcurrencylimit">`PerWorkflow.ExecutionConcurrencyLimit`</a> | Maximum number of concurrent executions for a specific workflow | 5 | +| <a href="#perworkflow-executiontimeout" id="perworkflow-executiontimeout">`PerWorkflow.ExecutionTimeout`</a> | Maximum total execution time for a single workflow run | 5 minutes | +| <a href="#perworkflow-wasmmemorylimit" id="perworkflow-wasmmemorylimit">`PerWorkflow.WASMMemoryLimit`</a> | Maximum memory allocated to a workflow | 100 MB | +| <a href="#perworkflow-executionresponselimit" id="perworkflow-executionresponselimit">`PerWorkflow.ExecutionResponseLimit`</a> | Maximum size of the data a workflow can return | 100 KB | -### Capability call quotas +### General capability quotas -| Quota | Description | <div style="width: 150px;">Value</div> | -| --------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------- | -| Concurrent Capability Calls | Maximum concurrent capability calls (HTTP, EVM read/write, secrets) that can execute within a workflow | 3 | -| Capability Call Timeout | Maximum time a single capability call can take to complete | 3 minutes | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | --------- | +| <a href="#perworkflow-capabilityconcurrencylimit" id="perworkflow-capabilityconcurrencylimit">`PerWorkflow.CapabilityConcurrencyLimit`</a> | Maximum concurrent capability calls (HTTP, EVM read/write, secrets) that can execute within a workflow | 3 | +| <a href="#perworkflow-capabilitycalltimeout" id="perworkflow-capabilitycalltimeout">`PerWorkflow.CapabilityCallTimeout`</a> | Maximum time a single capability call can take to complete | 3 minutes | ### Secrets quotas -| Quota | Description | <div style="width: 150px;">Value</div> | -| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | -| Secrets Size | Maximum total size of secrets accessible to a workflow | 1 MB | -| Concurrent Secrets Fetches | Maximum number of secrets that can be fetched concurrently. [Learn how to fetch multiple secrets](/cre/guides/workflow/secrets). | 5 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----- | +| <a href="#perworkflow-wasmsecreetssizelimit" id="perworkflow-wasmsecreetssizelimit">`PerWorkflow.WASMSecretsSizeLimit`</a> | Maximum total size of secrets accessible to a workflow | 1 MB | +| <a href="#perworkflow-secretsconcurrencylimit" id="perworkflow-secretsconcurrencylimit">`PerWorkflow.SecretsConcurrencyLimit`</a> | Maximum number of secrets that can be fetched concurrently. [Learn how to fetch multiple secrets](/cre/guides/workflow/secrets). | 5 | ### Consensus quotas -| Quota | Description | <div style="width: 150px;">Value</div> | -| --------------------- | ---------------------------------------------------------------- | -------------------------------------- | -| Observation Size | Maximum size of data that can be passed to consensus aggregation | 100 KB | -| Total Consensus Calls | Maximum number of consensus calls per workflow execution | 2,000 | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | ----- | +| <a href="#perworkflow-consensus-observationsizelimit" id="perworkflow-consensus-observationsizelimit">`PerWorkflow.Consensus.ObservationSizeLimit`</a> | Maximum size of data that can be passed to consensus aggregation | 25 KB | +| <a href="#perworkflow-consensus-calllimit" id="perworkflow-consensus-calllimit">`PerWorkflow.Consensus.CallLimit`</a> | Maximum number of consensus calls per workflow execution | 2,000 | ### Logging quotas -| Quota | Description | <div style="width: 150px;">Value</div> | -| ------------- | --------------------------------------------------- | -------------------------------------- | -| Log Line Size | Maximum size of a single log line | 1 KB | -| Log Events | Maximum number of log events per workflow execution | 1,000 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ----- | +| <a href="#perworkflow-loglinelimit" id="perworkflow-loglinelimit">`PerWorkflow.LogLineLimit`</a> | Maximum size of a single log line | 1 KB | +| <a href="#perworkflow-logeventlimit" id="perworkflow-logeventlimit">`PerWorkflow.LogEventLimit`</a> | Maximum number of log events per workflow execution | 1,000 | ## Trigger-specific quotas ### Cron trigger -| Quota | Description | <div style="width: 150px;">Value</div> | -| ------------ | --------------------------------------------- | -------------------------------------- | -| Trigger Rate | Maximum rate at which a cron trigger can fire | Rate: 1 per 30 seconds <br /> Burst: 1 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ---------- | +| <a href="#perworkflow-crontrigger-fastestscheduleinterval" id="perworkflow-crontrigger-fastestscheduleinterval">`PerWorkflow.CRONTrigger.FastestScheduleInterval`</a> | Minimum interval between cron trigger fires | 30 seconds | <Aside type="note" title="Minimum cron schedule"> While the rate quota allows firing once per 30 seconds, you should consider the [Concurrent Workflow @@ -98,47 +100,46 @@ These quotas apply to each individual workflow. ### HTTP trigger -| Quota | Description | <div style="width: 150px;">Value</div> | -| ------------ | ---------------------------------------------- | -------------------------------------- | -| Trigger Rate | Maximum rate at which an HTTP trigger can fire | Rate: 1 per 30 seconds <br /> Burst: 3 | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | -------------------------------------- | +| <a href="#perworkflow-httptrigger-ratelimit" id="perworkflow-httptrigger-ratelimit">`PerWorkflow.HTTPTrigger.RateLimit`</a> | Maximum rate at which an HTTP trigger can fire | Rate: 1 per 30 seconds <br /> Burst: 3 | ### EVM log trigger -| Quota | Description | <div style="width: 150px;">Value</div> | -| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------- | -| Maximum Log Triggers | Maximum number of EVM log triggers per workflow | 5 | -| Event Rate | Maximum rate at which log events can be processed | Rate: 10 per 6 seconds <br /> Burst: 10 | -| Filter Addresses | Maximum number of contract addresses that can be monitored | 5 | -| Filter Topics per Slot | Maximum number of topic values that can be specified within a single topic position (Topics[0], Topics[1], Topics[2], or Topics[3]). [Learn about topic filtering](/cre/guides/workflow/using-triggers/evm-log-trigger). | 10 | -| Event Size | Maximum size of a single log event | 5 KB | +| Quota Key | Description | Value | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------- | +| <a href="#perworkflow-logtrigger-eventratelimit" id="perworkflow-logtrigger-eventratelimit">`PerWorkflow.LogTrigger.EventRateLimit`</a> | Maximum rate at which log events can be processed | Rate: 10 per 6 seconds <br /> Burst: 10 | +| <a href="#perworkflow-logtrigger-filteraddresslimit" id="perworkflow-logtrigger-filteraddresslimit">`PerWorkflow.LogTrigger.FilterAddressLimit`</a> | Maximum number of contract addresses that can be monitored | 5 | +| <a href="#perworkflow-logtrigger-filtertopicsperslotlimit" id="perworkflow-logtrigger-filtertopicsperslotlimit">`PerWorkflow.LogTrigger.FilterTopicsPerSlotLimit`</a> | Maximum number of topic values that can be specified within a single topic position (Topics[0], Topics[1], Topics[2], or Topics[3]). [Learn about topic filtering](/cre/guides/workflow/using-triggers/evm-log-trigger). | 10 | +| <a href="#perworkflow-logtrigger-eventsizelimit" id="perworkflow-logtrigger-eventsizelimit">`PerWorkflow.LogTrigger.EventSizeLimit`</a> | Maximum size of a single log event | 5 KB | ## Capability-specific quotas ### EVM write capability -| Quota | Description | <div style="width: 150px;">Value</div> | -| --------------------- | --------------------------------------------------------- | -------------------------------------- | -| Target Chains | Maximum number of destination chains for write operations | 10 | -| Report Size | Maximum size of a report payload | 5 KB | -| Transaction Gas Quota | Gas quota per EVM transaction | 5,000,000 | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | --------- | +| <a href="#perworkflow-chainwrite-targetslimit" id="perworkflow-chainwrite-targetslimit">`PerWorkflow.ChainWrite.TargetsLimit`</a> | Maximum number of destination chains for write operations | 10 | +| <a href="#perworkflow-chainwrite-reportsizelimit" id="perworkflow-chainwrite-reportsizelimit">`PerWorkflow.ChainWrite.ReportSizeLimit`</a> | Maximum size of a report payload | 5 KB | +| <a href="#perworkflow-chainwrite-evm-transactiongaslimit" id="perworkflow-chainwrite-evm-transactiongaslimit">`PerWorkflow.ChainWrite.EVM.TransactionGasLimit`</a> | Gas quota per EVM transaction | 5,000,000 | ### EVM read capability -| Quota | Description | <div style="width: 150px;">Value</div> | -| ------------------------ | ---------------------------------------------------------------- | -------------------------------------- | -| Read Calls per Execution | Maximum number of EVM read calls per workflow execution | 10 | -| Log Query Block Quota | Maximum number of blocks that can be queried for historical logs | 100 | -| Payload Size | Maximum size of an EVM read request payload | 5 KB | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | ----- | +| <a href="#perworkflow-chainread-calllimit" id="perworkflow-chainread-calllimit">`PerWorkflow.ChainRead.CallLimit`</a> | Maximum number of EVM read calls per workflow execution | 10 | +| <a href="#perworkflow-chainread-logqueryblocklimit" id="perworkflow-chainread-logqueryblocklimit">`PerWorkflow.ChainRead.LogQueryBlockLimit`</a> | Maximum number of blocks that can be queried for historical logs | 100 | +| <a href="#perworkflow-chainread-payloadsizelimit" id="perworkflow-chainread-payloadsizelimit">`PerWorkflow.ChainRead.PayloadSizeLimit`</a> | Maximum size of an EVM read request payload | 5 KB | ### HTTP capability -| Quota | Description | <div style="width: 150px;">Value</div> | -| ------------------------ | ------------------------------------------------------ | -------------------------------------- | -| HTTP Calls per Execution | Maximum number of HTTP requests per workflow execution | 5 | -| Response Size | Maximum size of an HTTP response | 10 KB | -| Connection Timeout | Maximum time to establish an HTTP connection | 10 seconds | -| Request Size | Maximum size of an HTTP request payload | 100 KB | -| Cache Age | Maximum time HTTP responses can be cached | 10 minutes | +| Quota Key | Description | Value | +| ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------ | ---------- | +| <a href="#perworkflow-httpaction-calllimit" id="perworkflow-httpaction-calllimit">`PerWorkflow.HTTPAction.CallLimit`</a> | Maximum number of HTTP requests per workflow execution | 5 | +| <a href="#perworkflow-httpaction-responsesizelimit" id="perworkflow-httpaction-responsesizelimit">`PerWorkflow.HTTPAction.ResponseSizeLimit`</a> | Maximum size of an HTTP response | 100 KB | +| <a href="#perworkflow-httpaction-connectiontimeout" id="perworkflow-httpaction-connectiontimeout">`PerWorkflow.HTTPAction.ConnectionTimeout`</a> | Maximum time to establish an HTTP connection | 10 seconds | +| <a href="#perworkflow-httpaction-requestsizelimit" id="perworkflow-httpaction-requestsizelimit">`PerWorkflow.HTTPAction.RequestSizeLimit`</a> | Maximum size of an HTTP request payload | 10 KB | +| <a href="#perworkflow-httpaction-cacheagelimit" id="perworkflow-httpaction-cacheagelimit">`PerWorkflow.HTTPAction.CacheAgeLimit`</a> | Maximum time HTTP responses can be cached | 10 minutes | ## Quota increases diff --git a/src/content/cre/supported-networks-go.mdx b/src/content/cre/supported-networks-go.mdx new file mode 100644 index 00000000000..3c85dac359a --- /dev/null +++ b/src/content/cre/supported-networks-go.mdx @@ -0,0 +1,58 @@ +--- +section: cre +title: "Supported Networks" +date: Last Modified +sdkLang: "go" +pageId: "supported-networks" +metadata: + description: "View all EVM networks supported by CRE workflows, including required CLI and SDK versions for each network." + datePublished: "2026-02-03" + lastModified: "2026-02-03" +--- + +This page lists all EVM-compatible networks supported by CRE workflows, along with the minimum CLI and SDK versions required for each network. + +## Version Requirements + +Network support depends on your CLI and SDK versions. The tables below show the minimum versions required for each network. + +- **New projects:** Run `cre update` to get the latest CLI, which includes compatible SDK versions. +- **Existing projects:** You may need to update your SDK dependency. See [Updating Dependencies](/cre/reference/project-configuration-go#5-updating-dependencies) for instructions. + +## Mainnets + +| Network | CLI | Go SDK | TS SDK | +| ------------ | ------ | ------ | ------ | +| Arbitrum One | v1.0.0 | v1.0.0 | v1.0.1 | +| Avalanche | v1.0.0 | v1.0.0 | v1.0.1 | +| Base | v1.0.0 | v1.0.0 | v1.0.1 | +| BNB Chain | v1.0.0 | v1.0.0 | v1.0.1 | +| Ethereum | v1.0.0 | v1.0.0 | v1.0.1 | +| OP Mainnet | v1.0.0 | v1.0.0 | v1.0.1 | +| Polygon | v1.0.0 | v1.0.0 | v1.0.1 | +| ZKSync Era | v1.0.6 | v1.1.3 | v1.0.7 | + +## Testnets + +| Network | CLI | Go SDK | TS SDK | +| ------------------- | ------ | ------ | ------ | +| Apechain Curtis | v1.0.7 | v1.1.4 | v1.0.7 | +| Arc Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Arbitrum Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Avalanche Fuji | v1.0.0 | v1.0.0 | v1.0.1 | +| Base Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| BNB Chain Testnet | v1.0.0 | v1.0.0 | v1.0.1 | +| Ethereum Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Hyperliquid Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Ink Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| Jovay Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Linea Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| OP Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Plasma Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Polygon Amoy | v1.0.0 | v1.0.0 | v1.0.1 | +| World Chain Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| ZKSync Era Sepolia | v1.0.6 | v1.1.2 | v1.0.7 | + +## Forwarder Addresses + +For forwarder contract addresses and chain names, see the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). Forwarder addresses are used when building consumer contracts that receive workflow reports onchain. Learn more about [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview). diff --git a/src/content/cre/supported-networks-ts.mdx b/src/content/cre/supported-networks-ts.mdx new file mode 100644 index 00000000000..9075cce2d68 --- /dev/null +++ b/src/content/cre/supported-networks-ts.mdx @@ -0,0 +1,58 @@ +--- +section: cre +title: "Supported Networks" +date: Last Modified +sdkLang: "ts" +pageId: "supported-networks" +metadata: + description: "View all EVM networks supported by CRE workflows, including required CLI and SDK versions for each network." + datePublished: "2026-02-03" + lastModified: "2026-02-03" +--- + +This page lists all EVM-compatible networks supported by CRE workflows, along with the minimum CLI and SDK versions required for each network. + +## Version Requirements + +Network support depends on your CLI and SDK versions. The tables below show the minimum versions required for each network. + +- **New projects:** Run `cre update` to get the latest CLI, which includes compatible SDK versions. +- **Existing projects:** You may need to update your SDK dependency. See [Updating Dependencies](/cre/reference/project-configuration-ts#5-updating-dependencies) for instructions. + +## Mainnets + +| Network | CLI | Go SDK | TS SDK | +| ------------ | ------ | ------ | ------ | +| Arbitrum One | v1.0.0 | v1.0.0 | v1.0.1 | +| Avalanche | v1.0.0 | v1.0.0 | v1.0.1 | +| Base | v1.0.0 | v1.0.0 | v1.0.1 | +| BNB Chain | v1.0.0 | v1.0.0 | v1.0.1 | +| Ethereum | v1.0.0 | v1.0.0 | v1.0.1 | +| OP Mainnet | v1.0.0 | v1.0.0 | v1.0.1 | +| Polygon | v1.0.0 | v1.0.0 | v1.0.1 | +| ZKSync Era | v1.0.6 | v1.1.3 | v1.0.7 | + +## Testnets + +| Network | CLI | Go SDK | TS SDK | +| ------------------- | ------ | ------ | ------ | +| Apechain Curtis | v1.0.7 | v1.1.4 | v1.0.7 | +| Arc Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Arbitrum Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Avalanche Fuji | v1.0.0 | v1.0.0 | v1.0.1 | +| Base Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| BNB Chain Testnet | v1.0.0 | v1.0.0 | v1.0.1 | +| Ethereum Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Hyperliquid Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Ink Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| Jovay Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Linea Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| OP Sepolia | v1.0.0 | v1.0.0 | v1.0.1 | +| Plasma Testnet | v1.0.7 | v1.1.4 | v1.0.7 | +| Polygon Amoy | v1.0.0 | v1.0.0 | v1.0.1 | +| World Chain Sepolia | v1.0.7 | v1.1.4 | v1.0.7 | +| ZKSync Era Sepolia | v1.0.6 | v1.1.2 | v1.0.7 | + +## Forwarder Addresses + +For forwarder contract addresses and chain names, see the [Forwarder Directory](/cre/guides/workflow/using-evm-client/forwarder-directory). Forwarder addresses are used when building consumer contracts that receive workflow reports onchain. Learn more about [Onchain Write](/cre/guides/workflow/using-evm-client/onchain-write/overview). diff --git a/src/content/cre/templates/running-demo-workflow-go.mdx b/src/content/cre/templates/running-demo-workflow-go.mdx index e3d2a8235d9..7a22e3dca0f 100644 --- a/src/content/cre/templates/running-demo-workflow-go.mdx +++ b/src/content/cre/templates/running-demo-workflow-go.mdx @@ -132,7 +132,7 @@ Now you are ready to compile and run the workflow. The workflow code (`workflow. <Aside type="note" title="Onchain Writes are Dry Runs by Default"> The `--broadcast` flag is included here because this workflow performs an onchain write. By default, the `simulate` command performs a dry run and will not broadcast the transaction without this flag. For more details, see the `cre - workflow simulate` [reference](/cre/reference/cli#cre-workflow-simulate). + workflow simulate` [reference](/cre/reference/cli/workflow#cre-workflow-simulate). </Aside> You will first see a `Workflow compiled` message, followed by the trigger selection menu. diff --git a/src/content/cre/templates/running-demo-workflow-ts.mdx b/src/content/cre/templates/running-demo-workflow-ts.mdx index 9f97a122dd8..6a1aa597d09 100644 --- a/src/content/cre/templates/running-demo-workflow-ts.mdx +++ b/src/content/cre/templates/running-demo-workflow-ts.mdx @@ -7,7 +7,7 @@ pageId: "running-demo-workflow" metadata: description: "Run the Custom Data Feed demo: explore a TypeScript workflow template with API calls, blockchain reads, and onchain writes." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-01-20" --- import { Aside, CopyText } from "@components" @@ -27,7 +27,7 @@ Before you begin, ensure you have the necessary tools installed: - **CRE CLI**: You must have the CRE CLI installed. See [Install the CLI](/cre/getting-started/cli-installation) for instructions. - **CRE account & authentication**: You must have a CRE account and be logged in with the CLI. Run <CopyText text="cre whoami" code /> in your terminal to verify you're logged in, or run <CopyText text="cre login" code /> to authenticate. See [Creating Your Account](/cre/account/creating-account) and [Logging in with the CLI](/cre/account/cli-login) for instructions. -- **Bun**: You must have Bun version 1.2.21 or higher installed. Check your version with <CopyText text="bun --version" code />. See [Install Bun](https://bun.sh/docs/installation) for instructions. +- **Bun**: You must have Bun version 1.2.21 or higher installed. Check your version with <CopyText text="bun --version" code />. See [Install Bun](https://bun.com/docs/installation) for instructions. - **Sepolia Testnet Account**: You need a private key for an account funded with Sepolia ETH. This is required because the demo workflow performs a write transaction. Go to <a href="https://faucets.chain.link" target="blank">faucets.chain.link</a> to get some Sepolia ETH. ## 2. Initialize the demo project @@ -123,7 +123,7 @@ Now you are ready to compile and run the workflow. The single `main.ts` file you <Aside type="note" title="Onchain Writes are Dry Runs by Default"> The `--broadcast` flag is included here because this workflow performs an onchain write. By default, the `simulate` command performs a dry run and will not broadcast the transaction without this flag. For more details, see the `cre - workflow simulate` [reference](/cre/reference/cli#cre-workflow-simulate). + workflow simulate` [reference](/cre/reference/cli/workflow#cre-workflow-simulate). </Aside> You will first see a `Workflow compiled` message, followed by the trigger selection menu. @@ -267,7 +267,7 @@ The `main.ts` file is a great example of how a single workflow can contain multi - **`main()` and `Runner`**: The entry point of the workflow. It creates a new `Runner` instance with your config schema using `Runner.newRunner()`, then calls `runner.run()` with the `initWorkflow` function. This is the standard pattern for initializing CRE workflows in the TypeScript SDK. -- **`initWorkflow`**: This function initializes the trigger capabilities and returns an array of two handlers: one for the cron trigger and one for the EVM log trigger. Each handler is created using `cre.handler()`, which pairs a trigger configuration with a callback function. +- **`initWorkflow`**: This function initializes the trigger capabilities and returns an array of two handlers: one for the cron trigger and one for the EVM log trigger. Each handler is created using `handler()`, which pairs a trigger configuration with a callback function. - **`onCronTrigger`**: The entry point for **Path A**. It's a lightweight callback that immediately delegates to the shared `doPOR` function, demonstrating how you can reuse core logic. @@ -283,7 +283,7 @@ This demo showcases several important patterns and features of the TypeScript SD - **Runner Pattern**: The workflow uses the `Runner.newRunner()` pattern to initialize the workflow with a config schema and run it. - **Zod Schema Validation**: The workflow uses Zod to define and validate the configuration schema, ensuring type safety at runtime. -- **Multiple Trigger Handlers**: A single workflow can register multiple handlers for different trigger types using `cre.handler()`. +- **Multiple Trigger Handlers**: A single workflow can register multiple handlers for different trigger types using `handler()`. - **Viem Integration**: All EVM interactions use viem's `encodeFunctionData` and `decodeFunctionResult` for type-safe contract calls. - **Manual ABI Management**: TypeScript workflows use manually defined ABI constants from the `contracts/abi/` directory. - **Consensus Aggregation**: The HTTP capability uses `ConsensusAggregationByFields` to aggregate offchain data from multiple nodes. diff --git a/src/content/data-feeds/aptos/index.mdx b/src/content/data-feeds/aptos/index.mdx index 332edc23eed..e01dee5a2b4 100644 --- a/src/content/data-feeds/aptos/index.mdx +++ b/src/content/data-feeds/aptos/index.mdx @@ -127,7 +127,7 @@ You now have a funded testnet account on Aptos. - The `platform` address is the `ChainlinkPlatform` package address on Aptos testnet ([`0x516e771e1b4a903afe74c27d057c65849ecc1383782f6642d7ff21425f4f9c99`](https://explorer.aptoslabs.com/object/0x516e771e1b4a903afe74c27d057c65849ecc1383782f6642d7ff21425f4f9c99/modules/packages/ChainlinkPlatform?network=testnet)). - **Note**: You can find the mainnet addresses in the [Feeds Addresses](/data-feeds/price-feeds/addresses?page=1&testnetPage=1&network=aptos) page. + **Note**: You can find the mainnet addresses in the [Feeds Addresses](/data-feeds/price-feeds/addresses?network=aptos) page. 1. Run the following command to download the compiled bytecode for the `ChainlinkPlatform` and `ChainlinkDataFeeds` packages: diff --git a/src/content/data-feeds/l2-sequencer-feeds.mdx b/src/content/data-feeds/l2-sequencer-feeds.mdx index ec74f6a9254..2a8115d592b 100644 --- a/src/content/data-feeds/l2-sequencer-feeds.mdx +++ b/src/content/data-feeds/l2-sequencer-feeds.mdx @@ -47,6 +47,12 @@ Mantle Mainnet: [0xaDE1b9AbB98c6A542E4B49db2588a3Ec4bF7Cdf0](https://mantlescan. <br /> +### <img src="/assets/chains/megaeth.svg" style="height: 20px; width: auto; margin-right: 8px;" />MegaETH + +MegaETH Mainnet: [0x78B2195A21B8BBe82acaB43F90F9180E9513FD0C](https://megaeth.blockscout.com/address/0x78B2195A21B8BBe82acaB43F90F9180E9513FD0C) + +<br /> + ### <img src="/assets/chains/metis.svg" style="height: 20px; width: auto; margin-right: 8px;" />Metis Andromeda Mainnet: [0x58218ea7422255EBE94e56b504035a784b7AA204](https://andromeda-explorer.metis.io/address/0x58218ea7422255EBE94e56b504035a784b7AA204) @@ -71,6 +77,12 @@ Soneium Mainnet: [0xaDE1b9AbB98c6A542E4B49db2588a3Ec4bF7Cdf0](https://soneium.bl <br /> +### <img src="/assets/chains/xlayer.svg" style="height: 20px; width: auto; margin-right: 8px;" />X Layer + +X Layer Mainnet: [0x45c2b8C204568A03Dc7A2E32B71D67Fe97F908A9](https://www.okx.com/web3/explorer/xlayer/address/0x45c2b8C204568A03Dc7A2E32B71D67Fe97F908A9) + +<br /> + ### <img src="/assets/chains/zksync.svg" style="height: 20px; width: auto; margin-right: 8px;" />ZKsync zkSync Mainnet: [0x0E6AC8B967393dcD3D36677c126976157F993940](https://explorer.zksync.io/address/0x0E6AC8B967393dcD3D36677c126976157F993940) @@ -86,7 +98,7 @@ The diagram below shows how these feeds update and how a consumer retrieves the <ClickToZoom src="/images/data-feed/l2-diagram-arbitrum.webp" /> 1. Chainlink nodes trigger an OCR round every 30s and update the sequencer status by calling the `validate` function in the [`ArbitrumValidator` contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol) by calling it through the [`ValidatorProxy` contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.0.0/contracts/src/v0.8/ValidatorProxy.sol). -1. The `ArbitrumValidator` checks to see if the latest update is different from the previous update. If it detects a difference, it places a message in the [Arbitrum inbox contract](https://developer.offchainlabs.com/docs/inside_arbitrum#the-big-picture). +1. The `ArbitrumValidator` checks to see if the latest update is different from the previous update. If it detects a difference, it places a message in the [Arbitrum inbox contract](https://docs.arbitrum.io/how-arbitrum-works/inside-arbitrum-nitro). 1. The inbox contract sends the message to the [`ArbitrumSequencerUptimeFeed` contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol). The message calls the `updateStatus` function in the `ArbitrumSequencerUptimeFeed` contract and updates the latest sequencer status to 0 if the sequencer is up and 1 if it is down. It also records the block timestamp to indicate when the message was sent from the L1 network. 1. A consumer contract on the L2 network can read these values from the [`ArbitrumUptimeFeedProxy` contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.0.0/contracts/src/v0.6/EACAggregatorProxy.sol), which reads values from the `ArbitrumSequencerUptimeFeed` contract. diff --git a/src/content/data-feeds/llms-full.txt b/src/content/data-feeds/llms-full.txt index 9bf4a207cb3..8af0165ea2a 100644 --- a/src/content/data-feeds/llms-full.txt +++ b/src/content/data-feeds/llms-full.txt @@ -560,7 +560,7 @@ You now have a funded testnet account on Aptos. - The `platform` address is the `ChainlinkPlatform` package address on Aptos testnet ([`0x516e771e1b4a903afe74c27d057c65849ecc1383782f6642d7ff21425f4f9c99`](https://explorer.aptoslabs.com/object/0x516e771e1b4a903afe74c27d057c65849ecc1383782f6642d7ff21425f4f9c99/modules/packages/ChainlinkPlatform?network=testnet)). - **Note**: You can find the mainnet addresses in the [Feeds Addresses](/data-feeds/price-feeds/addresses?page=1\&testnetPage=1\&network=aptos) page. + **Note**: You can find the mainnet addresses in the [Feeds Addresses](/data-feeds/price-feeds/addresses?network=aptos) page. 3. Run the following command to download the compiled bytecode for the `ChainlinkPlatform` and `ChainlinkDataFeeds` packages: @@ -978,6 +978,15 @@ The example below uses Javascript Web3 library to interact with ENS. See the [EN This example logs the address of the data feed on the Ethereum mainnet for ETH / USD prices. +```js +const Web3 = require("web3") + +const web3 = new Web3("https://rpc.ankr.com/eth") +web3.eth.ens.getAddress("eth-usd.data.eth").then((address) => { + console.log(address) +}) +``` + ### Solidity In Solidity, the address of the ENS registry must be known. According to [ENS documentation](https://docs.ens.domains/ens-deployments), this address is the same across Mainnet and testnet: @@ -988,6 +997,52 @@ Also, instead of using readable string names like `eth-usd.data.eth`, resolvers "ETH / USD" hash: `0xf599f4cd075a34b92169cf57271da65a7a936c35e3f31e854447fbb3e7eb736d` +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +// ENS Registry Contract +interface ENS { + function resolver( + bytes32 node + ) external view returns (Resolver); +} + +// Chainlink Resolver +interface Resolver { + function addr( + bytes32 node + ) external view returns (address); +} + +// Consumer contract +contract ENSConsumer { + ENS ens; + + // ENS registry address: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e + constructor( + address ensAddress + ) { + ens = ENS(ensAddress); + } + + // Use ID Hash instead of readable name + // ETH / USD hash: 0xf599f4cd075a34b92169cf57271da65a7a936c35e3f31e854447fbb3e7eb736d + function resolve( + bytes32 node + ) public view returns (address) { + Resolver resolver = ens.resolver(node); + return resolver.addr(node); + } +} +``` + --- # Feed Types @@ -1029,6 +1084,59 @@ If you are new to smart contract development, learn how to [Deploy Your First Sm This example contract obtains the latest price answer from the [BTC / USD feed](/data-feeds/price-feeds/addresses) on the Sepolia testnet, but you can modify it to read any of the different [Types of Data Feeds](/data-feeds#types-of-data-feeds). +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED + * VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/** + * If you are reading data feeds on L2 networks, you must + * check the latest answer from the L2 Sequencer Uptime + * Feed to ensure that the data is accurate in the event + * of an L2 sequencer outage. See the + * https://docs.chain.link/data-feeds/l2-sequencer-feeds + * page for details. + */ +contract DataConsumerV3 { + AggregatorV3Interface internal dataFeed; + + /** + * Network: Sepolia + * Aggregator: BTC/USD + * Address: 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43 + */ + constructor() { + dataFeed = AggregatorV3Interface(0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43); + } + + /** + * Returns the latest answer. + */ + function getChainlinkDataFeedLatestAnswer() public view returns (int256) { + // prettier-ignore + ( + /* uint80 roundId */ + , + int256 answer, + /*uint256 startedAt*/ + , + /*uint256 updatedAt*/ + , + /*uint80 answeredInRound*/ + ) = dataFeed.latestRoundData(); + return answer; + } +} +``` + The contract has the following components: - The `import` line imports an interface named `AggregatorV3Interface`. Interfaces define functions without their implementation, which leaves inheriting contracts to define the actual implementation themselves. In this case, `AggregatorV3Interface` defines that all v3 Aggregators have the function `latestRoundData`. You can [see the complete code](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol) for the `AggregatorV3Interface` on GitHub. @@ -1183,12 +1291,160 @@ The [`getRoundData` function](/data-feeds/api-reference/#getrounddata) returns t ### Solidity +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract HistoricalDataConsumerV3 { + AggregatorV3Interface internal dataFeed; + + /** + * Network: Sepolia + * Aggregator: ETH/USD + * Address: 0x694AA1769357215DE4FAC081bf1f309aDC325306 + */ + constructor() { + dataFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306); + } + + /** + * Returns historical data for a round ID. + * roundId is NOT incremental. Not all roundIds are valid. + * You must know a valid roundId before consuming historical data. + * + * ROUNDID VALUES: + * InValid: 18446744073709562300 + * Valid: 18446744073709554683 + * + * @dev A timestamp with zero value means the round is not complete and should not be used. + */ + function getHistoricalData( + uint80 roundId + ) public view returns (int256) { + // prettier-ignore + ( + /*uint80 roundID*/ + , + int256 answer, + /*uint startedAt*/ + , + /*uint timeStamp*/ + , + /*uint80 answeredInRound*/ + ) = dataFeed.getRoundData(roundId); + return answer; + } +} +``` + ### Javascript -<HistoricalPrice client:idle feedAddress={priceFeedAddresses.btc.usd.sepolia.address} roundId={priceFeedAddresses.btc.usd.sepolia.historicalRound} supportedChain="ETHEREUM_SEPOLIA" /> +```js +/** + * THIS IS EXAMPLE CODE THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS EXAMPLE CODE THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +const Web3 = require("web3") // for nodejs only +// Replace the provider URL with your own endpoint URL +const web3 = new Web3("https://rpc.ankr.com/eth_sepolia") +const aggregatorV3InterfaceABI = [ + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "description", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint80", name: "_roundId", type: "uint80" }], + name: "getRoundData", + outputs: [ + { internalType: "uint80", name: "roundId", type: "uint80" }, + { internalType: "int256", name: "answer", type: "int256" }, + { internalType: "uint256", name: "startedAt", type: "uint256" }, + { internalType: "uint256", name: "updatedAt", type: "uint256" }, + { internalType: "uint80", name: "answeredInRound", type: "uint80" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "latestRoundData", + outputs: [ + { internalType: "uint80", name: "roundId", type: "uint80" }, + { internalType: "int256", name: "answer", type: "int256" }, + { internalType: "uint256", name: "startedAt", type: "uint256" }, + { internalType: "uint256", name: "updatedAt", type: "uint256" }, + { internalType: "uint80", name: "answeredInRound", type: "uint80" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, +] +const addr = "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43" +const dataFeed = new web3.eth.Contract(aggregatorV3InterfaceABI, addr) + +// Valid roundId must be known. They are NOT incremental. +let validId = BigInt("18446744073709554177") +dataFeed.methods + .getRoundData(validId) + .call() + .then((historicalRoundData) => { + document.getElementById("get-data-field").value = historicalRoundData.answer + }) +``` ### Python +```py +# THIS IS EXAMPLE CODE THAT USES HARDCODED VALUES FOR CLARITY. +# THIS IS EXAMPLE CODE THAT USES UN-AUDITED CODE. +# DO NOT USE THIS CODE IN PRODUCTION. + +from web3 import Web3 + +# Change this to use your own RPC URL +web3 = Web3(Web3.HTTPProvider('https://rpc.ankr.com/eth_sepolia')) +# AggregatorV3Interface ABI +abi = '[{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"_roundId","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]' +# Feed address +addr = '0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43' + +# Set up contract instance +contract = web3.eth.contract(address=addr, abi=abi) + +# Valid roundId must be known. They are NOT incremental. +# invalidRoundId = 18446744073709562300 +validRoundId = 18446744073709554177 + +historicalData = contract.functions.getRoundData(validRoundId).call() +print(historicalData) +``` + --- # Chainlink Data Feeds @@ -1377,6 +1633,10 @@ Celo Mainnet: [0x4CD491Dc27C8B0BbD10D516A502856B786939d18](https://celoscan.io/a Mantle Mainnet: [0xaDE1b9AbB98c6A542E4B49db2588a3Ec4bF7Cdf0](https://mantlescan.xyz/address/0xaDE1b9AbB98c6A542E4B49db2588a3Ec4bF7Cdf0) +### <img src="/assets/chains/megaeth.svg" style="height: 20px; width: auto; margin-right: 8px;" />MegaETH + +MegaETH Mainnet: [0x78B2195A21B8BBe82acaB43F90F9180E9513FD0C](https://megaeth.blockscout.com/address/0x78B2195A21B8BBe82acaB43F90F9180E9513FD0C) + ### <img src="/assets/chains/metis.svg" style="height: 20px; width: auto; margin-right: 8px;" />Metis Andromeda Mainnet: [0x58218ea7422255EBE94e56b504035a784b7AA204](https://andromeda-explorer.metis.io/address/0x58218ea7422255EBE94e56b504035a784b7AA204) @@ -1393,6 +1653,10 @@ Scroll Mainnet: [0x45c2b8C204568A03Dc7A2E32B71D67Fe97F908A9](https://scrollscan. Soneium Mainnet: [0xaDE1b9AbB98c6A542E4B49db2588a3Ec4bF7Cdf0](https://soneium.blockscout.com/address/0xaDE1b9AbB98c6A542E4B49db2588a3Ec4bF7Cdf0) +### <img src="/assets/chains/xlayer.svg" style="height: 20px; width: auto; margin-right: 8px;" />X Layer + +X Layer Mainnet: [0x45c2b8C204568A03Dc7A2E32B71D67Fe97F908A9](https://www.okx.com/web3/explorer/xlayer/address/0x45c2b8C204568A03Dc7A2E32B71D67Fe97F908A9) + ### <img src="/assets/chains/zksync.svg" style="height: 20px; width: auto; margin-right: 8px;" />ZKsync zkSync Mainnet: [0x0E6AC8B967393dcD3D36677c126976157F993940](https://explorer.zksync.io/address/0x0E6AC8B967393dcD3D36677c126976157F993940) @@ -1404,7 +1668,7 @@ zkSync Mainnet: [0x0E6AC8B967393dcD3D36677c126976157F993940](https://explorer.zk The diagram below shows how these feeds update and how a consumer retrieves the status of the Arbitrum sequencer. 1. Chainlink nodes trigger an OCR round every 30s and update the sequencer status by calling the `validate` function in the [`ArbitrumValidator` contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol) by calling it through the [`ValidatorProxy` contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.0.0/contracts/src/v0.8/ValidatorProxy.sol). -2. The `ArbitrumValidator` checks to see if the latest update is different from the previous update. If it detects a difference, it places a message in the [Arbitrum inbox contract](https://developer.offchainlabs.com/docs/inside_arbitrum#the-big-picture). +2. The `ArbitrumValidator` checks to see if the latest update is different from the previous update. If it detects a difference, it places a message in the [Arbitrum inbox contract](https://docs.arbitrum.io/how-arbitrum-works/inside-arbitrum-nitro). 3. The inbox contract sends the message to the [`ArbitrumSequencerUptimeFeed` contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol). The message calls the `updateStatus` function in the `ArbitrumSequencerUptimeFeed` contract and updates the latest sequencer status to 0 if the sequencer is up and 1 if it is down. It also records the block timestamp to indicate when the message was sent from the L1 network. 4. A consumer contract on the L2 network can read these values from the [`ArbitrumUptimeFeedProxy` contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.0.0/contracts/src/v0.6/EACAggregatorProxy.sol), which reads values from the `ArbitrumSequencerUptimeFeed` contract. @@ -1457,6 +1721,83 @@ This example code works on any network that supports Solidity. Create the consum - Configure the `sequencerUptimeFeed` object with the [sequencer uptime feed proxy address](#supported-networks) for your L2 network. - Configure the `dataFeed` object with one of the [Data Feed proxy addresses](/data-feeds/price-feeds/addresses) that are available for your network. +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import {AggregatorV2V3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV2V3Interface.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract DataConsumerWithSequencerCheck { + AggregatorV2V3Interface internal dataFeed; + AggregatorV2V3Interface internal sequencerUptimeFeed; + + uint256 private constant GRACE_PERIOD_TIME = 3600; + + error SequencerDown(); + error GracePeriodNotOver(); + + /** + * Network: OP Mainnet + * Data Feed: BTC/USD + * Data Feed address: 0xD702DD976Fb76Fffc2D3963D037dfDae5b04E593 + * Uptime Feed address: 0x371EAD81c9102C9BF4874A9075FFFf170F2Ee389 + * For a list of available Sequencer Uptime Feed proxy addresses, see: + * https://docs.chain.link/docs/data-feeds/l2-sequencer-feeds + */ + constructor() { + dataFeed = AggregatorV2V3Interface(0xD702DD976Fb76Fffc2D3963D037dfDae5b04E593); + sequencerUptimeFeed = AggregatorV2V3Interface(0x371EAD81c9102C9BF4874A9075FFFf170F2Ee389); + } + + // Check the sequencer status and return the latest data + function getChainlinkDataFeedLatestAnswer() public view returns (int256) { + // prettier-ignore + ( + /*uint80 roundID*/ + , + int256 answer, + uint256 startedAt, + /*uint256 updatedAt*/ + , + /*uint80 answeredInRound*/ + ) = sequencerUptimeFeed.latestRoundData(); + + // Answer == 0: Sequencer is up + // Answer == 1: Sequencer is down + bool isSequencerUp = answer == 0; + if (!isSequencerUp) { + revert SequencerDown(); + } + + // Make sure the grace period has passed after the + // sequencer is back up. + uint256 timeSinceUp = block.timestamp - startedAt; + if (timeSinceUp <= GRACE_PERIOD_TIME) { + revert GracePeriodNotOver(); + } + + // prettier-ignore + ( + /*uint80 roundID*/ + , + int256 data, + /*uint startedAt*/ + , + /*uint timeStamp*/ + , + /*uint80 answeredInRound*/ + ) = dataFeed.latestRoundData(); + + return data; + } +} +``` + The `sequencerUptimeFeed` object returns the following values: - `answer`: A variable with a value of either `0` or `1` @@ -2408,6 +2749,157 @@ Below is a full example that demonstrates how to: 5. Update the field names in `consumeData()` to match your struct </Aside> +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {IBundleAggregatorProxy} from "@chainlink/contracts/src/v0.8/data-feeds/interfaces/IBundleAggregatorProxy.sol"; + +/** + * @notice This struct defines the exact data structure of the MVR feed + * @dev The order and types must match exactly what's defined in the feed + */ +struct Data { + uint256 netAssetValue; + uint256 assetsUnderManagement; + uint256 outstandingShares; + uint256 netIncomeExpenses; + bool openToNewInvestors; +} + +contract MVRDataConsumer { + // Reference to the MVR feed proxy + IBundleAggregatorProxy public s_proxy; + + // Maximum allowed staleness duration for the data + // IMPORTANT: This should be configured based on the specific feed's heartbeat interval + // Check the feed's documentation for the appropriate value instead of using this example value + uint256 public immutable STALENESS_THRESHOLD; + + // Storage for scaled values (after dividing by decimals) + uint256 public netAssetValue; + uint256 public assetsUnderManagement; + uint256 public outstandingShares; + uint256 public netIncomeExpenses; + bool public openToNewInvestors; + + // Storage for original onchain values (no decimal adjustments) + uint256 public rawNetAssetValue; + uint256 public rawAssetsUnderManagement; + uint256 public rawOutstandingShares; + uint256 public rawNetIncomeExpenses; + + // Keep track of decimals for each field in the struct. + // Non-numeric fields (e.g., bool) typically return 0. + uint8[] public decimals; + + // Error for stale data + error StaleData(uint256 lastUpdateTimestamp, uint256 blockTimestamp, uint256 threshold); + + // Error for insufficient decimals array + error InsufficientDecimals(uint256 expected, uint256 actual); + + /** + * @notice Constructor that sets the staleness threshold for the feed + * @param _proxy The address of the MVR feed's proxy contract + * @param _stalenessThreshold Maximum time (in seconds) since last update before data is considered stale + * @dev The threshold should be based on the feed's heartbeat interval from documentation + * For example, if a feed updates every 24 hours (86400s), you might set this to 86400s + some buffer + */ + constructor( + IBundleAggregatorProxy _proxy, + uint256 _stalenessThreshold + ) { + s_proxy = _proxy; + STALENESS_THRESHOLD = _stalenessThreshold; + } + + /** + * @notice Stores the decimals array in your contract for repeated usage. + * @dev Index mapping for this example: + * 0 -> netAssetValue, + * 1 -> assetsUnderManagement, + * 2 -> outstandingShares, + * 3 -> netIncomeExpenses, + * 4 -> openToNewInvestors (likely returns 0). + */ + function storeDecimals() external { + decimals = s_proxy.bundleDecimals(); + } + + /** + * @notice Returns the timestamp of the most recent MVR feed update. + */ + function getLatestBundleTimestamp() external view returns (uint256) { + return s_proxy.latestBundleTimestamp(); + } + + /** + * @notice Simple boolean check for data freshness (block explorer friendly) + * @return true if data is fresh, false if stale + */ + function isDataFresh() public view returns (bool) { + uint256 lastUpdateTime = s_proxy.latestBundleTimestamp(); + return (block.timestamp - lastUpdateTime) <= STALENESS_THRESHOLD; + } + + /** + * @notice Fetches and decodes the latest MVR feed data, then stores both the raw and scaled values. + * @dev This process demonstrates the complete flow of consuming MVR feed data: + * 1. Check data freshness + * 2. Fetch the raw bytes + * 3. Decode into the struct matching the feed's data structure + * 4. Store raw values (preserving original precision) + * 5. Apply decimal conversions to get the true numerical values + */ + function consumeData() external { + // Check data freshness before proceeding + if (!isDataFresh()) { + uint256 lastUpdateTime = s_proxy.latestBundleTimestamp(); + revert StaleData(lastUpdateTime, block.timestamp, STALENESS_THRESHOLD); + } + + // Ensure we have the decimals array - if not, fetch it + if (decimals.length == 0) { + decimals = s_proxy.bundleDecimals(); + } + + // Verify we have enough decimal values for our struct fields + if (decimals.length < 4) { + revert InsufficientDecimals(4, decimals.length); + } + + // 1. Retrieve the raw bytes from the MVR feed + // This is the encoded form of all data fields packed together + bytes memory b = s_proxy.latestBundle(); + + // 2. Decode the raw bytes into our known struct + // The struct Data must match exactly what the feed encodes + Data memory d = abi.decode(b, (Data)); + + // 3. Store the raw (original onchain) values + // These preserve the full precision as reported by the feed + rawNetAssetValue = d.netAssetValue; + rawAssetsUnderManagement = d.assetsUnderManagement; + rawOutstandingShares = d.outstandingShares; + rawNetIncomeExpenses = d.netIncomeExpenses; + openToNewInvestors = d.openToNewInvestors; // Boolean, no need for decimal adjustment + + // 4. Convert values by dividing by 10^decimals[i] + // This removes the decimal scaling factor to get the human-readable representation + // Note: This uses integer division which truncates decimal places + // For example, if decimals[0] = 8 and rawNetAssetValue = 1850000000, + // then netAssetValue = 18 (integer division, decimals are truncated) + netAssetValue = d.netAssetValue / (10 ** decimals[0]); + assetsUnderManagement = d.assetsUnderManagement / (10 ** decimals[1]); + outstandingShares = d.outstandingShares / (10 ** decimals[2]); + netIncomeExpenses = d.netIncomeExpenses / (10 ** decimals[3]); + // Note: We don't need to apply decimals to boolean fields + // The openToNewInvestors field typically has 0 decimals in the array + } +} +``` + **Key Points**: - **Exact Order Matters**: The struct fields and their types must match the feed's definition. @@ -3117,7 +3609,7 @@ See the [Rate and Volatility Feed Addresses](/data-feeds/rates-feeds/addresses) # Selecting Quality Data Feeds Source: https://docs.chain.link/data-feeds/selecting-data-feeds -When you design your applications, consider the quality of the data that you use in your smart contracts. Ultimately you are responsible for identifying and assessing the accuracy, availability, and quality of data that you choose to consume via the Chainlink Network. Note that all feeds contain some inherent risk. Read the [Risk Mitigation](#risk-mitigation) and [Evaluating Data Sources](#evaluating-data-sources-and-risks) sections when making design decisions. Chainlink lists decentralized data feeds in the documentation to help developers build new applications integrated with data. +When you design your applications, consider the quality of the data that you use in your smart contracts. Ultimately you are responsible for identifying and assessing the accuracy, availability, and quality of data that you choose to consume via the Chainlink Network. Note that all feeds contain some inherent risk. Read the [Risk Mitigation](#risk-mitigation) and [Evaluating Data Sources](#evaluating-data-sources-and-risks) sections when making design decisions. Chainlink lists decentralized data feeds in the documentation to help developers build new applications integrated with data. Please review this page in its entirety to understand the risks and categories relevant to your data feed implementation. For a summary of data sourcing models by asset type, see [Data Sources](/data-feeds/data-sources). @@ -3125,16 +3617,15 @@ For a summary of data sourcing models by asset type, see [Data Sources](/data-fe This categorization is put in place to inform users about the intended use cases of feeds and help highlight some of the inherent market integrity risks surrounding the data quality of these feeds. -All feeds published on [docs.chain.link](http://docs.chain.link) are monitored and maintained to the same levels and standards. Each feed goes through a rigorous assessment process when implemented. The assessment criteria can vary depending on the product type of feed being deployed or change over time as the understanding of market integrity risks evolves. - -Market price feeds incorporate three layers of aggregation at the data source, node operator, and oracle network layers, providing industry-standard security and reliability on the price data they reference. To learn more about the three layers of data aggregation, see the blog post about [Data Aggregation in Chainlink Price Feeds](https://blog.chain.link/levels-of-data-aggregation-in-chainlink-price-feeds/). Additional information about how Chainlink Data Feeds are secured can be seen in the blog post about [How Chainlink Price Feeds Secure the DeFi Ecosystem](https://blog.chain.link/chainlink-price-feeds-secure-defi/). +Market price feeds incorporate three layers of aggregation at the data source, node operator, and oracle network layers, providing industry-standard security and reliability on the price data they reference. -Data feeds are grouped into the following categories based on the level of market integrity risk from lowest to highest: +Data feeds are grouped into the following categories based on the level of market pricing risk, based on multiple factors, from lowest to highest: -- [🟢 Low Market Risk](#-low-market-risk-feeds) -- [🟡 Medium Market Risk](#-medium-market-risk-feeds) -- [🔴 High Market Risk](#-high-market-risk-feeds) -- [🟠 New Token Feeds](#-new-token-feeds) +- [🟢 Low Market Pricing Risk](#-low-market-pricing-risk-feeds) +- [🟡 Medium Market Pricing Risk](#-medium-market-pricing-risk-feeds) +- [🟠 High Market Pricing Risk](#-high-market-pricing-risk-feeds) +- [🔴 Very High Market Pricing Risk](#-very-high-market-pricing-risk-feeds) +- [🆕 New Token Feeds](#-new-token-feeds) - [🔵 Custom Feeds](#-custom-feeds) - [⭕ Deprecating](#-deprecating) @@ -3143,64 +3634,71 @@ Data feeds are grouped into the following categories based on the level of marke subscribe to the [#data-feeds channel](https://discord.gg/Dqy5N9UbsR). </Aside> -### 🟢 Low Market Risk Feeds +### 🟢 Low Market Pricing Risk Feeds These are data feeds that follow a standardized data feeds workflow to report market prices for an asset pair. Chainlink node operators each query several sources for the market price and aggregate the estimates provided by those sources. -Low Market Risk feeds have the following characteristics: +Low Market Pricing Risk feeds have the following characteristics: -- Highly resilient to disruption -- Leverage many data sources -- High volumes across a large number of markets enable consistent price discovery +- More resilient to disruption than other feeds +- Leverage multiple data sources when they are available +- Higher volumes across multiple markets enables price discovery -While market risk may be low, other risks might still exist based on your use case, the blockchain on which the feed is deployed, and the conditions on that chain. +While Market Pricing Risk may be categorized as low, other risks might still exist based on your use case, data provider availability or performance, the blockchain on which the feed is deployed, and the conditions on that chain. Developers remain responsible for ensuring that protocol [risk parameters are configured appropriately](#risk-mitigation) and that the operation and performance of Low Market Pricing Risk data feeds match expectations. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. -### 🟡 Medium Market Risk Feeds +### 🟡 Medium Market Pricing Risk Feeds -These feeds also follow a standardized data feeds workflow to report market prices for an asset pair. The pair in question may have features that make it more challenging to reliably price, or potentially subject it to volatility which may pose a risk in some use cases. While the architecture of these feeds is resilient and distributed, these feeds carry additional market risk. +These feeds also follow a standardized data feeds workflow to report market prices for an asset pair. The pair in question may have features that make it more challenging to reliably price, or potentially subject it to volatility, which may pose a risk in some use cases. While the architecture of these feeds is resilient and distributed, these feeds carry additional Market Pricing Risk. -Types of market risk that may lead to a feed being categorized as Medium Market Risk include: +Types of Market Pricing Risk that may lead to a feed being categorized as Medium Market Pricing Risk include: -- Lower or inconsistent asset volume may result in periods of low liquidity in the market for such assets. This, in turn, can lead to volatile price movements +- Lower or inconsistent asset volume may result in periods of low liquidity in the market for such assets. This, in turn, can lead to volatile price movements. - A spread between the price for this asset on different trading venues or liquidity pools. - Market Concentration Risk: If the volume for a given asset is excessively concentrated on a single exchange, that trading venue could become a single point of failure for the feed. - Cross-Rate Risk: The base asset trades in large volumes against assets that are not pegged to the quote asset. As a result, the price of this specific asset pair may fluctuate even if the underlying asset is not being traded. - The asset is going through a significant market event such as a token or liquidity migration. - The asset has a high spread between data providers, the root cause of which is often one of the above factors. +- The availability of pricing sources may be subject to change based on concentration, trading venue location, and currency pairs. + +Developers remain responsible for ensuring that protocol [risk parameters are configured appropriately](#risk-mitigation) and that the operation and performance of Medium Market Pricing Risk data feeds matches expectations. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. -### 🔴 High Market Risk Feeds +### 🟠 High Market Pricing Risk Feeds -These feeds also follow a standardized data feeds workflow to report market prices for an asset pair. However, the pair in question often exhibits a heightened degree of some of the risk factors outlined under “Medium Market Risk”, or a separate risk that makes the market price subject to uncertainty or volatility. In using a High Market Risk data feed you acknowledge that you understand the risks associated with such a feed and that you are solely responsible for monitoring and mitigating such risks. +These feeds also follow a standardized data feeds workflow to report market prices for an asset pair. However, the pair in question often exhibits a heightened degree of some of the risk factors outlined under Medium Market Pricing Risk, or a separate risk that makes the market price subject to uncertainty or volatility. In using a High Market Pricing Risk data feed you acknowledge that you understand the risks associated with such a feed and that you are solely responsible for monitoring and mitigating such risks. Developers remain responsible for ensuring that protocol [risk parameters are configured appropriately](#risk-mitigation) and that the operation and performance of High Market Pricing Risk data feeds matches expectations. High Market Pricing Risk data feeds may be deprecated. See the [Data Feed Shutdown Policy](#data-feed-shutdown-policy) for more information. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. -Types of market risk that may lead to a feed being categorized as High Market Risk include: +### 🔴 Very High Market Pricing Risk Feeds + +Very High Market Pricing Risk feeds price assets with quotes that are subject to extreme levels of risk, greater than those outlined above for High Market Pricing Risk. Types of Market Pricing Risk that may lead to a feed being categorized as Very High Market Pricing Risk include, but are not limited to: - The asset is going through a significant market event such as a hack, bridge failure, or a delisting from a major exchange. - The asset or project is being deprecated in the market. - Volumes have dropped to extremely low levels. +- Reliable pricing sources for asset are extremely limited. + +Users should wind down their reliance on these feeds and/or implement strict capital and risk management policies accounting for extreme price and market structure volatility. Very High Market Pricing Risk feeds will be wound down over time in accordance with the [Data Feed Shutdown Policy](#data-feed-shutdown-policy). In using a Very High Market Pricing Risk data feed you acknowledge that you understand the risks associated with such a feed and that you are solely responsible for monitoring and mitigating such risks. You understand that Chainlink may not provide separate monitoring for these feeds. Developers remain responsible for ensuring that protocol [risk parameters are configured appropriately](#risk-mitigation) and that the operation and performance of Very High Market Pricing Risk data feeds matches expectations. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. -### 🟠 New Token Feeds +### 🆕 New Token Feeds -When a token is newly launched, the historical data required to implement a rigorous risk assessment framework that would allow the categorization of a market data feed for that token as low, medium, or high market risk is unavailable. Consistent price discovery may involve an indeterminate amount of time. Users must understand the additional [market and volatility risks](https://docs.chain.link/data-feeds/selecting-data-feeds#evaluating-data-sources-and-risks) inherent with such assets. Users of new token feeds are responsible for independently verifying the liquidity and stability of the assets priced by the feeds that they use. -At the end of a probationary period, the status of new token feeds may be adjusted to high/medium/low market risk or in rare cases be deprecated entirely. +When a token is newly launched, the historical data required to implement a rigorous risk assessment framework that would allow the categorization of a market data feed for that token as Low, Medium, or High Pricing Risk is unavailable. Consistent price discovery may involve an indeterminate amount of time. Users must understand the additional [market and volatility risks](#evaluating-data-sources-and-risks) inherent with such assets. Users of New Token feeds are responsible for independently verifying the liquidity and stability of the assets priced by the feeds that they use. At the end of a probationary period, the status of New Token feeds may be adjusted to Very High, High, Medium, or Low Market Pricing Risk, or in rare cases be deprecated entirely. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. ### 🔵 Custom Feeds Custom Feeds are built to serve a specific use case and might not be suitable for general use or your use case's risk parameters. Users must evaluate the properties of a feed to make sure it aligns with their intended use case. [Contact the Chainlink Labs team](https://chain.link/contact?ref_id=DataFeed) if you want more detail on any specific feeds in this category. -Custom feeds have the following categories and compositions: +Custom Feeds have the following categories and compositions: -- Onchain single source feeds: These feeds take their data from an onchain source, however, the feed has only a single data provider currently supporting the feed. -- Onchain Proof of Reserve Feeds: Chainlink Proof of Reserve uses a large decentralized collection of security-reviewed and Sybil-resistant node operators to acquire and verify reserve data. In this use case, reserves reside onchain. -- Exchange Rate Feeds: These feeds read an exchange rate from an external contract onchain that is designed to allow conversion from one token to another. Chainlink does not own or control these contracts in any way. They are not equivalent to market price feeds. -- Technical Feeds: Feeds within this category measure a particular technical metric from a specified blockchain. For example, Fast Gas or Block Difficulty. -- Total Value Locked Feeds: These feeds measure the total value locked in a particular protocol. -- Custom Index Feeds: An index calculates a function of the values for multiple underlying assets. The function is specific to that index and is typically calculated by node operators following an agreed formula. -- Offchain Single Source Feeds: Some data providers use a single data source, which might be necessary if only one source exists offchain for a specific type of data. -- Offchain Proof of Reserve Feeds: Chainlink Proof of Reserve uses a large decentralized collection of security-reviewed and Sybil-resistant node operators to acquire and verify reserve data. In this use case, reserves reside offchain. -- LP Token Feeds: These feeds use a decentralized feed for the underlying asset as well as calculations to value the liquidity pool (LP) tokens. -- Wrapped Calculated Feeds: These feeds are typically pegged 1:1 to the underlying token or asset. Under normal market conditions, these feeds track their underlying value accurately. However, given that the price is a derivative formed from a calculated method, the derivative asset may not always precisely track the value of the underlying token or asset precisely. +- [🟠](#-high-market-pricing-risk-feeds) **Onchain Single Source Feeds:** These feeds take their data from an onchain source, however, the feed has only a single data provider currently supporting the feed. +- [🟡](#-medium-market-pricing-risk-feeds) **Onchain Proof of Reserve Feeds:** Chainlink Proof of Reserve uses a large decentralized collection of security-reviewed and Sybil-resistant node operators to acquire and verify reserve data. In this use case, reserves reside onchain. +- [🟡](#-medium-market-pricing-risk-feeds) **Exchange Rate Feeds:** These feeds read an exchange rate from an external contract onchain that is designed to allow conversion from one token to another. Chainlink does not own or control these contracts in any way. They are not equivalent to market price feeds. +- [🟡](#-medium-market-pricing-risk-feeds) **Technical Feeds:** Feeds within this category measure a particular technical metric from a specified blockchain. For example, Fast Gas or Block Difficulty. +- [🟡](#-medium-market-pricing-risk-feeds) **Total Value Locked Feeds:** These feeds measure the total value locked in a particular protocol. +- [🟠](#-high-market-pricing-risk-feeds) **Custom Index Feeds:** An index calculates a function of the values for multiple underlying assets. The function is specific to that index and is typically calculated by node operators following an agreed formula. +- [🟠](#-high-market-pricing-risk-feeds) **Offchain Single Source Feeds:** Some data providers use a single data source, which might be necessary if only one source exists offchain for a specific type of data. +- [🟠](#-high-market-pricing-risk-feeds) **Offchain Proof of Reserve Feeds:** Chainlink Proof of Reserve uses a large decentralized collection of security-reviewed and Sybil-resistant node operators to acquire and verify reserve data. In this use case, reserves reside offchain. +- [🟠](#-high-market-pricing-risk-feeds) **LP Token Feeds:** These feeds use a decentralized feed for the underlying asset as well as calculations to value the liquidity pool (LP) tokens. +- [🔴](#-very-high-market-pricing-risk-feeds) **Wrapped Calculated Feeds:** These feeds are typically pegged 1:1 to the underlying token or asset. Under normal market conditions, these feeds track their underlying value accurately. However, given that the price is a derivative formed from a calculated method, the derivative asset may not always precisely track the value of the underlying token or asset. -If you plan on using one of these feeds and would like to get a more detailed understanding, [contact the Chainlink Labs team](https://chain.link/contact?ref_id=DataFeed). +If you plan on using one of these feeds and would like to get a more detailed understanding, [contact the Chainlink Labs team](https://chain.link/contact?ref_id=DataFeed). Using feeds that were not specifically designed for your use case involves risk. Their use might pose risks that could result in harm to your project. Users are responsible for thoroughly vetting and validating such deployments and determining their suitability. You bear responsibility for any manner in which you use the Chainlink Network, its software, and documentation. ### ⭕ Deprecating @@ -3208,9 +3706,17 @@ These feeds are being deprecated. To find the deprecation dates for specific fee #### Data Feed Shutdown Policy -Data feeds managed by Chainlink Labs will be considered for deprecation if they pose a risk to the Chainlink Community and broader ecosystem, if the asset or assets on the feed have significantly deteriorated and no longer meet our Quality Assurance standards, or if the data feed has become economically unsustainable to support. +Data feeds managed by Chainlink Labs will be considered for deprecation if they pose a risk to the Chainlink Community and broader ecosystem, if the asset or assets (or their volume or liquidity) on the feed have significantly deteriorated or are unreliable and no longer meet our Quality Assurance standards, or if the data feed has become economically unsustainable to support. Users are therefore advised to ensure they have measures in place for the orderly deprecation of reliance on specific Chainlink price feeds. + +Known users of these feeds will be contacted directly about the feeds' deprecation whenever possible. Notifications will also be posted on the [Feeds Scheduled For Deprecation](/data-feeds/deprecating-feeds) page and on our [Discord channel](https://discord.com/channels/592041321326182401/991444378335838318) with two weeks of notice before they are shut down except where conditions require an accelerated deprecation. + -Known users of these feeds will be contacted directly about the feeds' deprecation. Notifications will also be posted on the [Feeds Scheduled For Deprecation](/data-feeds/deprecating-feeds) page and on our [Discord channel](https://discord.com/channels/592041321326182401/991444378335838318) with two weeks of notice before they are shut down. +<Aside type="note" title="Data Feed Shutdown Behavior"> + Once a feed is shutdown, calls to the feed will behave as follows: + + - `lastAnswer` will return `0` + - `latestRoundData` will revert with no data available +</Aside> ## Market hours @@ -3220,6 +3726,7 @@ In addition to categories, be aware that markets for several assets are actively | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Crypto** | 24/7/365 - No market close. | | **US_Equities** | Standard US equity market hours: 09:30 - 16:00 ET M-F excluding US equity market holidays. | +| **US_Equities_24/5** | 24 hours a day, 5 days a week: 18:00 ET Sunday to 17:00 ET Friday. These feeds aggregate data across regular, pre-market, post-market, and overnight equity trading sessions. Used by [tokenized equity feeds](/data-feeds/tokenized-equity-feeds) that require continuous equity pricing outside of standard market hours. Feeds are not updated on weekends or US equity market holidays. | | **UK_ETF** | Standard UK equity market hours: 08:00 - 16:30 UK time M-F excluding UK equity market holidays. | | **Forex** | 18:00 ET Sunday to 17:00 ET Friday. <br /> The feeds also follow the global Forex market Christmas and New Year's Day holiday schedule. Many non-G12 currencies primarily trade during local market hours. It is recommended to use those feeds only during local trading hours. We generally observe normal trading within these hours. Prices outside of these hours may be subject to volatility and users are advised to implement additional controls. In addition, local holidays, natural disasters, political unrest or other exogenous shocks are liable to interrupt normal trading in less-liquid currencies. | | **Precious_Metals** | 18:00 ET Sunday to 17:00 ET Friday with a one-hour break Monday through Thursday from 17:00 to 18:00. <br /> The feeds also follow the global Forex market holiday schedule for Christmas and New Year's Day. | @@ -3231,12 +3738,11 @@ In addition to categories, be aware that markets for several assets are actively ## Risk Mitigation -As a development best practice, design your systems and smart contracts to be resilient and mitigate risk to your protocol and your users. Ensure that your systems can tolerate known and unknown exceptions that might occur. Some examples include but are not limited to volatile market conditions, the degraded performance of infrastructure, chains, or networks, and any other upstream outage related to data providers or node operators. You bear responsibility for any manner in which you use the Chainlink Network, its software, and documentation. +As a development best practice, design your systems and smart contracts to be resilient and mitigate risk to your protocol and your users. Ensure that your systems can tolerate known and unknown exceptions that might occur. Some examples include but are not limited to volatile market conditions, reduced price discovery availability, the degraded performance of infrastructure, chains, or networks, and any other upstream outage related to data providers or node operators. You bear responsibility for any manner in which you use the Chainlink Network, its software, and documentation. -To help you prepare for unforeseen market events, you should take additional steps to protect your application or protocol regardless of the market risk categorization of the Data Feeds your application consumes. The below tooling is put in place to mitigate extreme market events, possible malicious activity on third-party venues or contracts, potential delays, performance degradation, and outages. -Below are some examples of tooling that Chainlink users have put in place: +To help you prepare for unforeseen market events, you should take additional steps to protect your application or protocol regardless of the Market Pricing Risk categorization of the Data Feeds your application consumes. The below tooling is put in place to mitigate extreme market events, possible malicious activity on third-party venues or contracts, potential delays, performance degradation, and outages. Below are some examples of tooling that Chainlink users have put in place: -- **Circuit breakers:** In the case of an extreme price event, the contract would pause operations for a limited period of time. [Chainlink Automation](/chainlink-automation) is able to monitor data feeds to identify unexpected events. If an event were to occur, the Automation network can send an onchain transaction to pause or halt contract functionality. +- **Circuit breakers:** In the case of an extreme price event, the contract would pause operations for a limited period of time. [Chainlink Runtime Environment](/cre) is able to monitor data feeds to identify unexpected events. If an event were to occur, the Automation network can send an onchain transaction to pause or halt contract functionality. - **Contract update delays:** Contracts would not update until the protocol had received a recent fresh input from the data feed. - **Manual kill switch:** If a vulnerability or bug is discovered in one of the upstream contracts, the user can manually cease operation and temporarily sever the connection to the data feed. - **Monitoring:** Some users create their own monitoring alerts based on deviations in the data feeds that they are using. @@ -3246,6 +3752,10 @@ For more detailed information about some of these examples, see the [Monitoring For important updates regarding the use of Chainlink Price Feeds, users should join the official Chainlink Discord and subscribe to the [data-feeds-user-notifications channel](https://discord.gg/Dqy5N9UbsR). +### Stablecoin-specific considerations + +To protect against extreme stablecoin price events, protocols should assess upside risk and evaluate setting an explicit valuation ceiling for each stablecoin, along with mechanisms that provide proactive peg protection. One example of this approach is the Correlated-assets Price Oracle ([CAPO](https://app.aave.com/governance/v3/proposal/?proposalId=51)), which was implemented by Aave Labs with support from Chainlink Labs and adds upside protection when valuing fiat-pegged stablecoins while preserving full downside responsiveness. Other risk mitigation measures may be appropriate depending on a protocol's intended use case. Teams interested in developing similar risk mitigation measures for stablecoins can [contact the Chainlink Labs team](https://chain.link/contact?ref_id=DataFeed). Developers remain responsible for ensuring that protocol risk parameters are configured appropriately and that the operation and performance of stablecoin data feeds matches expectations. + ## Chainlink Community Deployments Chainlink technology is used by many within the blockchain community to support their use cases. Deployments built and run by community members are not tracked in the Chainlink documentation. Chainlink's community is continuously growing, and they play a vital role in developing the ecosystem, so the software and tooling are developed for anyone to use. Users have a wide variety of options for choosing how to deliver data onchain. They can deploy Chainlink nodes themselves or via the extensive network of node operators that offer services and access one of the community-managed oracle networks that support the supply of various types of data onchain. Chainlink Labs does not take responsibility for the use of Chainlink node software. @@ -3274,7 +3784,7 @@ If your smart contracts use data feeds, assess those data feeds for the followin ### Liquidity and its Distribution -If your smart contract relies on pricing data for a specific asset, make sure that the asset has a sufficiently healthy level of liquidity in the market to avoid price and market manipulation. Assets with low liquidity or volume can be volatile, which might negatively impact your application and its users. Malicious actors might try to exploit volatility or periods of reduced trading activity to take advantage of the logic in a smart contract and cause it to execute in a way that you did not intend. +If your smart contract relies on pricing data for a specific asset, make sure that the asset has a sufficiently healthy level of liquidity in the market to avoid price and market manipulation. Assets with low liquidity or volume can be volatile or difficult to price, which might negatively impact your application and its users. Malicious actors might try to exploit volatility or periods of reduced trading activity to take advantage of the logic in a smart contract and cause it to execute in a way that you did not intend. Some data feeds obtain their pricing data from individual exchanges rather than from aggregated price tracking services that gather their data from multiple exchanges. These are marked as such in the docs page for that feed. Assess the liquidity and reliability of that specific exchange. @@ -3286,7 +3796,7 @@ Design and test your contracts to handle price spikes and implement risk managem ### Single Source Data Providers -Some data providers use a single data source, which might be necessary if only one source exists onchain or offchain for a specific type of data. Evaluate data providers to make sure they provide high-quality data that your smart contracts can rely on. Any error or omission in the provider's data might negatively impact your application and its users. +Some data providers use a single data source, which might be necessary if only one source exists onchain or offchain for a specific type of data. Evaluate data providers to make sure they provide high-quality data that your smart contracts can rely on. Any error or omission in the provider's data might negatively impact your application and its users. Single Source Data Provider based feeds can be classified as high or very high market pricing risk and users should take precautions in consuming based on suitability. ### Crypto and Blockchain Actions @@ -3369,6 +3879,15 @@ When you use Data Feeds for ETFs or Foreign Exchange (Forex) data, be aware of t - Assets on the Forex (Foreign Exchange) markets are traded only during [defined market hours](/data-feeds/selecting-data-feeds#market-hours). Additionally, some currencies might trade only during local banking hours. Do not use Forex feeds outside market hours for the specific currency. - UK ETF price feed answers are 15 minutes delayed from their original published source. Assets are traded only during [standard market hours](/data-feeds/selecting-data-feeds#market-hours). Do not use these feeds outside their specified hours. +<Aside type="note" title="Disclaimer"> + Developers remain responsible for ensuring that protocol risk parameters are configured appropriately and that the + operation and performance of a Chainlink Data Feed matches expectations. The performance of a Chainlink Data Feed may + be affected by the availability or performance of a data provider. The composition or availability of a Chainlink Data + Feed may change over time. Please review this webpage in its entirety and review the [Chainlink Terms of + Service](https://chain.link/terms) for important information and disclosures. By using Chainlink Data Feeds, you + acknowledge and agree to these terms. +</Aside> + --- # SmartData Feed Addresses @@ -3454,6 +3973,45 @@ Using Solidity, your smart contract should reference [`AggregatorV3Interface`](h Example for reading a Proof of Reserve feed: +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; + +contract ReserveConsumerV3 { + AggregatorV3Interface internal reserveFeed; + + /** + * Network: Ethereum Mainnet + * Aggregator: WBTC PoR + * Address: 0xa81FE04086865e63E12dD3776978E49DEEa2ea4e + */ + constructor() { + reserveFeed = AggregatorV3Interface(0xa81FE04086865e63E12dD3776978E49DEEa2ea4e); + } + + /** + * Returns the latest price + */ + function getLatestReserve() public view returns (int256) { + // prettier-ignore + ( + /*uint80 roundID*/ + , + int256 reserve, + /*uint startedAt*/ + , + /*uint timeStamp*/ + , + /*uint80 answeredInRound*/ + ) = reserveFeed.latestRoundData(); + + return reserve; + } +} +``` + ### Using MVR Feeds [MVR feeds](/data-feeds/mvr-feeds) require a different approach compared to single-value SmartData feeds. Instead of returning a single numeric value, they return a bytes array that must be decoded into a specific data structure. @@ -3631,7 +4189,85 @@ Install the necessary components and include the example code in your project. O 9. Copy the sample code into your project. This example queries price data offchain. By default, the script reads the SOL/USD feed, but you can change the `CHAINLINK_FEED_ADDRESS` variable to point to the [feed account addresses](/data-feeds/price-feeds/addresses?network=solana) that you want to query. You can take the components of these code samples and integrate them with your existing project. Because these examples read data feeds without making any onchain changes, no lamports are required to run them. - <CodeSample src="samples/Solana/PriceFeeds/off-chain-read.ts" /> + ```js + /** + * THIS IS EXAMPLE CODE THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS EXAMPLE CODE THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + + const anchor = require("@project-serum/anchor") + const chainlink = require("@chainlink/solana-sdk") + const provider = anchor.AnchorProvider.env() + + async function main() { + anchor.setProvider(provider) + + const CHAINLINK_FEED_ADDRESS = "99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR" + const CHAINLINK_PROGRAM_ID = new anchor.web3.PublicKey("cjg3oHmg9uuPsP8D6g29NWvhySJkdYdAo9D25PRbKXJ") + const feedAddress = new anchor.web3.PublicKey(CHAINLINK_FEED_ADDRESS) //SOL-USD Devnet Feed + + //load the data feed account + let dataFeed = await chainlink.OCR2Feed.load(CHAINLINK_PROGRAM_ID, provider) + let listener = null + + //listen for events agains the price feed, and grab the latest rounds price data + listener = dataFeed.onRound(feedAddress, (event) => { + console.log(event.answer.toNumber()) + }) + + //block execution and keep waiting for events to be emitted with price data + await new Promise(function () {}) + } + + main().then( + () => process.exit(), + (err) => { + console.error(err) + process.exit(-1) + } + ) + ``` + + ```ts + /** + * THIS IS EXAMPLE CODE THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS EXAMPLE CODE THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + + import * as anchor from "@project-serum/anchor" + import { OCR2Feed } from "@chainlink/solana-sdk" + + async function main() { + const provider = anchor.AnchorProvider.env() + anchor.setProvider(provider) + + const CHAINLINK_FEED_ADDRESS = "99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR" + const CHAINLINK_PROGRAM_ID = new anchor.web3.PublicKey("cjg3oHmg9uuPsP8D6g29NWvhySJkdYdAo9D25PRbKXJ") + const feedAddress = new anchor.web3.PublicKey(CHAINLINK_FEED_ADDRESS) //SOL-USD Devnet Feed + + //load the data feed account + let dataFeed = await OCR2Feed.load(CHAINLINK_PROGRAM_ID, provider) + let listener: null | number = null + + //listen for events agains the price feed, and grab the latest rounds price data + listener = dataFeed.onRound(feedAddress, (event) => { + console.log(event.answer.toNumber()) + }) + + //block execution and keep waiting for events to be emitted with price data + await new Promise(function () {}) + } + + main().then( + () => process.exit(), + (err) => { + console.error(err) + process.exit(-1) + } + ) + ``` You can run these examples using the following commands: @@ -4139,7 +4775,7 @@ starkli --version 0.2.8 (f59724e) ``` -Follow the official [installation guide]((https://book.starkli.rs/installation)) if necessary. +Follow the official [installation guide](https://book.starkli.rs/installation) if necessary. ### Read data from a Chainlink Price Feed @@ -4811,7 +5447,7 @@ Traditional MEV searching depends on spotting oracle price updates in the public ### Example Application: Aave Liquidations -Aave is a lending protocol where collateralized positions must remain above a [threshold](https://aave.com/docs/concepts/liquidations) called their health factor. When an oracle price update reveals a borrower is undercollateralized, the position becomes eligible for liquidation. The searcher liquidates the position in exchange for a liquidation bonus reward. With Chainlink SVR, a searcher's liquidation transaction can be bundled with the new SVR price update through Flashbots. +Aave is a lending protocol where collateralized positions must remain above a [threshold](https://aave.com/help/borrowing/liquidations) called their health factor. When an oracle price update reveals a borrower is undercollateralized, the position becomes eligible for liquidation. The searcher liquidates the position in exchange for a liquidation bonus reward. With Chainlink SVR, a searcher's liquidation transaction can be bundled with the new SVR price update through Flashbots. For more background on how Aave liquidations work, see [Aave Documentation](https://docs.aave.com/). To understand how Chainlink SVR adds a structured auction for these Aave liquidation opportunities, read the following sections. @@ -4881,6 +5517,34 @@ The decoding process involves understanding two function calls: Below is an example of an ABI definition for the `forward` and `transmitSecondary` function interfaces to help you decode the function calls: +```json +[ + { + "type": "function", + "name": "forward", + "inputs": [ + { "name": "to", "type": "address" }, + { "name": "callData", "type": "bytes" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transmitSecondary", + "inputs": [ + { "name": "reportContext", "type": "bytes32[3]", "internalType": "bytes32[3]" }, + { "name": "report", "type": "bytes", "internalType": "bytes" }, + { "name": "rs", "type": "bytes32[]", "internalType": "bytes32[]" }, + { "name": "ss", "type": "bytes32[]", "internalType": "bytes32[]" }, + { "name": "rawVs", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +] +``` + The following code samples demonstrate the complete decoding process, including extracting the median price from the nested report structure. These implementations show how to: 1. Decode the `forward` function call @@ -4976,6 +5640,410 @@ This split provides DeFi protocols with an additional revenue stream while also --- +# Tokenized Equity Feeds +Source: https://docs.chain.link/data-feeds/tokenized-equity-feeds + +<TokenizedEquityFeeds section="tokenizedEquityNote" /> + +## What are tokenized equities? + +Tokenized equities are blockchain tokens that represent ownership or economic exposure to traditional stocks and ETFs. These tokens are distinct financial instruments issued by token issuers, not the underlying equities themselves. Tokenized equity feeds deliver the **primary market price representing the intrinsic value of the equity token** – this is the calculated theoretical token value and may account for long-term total return adjustments such as dividends or corporate actions. + +## About tokenized equity feeds + +Chainlink Tokenized Equity Feeds provide continuous 24/5 pricing for tokenized representations of US equities and ETFs. These feeds deliver the calculated primary market price of the token as determined by the issuer's pricing methodology, enabling DeFi protocols to accurately value tokenized equities across all major trading sessions in US markets, including regular hours, pre-market, post-market, and overnight (Eastern Standard Time). + +Tokenized equity feeds behave differently from standard crypto price feeds due to structural connections with underlying traditional equity markets affecting asset liquidity and pricing. Given the specialized nature of these feeds, all developers must reach out to Chainlink Labs prior to integrating these feeds and also review the [key differences](#key-differences-from-standard-feeds) and [risks](#risks) sections to understand how these characteristics may affect your application. + +See the [Provider Catalog](/data-feeds/tokenized-equity-feeds/providers) to view available feeds and issuer-specific implementations. + +## Why use tokenized equity feeds? + +Tokenized equities bring traditional stocks and ETFs onchain, but integrating them into DeFi protocols creates a fundamental challenge: US equity markets operate only 6.5 hours per trading day during regular hours, yet DeFi protocols operate continuously. Interest accrues around the clock, liquidation thresholds are monitored constantly, and risk parameters remain active regardless of underlying market hours. + +Chainlink Tokenized Equity Feeds help bridge this gap between TradFi and DeFi markets by: + +- **Providing continuous 24/5 pricing**: A single feed that spans regular, pre-market, post-market, and overnight sessions +- **Simplifying integration**: Consume one feed across trading sessions instead of managing multiple session-specific data sources +- **Applying session-aware smoothing**: Intelligent pricing algorithms that aim to reduce certain price anomalies during session transitions +- **Maintaining benchmark accuracy**: Optimized algorithms that are designed to track consolidated tape benchmarks with high fidelity +- **Performing tokenized price calculations**: Returning real-time calculated primary market valuations of tokenized equities based on the issuer's multiplier values. + +## Available tokenized equity feeds + +The following table shows all available tokenized equity feeds. + +## How tokenized equity feeds work + +Tokenized equity feeds leverage Chainlink's decentralized oracle infrastructure to aggregate price data from multiple trading sessions and apply session-aware smoothing algorithms. The feeds combine data from various trading venues into a single continuous 24/5 price, handling the complexity of multi-session equity markets. + +### Session coverage + +US equity markets exhibit distinct liquidity regimes throughout the 24-hour cycle: + +| Session | Hours (ET) | Liquidity | Characteristics | +| :-------------- | :-------------------- | :-------- | :-------------------------------------------- | +| Pre-Market | 04:00 – 09:30 | Rising | Increasing activity as regular hours approach | +| Regular Trading | 09:30 – 16:00 | Deep | Full liquidity, primary price discovery | +| Post-Market | 16:00 – 20:00 | Declining | Reduced liquidity, wider spreads | +| Overnight | 20:00 – 04:00 | Thin | Limited venues, potential for price spikes | +| Weekend | Fri 20:00 – Sun 20:00 | Zero | Traditional markets closed | + +### Session-aware smoothing + +To enable reliable, 24/5 continuous pricing, tokenized equity feeds apply intelligent smoothing during session transitions to target pricing integrity under different liquidity conditions. The smoothing methodology: + +1. **Tracks benchmark prices accurately** during liquid regular sessions +2. **Filters microstructure noise** during illiquid session transitions +3. **Reduces the risk of phantom liquidations** from transient price spikes in thin markets +4. **Converges quickly** after legitimate large price movements +5. **Minimizes tracking lag** to reduce mispricing during active trading + +Please note that while intelligent smoothing is designed to mitigate these issues, tokenized equities' structural connections with underlying traditional equity markets, liquidity, and pricing considerations require protocols to ensure performance of Chainlink Tokenized Equity Feeds matches expectations and is appropriate for the intended use case. + +### Input sources + +Tokenized equity feeds combine multiple input sources: + +- **Regular hours data**: Multi-sourced from consolidated tape data with deep liquidity +- **Extended hours data**: Pre-market and post-market venue data +- **Overnight data**: Data from overnight trading venues + +*Extended and overnight session data may be sourced from fewer providers than regular hours data, reflecting the reduced number of venues operating during these periods. See the [Limited Provider Coverage](#limited-provider-coverage-during-extended-and-overnight-sessions) risk section for details.* + +## Key differences from standard feeds + +While tokenized equity feeds use the same Chainlink infrastructure as standard crypto price feeds, they have distinct behaviors you should understand before integrating. + +### Continuous vs. point-in-time pricing + +Standard crypto price feeds reflect a single aggregated market price at a point in time from 24/7 markets. Tokenized equity feeds combine data from multiple trading sessions that have different operating hours, update frequencies, liquidity profiles, and data sources. The feed value represents a calculated return using the best mid-price for continuous 24/5 coverage of underlying equity markets. + +### Smoothing during transitions + +Standard feeds report raw aggregated prices. Tokenized equity feeds apply smoothing algorithms during session transitions in an effort to filter out microstructure noise and mitigate artificial volatility. This means: + +- Brief price spikes in illiquid sessions are dampened +- Convergence to new price levels after gaps is gradual rather than instantaneous +- The reported price may temporarily lag during rapid price movements + +For more information about this risk, see [Smoothing-induced Tracking Lag](#smoothing-induced-tracking-lag) below. + +### Variable data quality by session + +The reliability and accuracy of tokenized equity feeds varies by trading session: + +| Session | Data Quality | Provider Coverage | Update Frequency | +| :-------- | :----------- | :--------------------- | :--------------- | +| Regular | Highest | Multiple providers | Highest | +| Extended | Moderate | Limited providers | Moderate | +| Overnight | Lower | Very limited | Lower | +| Weekend | N/A | No traditional trading | Stale | + +### Provider-specific behaviors + +Tokenized equity feeds for assets from different issuers may differ in terms of their behavior and composition. Review the provider-specific documentation in the [Provider Catalog](/data-feeds/tokenized-equity-feeds/providers) before integrating one of these feeds. + +*** + +## Risks + +Tokenized equity feeds introduce specific risks related to the nature of traditional equity markets, multi-session data aggregation, smoothing algorithms, and data sourcing. Users must understand these factors and implement appropriate safeguards. + +### Limited provider coverage during extended and overnight sessions + +Extended and overnight session price data is sourced from a more limited number of data providers compared to regular hours, making these sessions less reliable than regular hours feeds, which are aggregated from a broader set of providers. + +If providers experience downtime, technical failures, or connectivity disruption, the feed may flatline or report stale values. Such issues may lead to mispricing, failed liquidations, and potential bad debt accumulation. + +#### Mitigation + +- Implement staleness detection by monitoring the feed's last update timestamp +- Define protocol behavior for when data stops updating (pause operations, use bounded trading ranges, or implement fallback logic) +- Consider restricting high-risk operations (large liquidations, new positions) during extended and overnight sessions + +### Structural illiquidity during extended hours + +Pre-market, post-market, and overnight sessions are inherently less liquid than regular trading hours. This results in: + +- **Wider bid-ask spreads**: Higher transaction costs and less reliable mid-prices +- **Stale ticks**: Longer intervals between price updates +- **Price gaps**: Larger price movements on individual trades +- **Higher volatility**: Increased susceptibility to large orders moving prices + +These conditions are inherent to the underlying markets, not the feed itself, but will be visible in the published data. + +#### Mitigation + +- Evaluate whether full 24/5 coverage is appropriate for your use case, or if restricting operations to regular hours is safer +- Configure session-specific risk thresholds, circuit breakers, or mode switching aligned with your risk appetite +- Apply additional safeguards (wider liquidation buffers, reduced leverage) during lower-liquidity sessions +- Validate configurations during integration testing, not post-deployment + +### Price jumps at session transitions + +When transitioning between sessions (Regular ↔ Extended ↔ Overnight), price dislocations can occur due to: + +- Different liquidity conditions between sessions +- Different venues and participants per session +- Accumulated order flow during closed periods +- News events occurring outside regular hours +- Shifts in data provider coverage between sessions (i.e., different cohorts of data providers contributing to the aggregated price) + +These are expected market microstructure effects, not data quality issues. Typical jumps are minor, but larger spikes are possible during low-liquidity environments or impactful news cycles. + +#### Mitigation + +- Implement transition-aware logic that expects and handles price gaps +- Consider pausing or restricting operations during transition windows +- Apply additional smoothing or price change limits during transitions +- Use time-weighted averages (TWAP) or exponential moving averages (EMA) for risk-sensitive calculations + +### Smoothing-induced tracking lag + +The session-aware smoothing that mitigates phantom liquidations also introduces tracking lag: a delay between market price movements and the reported feed price. During rapid legitimate price moves: + +- The smoothed price will temporarily trail the true market price +- Convergence typically occurs within seconds to tens of seconds +- In extreme cases, this may result in delayed liquidations or arbitrage opportunities + +#### Mitigation + +- Understand the trade-off: smoothing protects against false liquidations but delays real ones +- Configure your protocol's risk parameters to account for potential tracking lag +- Consider the tracking lag characteristics when setting liquidation thresholds +- Monitor for persistent deviation between tokenized equity feeds and other market data sources + +### Weekend and holiday behavior + +Traditional equity markets are closed on weekends and holidays. During these periods: + +- The feed will report the last closing price prior to the holiday market close +- No new price discovery occurs in the underlying markets +- The staleness indicator will show increasingly old timestamps + +This reflects true underlying market inactivity rather than an outage or failure. + +#### Mitigation + +- Treat weekends and holidays as expected states requiring specific protocol behavior +- Options include: pausing operations, allowing restricted trading within bounded ranges, or referencing tokenized asset prices on secondary markets +- Incorporate authoritative exchange holiday calendars (NYSE/NASDAQ for US equities) into your integration +- Define deterministic behaviors for these periods before deployment + +### Corporate actions + +Traditional equities are subject to corporate actions that can dramatically change asset prices: + +- **Stock splits and reverse splits**: Can cause overnight price changes of 2x, 10x, or more +- **Dividends**: Ex-dividend date adjustments affect pricing +- **Mergers and acquisitions**: May cause trading halts or significant price changes +- **Spin-offs**: New securities with separate pricing + +These actions are usually announced outside regular trading hours. The feed will reflect these price changes when markets reopen, which may appear as sudden large moves. + +#### Mitigation + +- Actively monitor corporate action announcements for assets in your protocol +- Adjust pricing logic, risk parameters, and position limits around corporate action dates +- Consider pausing markets during corporate action windows +- Implement maximum price change limits with manual review for extreme moves + +### Market closures and halts not explicitly flagged + +Tokenized equity feeds do not explicitly flag: + +- Exchange public holidays +- Trading halts (regulatory, news-pending, circuit breakers) +- Other operational closures + +During these periods, the feed may appear stale or flatline. This reflects true market inactivity, not a data quality issue. + +#### Mitigation + +- Implement staleness checks comparing the feed's last update timestamp to current time +- Define protocol behavior for stale data scenarios +- Monitor exchange halt notifications independently +- Do not rely solely on feed freshness to determine market status. Users should incorporate external market status sources where available. + +*** + +## Best practices + +### Protocol design + +- **Set deviation limits**: Cap maximum acceptable price changes per update or per time window +- **Define fallback behavior**: Determine what happens if the feed stops updating or deviates beyond thresholds +- **Implement session awareness**: Consider different risk parameters for different trading sessions +- **Test extensively**: Validate protocol behavior during session transitions, weekends, and simulated failure scenarios before production deployment + +### Monitoring + +- **Track staleness**: Alert when no new updates arrive within expected frequency +- **Monitor deviation**: Compare tokenized equity feed values against other market data sources when available +- **Log session transitions**: Track behavior during session changes to identify patterns +- **Set up alerts**: Notify operators of unusual price movements, extended staleness, or deviation from expected ranges + +### Integration testing + +Before deploying to production: + +1. Test behavior during each trading session (regular, extended, overnight) +2. Validate handling of session transitions +3. Simulate weekend and holiday behavior +4. Test failure scenarios (stale data, extreme price moves, data gaps) +5. Verify your staleness detection and fallback logic works correctly + +When using tokenized equity feeds, you inherit all responsibilities associated with standard price feeds plus additional responsibilities for understanding session-specific risks, equity market dynamics, and multi-source data quality. Review the [Developer Responsibilities](/data-feeds/developer-responsibilities) page for comprehensive guidance. + +*** + +## FAQ + +### How is market data sourced for tokenized equity feed calculation? + +Tokenized equity feeds use the [Data Streams v11 report schema](/data-streams/reference/report-schema-v11) for sourcing the underlying equity market price. + +### How are total return values (stock splits, multipliers, market pauses) determined? + +These values are sourced from the asset issuer. Learn more in the [Provider Catalog](/data-feeds/tokenized-equity-feeds/providers). + +--- + +# Ondo Finance Global Markets (GM) +Source: https://docs.chain.link/data-feeds/tokenized-equity-feeds/ondo + +<TokenizedEquityFeeds section="tokenizedEquityNote" /> + +Chainlink provides tokenized equity feeds for Ondo Finance Global Markets (GM) tokenized equities. These feeds differ from standard market-rate feeds in that they report **Total Return Values** rather than raw equity prices. + +## Available Ondo tokenized equity feeds + +The following table shows the available Ondo tokenized equity feeds. + +## Total Return Value calculation + +Ondo tokenized equity feeds calculate the token price using the following formula: + +``` +Token Price = Underlying Equity Market Price × Multiplier (sValue) +``` + +Where: + +- **Underlying Equity Market Price**: Sourced from Chainlink's 24/5 equity price feeds, which aggregate data across regular, pre-market, post-market, and overnight trading sessions +- **Multiplier (`sValue`)**: Sourced from Ondo's `SyntheticSharesOracle` contract, which tracks dividend reinvestments and corporate action adjustments (see [Corporate action handling](#corporate-action-handling) below). + +This approach ensures that the token price reflects the total return of the underlying equity, including dividend reinvestments and corporate action adjustments, rather than just the current market price per share. + +## How the multiplier works + +The multiplier (`sValue`) accounts for events that change the relationship between token quantity and underlying equity value: + +| Event Type | Multiplier Behavior | Example | +| :--------------------------- | :------------------------------------ | :---------------------- | +| Dividend reinvestment | Small increase (less than 1% per day) | `sValue`: 1.000 → 1.008 | +| Stock split (10:1 example) | Large increase | `sValue`: 1.0 → 10.0 | +| Reverse split (1:10 example) | Large decrease | `sValue`: 10.0 → 1.0 | +| Spin-offs | Adjustment to reflect new value | Varies by event | + +The `SyntheticSharesOracle` contract enforces two update paths: + +- **Small updates** (≤1% per 24-hour period): Applied immediately via automated processes. These handle routine dividend reinvestments. +- **Large updates** (>1%): Requires a scheduled pause window and manual confirmation. These handle major corporate actions like stock splits. + +## Corporate action handling + +Large corporate actions require special handling to maintain price continuity. The system operates in two modes: + +**Normal mode**: The feed returns the current stock price multiplied by the current `sValue`. + +**Corporate action mode**: When a large corporate action is scheduled, the system enters a pause state where: + +1. The pause is scheduled at least 24 hours in advance +2. At the scheduled pause time, the price freezes at the last known good value +3. The new `sValue` is staged but not yet applied +4. After the corporate action takes effect and Ondo confirms that both the stock price and `sValue` reflect the new values correctly, the system is manually unpaused +5. The new `sValue` takes effect, and normal operation resumes + +This pause mechanism ensures price continuity during corporate actions. For example, during a 10:1 stock split: + +| Stage | Stock Price | `sValue` | Token Price | +| :------------ | :---------- | :------------ | :------------ | +| Before split | $200 | 1.0 | $200 | +| During pause | Frozen | Pending: 10.0 | $200 (frozen) | +| After unpause | $20 | 10.0 | $200 | + +The token price remains continuous at $200 throughout the event, even though the underlying equity market price dropped from $200 to $20. + +<Aside type="note"> + When the `SyntheticSharesOracle` contract returns `paused = true`, the Chainlink feed freezes at the last known good + price. Integrators should be aware that during pause windows: + + - The feed will not update until manually unpaused + - The pause duration depends on when Ondo confirms the corporate action has been correctly applied + - A minimum pause duration (at least 10 minutes) is enforced to prevent premature unpausing +</Aside> + +## Example scenarios + +**Normal operation** + +``` +- Stock price: $200 → $201 +- sValue: 1.000 (unchanged) +- Token price: $201 +``` + +**Dividend reinvestment** (small `sValue` drift) + +``` +- Stock price: $200 +- sValue: 1.000 → 1.008 (0.8% increase, within allowed drift) +- Token price: $201.60 +``` + +**Stock split** (10:1, scheduled corporate action) + +``` +1. Ondo schedules pause for Tuesday 8pm with `newSValue = 10` +2. At 8pm, feed freezes at current token price +3. Market opens Wednesday with stock price at $20 (post-split) +4. Ondo confirms alignment and unpauses +5. sValue becomes 10.0, token price = $20 × 10 = $200 (continuous) +``` + +**Split with timing mismatch** (stock price updates before `sValue`) + +``` +- Scheduled pause at Tuesday 8pm with `newSValue = 10` +- At 8:01pm: stock price = $20, sValue = 1.0 (not yet updated) +- Result: Feed remains frozen at the pre-pause price until Ondo confirms the sValue update and unpauses +``` + +This fail-safe behavior prevents incorrect token prices from being published when the stock price and `sValue` are temporarily out of sync. + +--- + +# Asset Issuer Catalog +Source: https://docs.chain.link/data-feeds/tokenized-equity-feeds/providers + +<TokenizedEquityFeeds section="tokenizedEquityNote" /> + +Tokenized equity feeds have issuer-specific implementations that affect pricing methodology, data handling, and operational behavior. This page catalogs the available issuers and their key characteristics. + +## Available providers + +| Provider | Feed Type | Price Calculation | Corporate Action Handling | Documentation | Issuer Contact | +| :----------- | :----------------- | :----------------------------------------------------- | :----------------------------------- | :------------------------------------------------------ | :------------------------------------ | +| Ondo Finance | Total Return Value | Underlying Equity Market Price × Multiplier (`sValue`) | Pause-based with manual confirmation | [View details](/data-feeds/tokenized-equity-feeds/ondo) | [Contact page](https://ondo.finance/) | + +## Provider-specific considerations + +Each provider may implement tokenized equity feeds differently based on their token design and corporate action handling requirements. Review the provider-specific documentation and contact Chainlink Labs at [chainlink_data_feeds@smartcontract.com](mailto:chainlink_data_feeds@smartcontract.com) before integrating their tokenized equity feeds into your protocol. + +--- + # Using Data Feeds on Tron Source: https://docs.chain.link/data-feeds/tron @@ -5245,6 +6313,59 @@ These code examples demonstrate how to deploy a consumer contract onchain that r To consume price data, your smart contract should reference [`AggregatorV3Interface`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol), which defines the external functions implemented by Data Feeds. +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED + * VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/** + * If you are reading data feeds on L2 networks, you must + * check the latest answer from the L2 Sequencer Uptime + * Feed to ensure that the data is accurate in the event + * of an L2 sequencer outage. See the + * https://docs.chain.link/data-feeds/l2-sequencer-feeds + * page for details. + */ +contract DataConsumerV3 { + AggregatorV3Interface internal dataFeed; + + /** + * Network: Sepolia + * Aggregator: BTC/USD + * Address: 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43 + */ + constructor() { + dataFeed = AggregatorV3Interface(0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43); + } + + /** + * Returns the latest answer. + */ + function getChainlinkDataFeedLatestAnswer() public view returns (int256) { + // prettier-ignore + ( + /* uint80 roundId */ + , + int256 answer, + /*uint256 startedAt*/ + , + /*uint256 updatedAt*/ + , + /*uint80 answeredInRound*/ + ) = dataFeed.latestRoundData(); + return answer; + } +} +``` + The `latestRoundData` function returns five values representing information about the latest price data. See the [Data Feeds API Reference](/data-feeds/api-reference) for more details. ### Vyper @@ -5266,6 +6387,27 @@ This example uses [web3.js](https://web3js.readthedocs.io/) to retrieve feed dat This example uses [Web3.py](https://web3py.readthedocs.io/en/stable/) to retrieve feed data from the [BTC / USD feed](https://sepolia.etherscan.io/address/0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43) on the Sepolia testnet. +```py +# THIS IS EXAMPLE CODE THAT USES HARDCODED VALUES FOR CLARITY. +# THIS IS EXAMPLE CODE THAT USES UN-AUDITED CODE. +# DO NOT USE THIS CODE IN PRODUCTION. + +from web3 import Web3 + +# Change this to use your own RPC URL +web3 = Web3(Web3.HTTPProvider('https://rpc.ankr.com/eth_sepolia')) +# AggregatorV3Interface ABI +abi = '[{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"_roundId","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]' +# Price Feed address +addr = '0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43' + +# Set up contract instance +contract = web3.eth.contract(address=addr, abi=abi) +# Make call to latestRoundData() +latestData = contract.functions.latestRoundData().call() +print(latestData) +``` + ### Golang You can find an example with all the source files [here](https://github.com/smartcontractkit/smart-contract-examples/tree/main/pricefeed-golang). This example uses [go-ethereum](https://github.com/ethereum/go-ethereum) to retrieve feed data from the [BTC / USD feed](https://sepolia.etherscan.io/address/0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43) on the Sepolia testnet. @@ -5283,6 +6425,60 @@ If you require a denomination other than what is provided, you can use two data If your contracts require Solidity versions that are `>=0.6.0 <0.8.0`, use [OpenZeppelin's SafeMath version 3.4](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/math/SafeMath.sol). </Aside> +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; + +/** + * Network: Sepolia + * Base: BTC/USD + * Base Address: 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43 + * Quote: EUR/USD + * Quote Address: 0x1a81afB8146aeFfCFc5E50e8479e826E7D55b910 + * Decimals: 8 + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract PriceConverter { + function getDerivedPrice( + address _base, + address _quote, + uint8 _decimals + ) public view returns (int256) { + require(_decimals > uint8(0) && _decimals <= uint8(18), "Invalid _decimals"); + int256 decimals = int256(10 ** uint256(_decimals)); + (, int256 basePrice,,,) = AggregatorV3Interface(_base).latestRoundData(); + uint8 baseDecimals = AggregatorV3Interface(_base).decimals(); + basePrice = scalePrice(basePrice, baseDecimals, _decimals); + + (, int256 quotePrice,,,) = AggregatorV3Interface(_quote).latestRoundData(); + uint8 quoteDecimals = AggregatorV3Interface(_quote).decimals(); + quotePrice = scalePrice(quotePrice, quoteDecimals, _decimals); + + return (basePrice * decimals) / quotePrice; + } + + function scalePrice( + int256 _price, + uint8 _priceDecimals, + uint8 _decimals + ) internal pure returns (int256) { + if (_priceDecimals < _decimals) { + return _price * int256(10 ** uint256(_decimals - _priceDecimals)); + } else if (_priceDecimals > _decimals) { + return _price / int256(10 ** uint256(_priceDecimals - _decimals)); + } + return _price; + } +} +``` + ## More aggregator functions Getting the latest price is not the only data that aggregators can retrieve. You can also retrieve historical price data. To learn more, see the [Historical Price Data](/data-feeds/historical-data) page. diff --git a/src/content/data-feeds/selecting-data-feeds.mdx b/src/content/data-feeds/selecting-data-feeds.mdx index 57cbcc67ccd..e450d19ebde 100644 --- a/src/content/data-feeds/selecting-data-feeds.mdx +++ b/src/content/data-feeds/selecting-data-feeds.mdx @@ -8,7 +8,7 @@ metadata: import { Aside } from "@components" -When you design your applications, consider the quality of the data that you use in your smart contracts. Ultimately you are responsible for identifying and assessing the accuracy, availability, and quality of data that you choose to consume via the Chainlink Network. Note that all feeds contain some inherent risk. Read the [Risk Mitigation](#risk-mitigation) and [Evaluating Data Sources](#evaluating-data-sources-and-risks) sections when making design decisions. Chainlink lists decentralized data feeds in the documentation to help developers build new applications integrated with data. +When you design your applications, consider the quality of the data that you use in your smart contracts. Ultimately you are responsible for identifying and assessing the accuracy, availability, and quality of data that you choose to consume via the Chainlink Network. Note that all feeds contain some inherent risk. Read the [Risk Mitigation](#risk-mitigation) and [Evaluating Data Sources](#evaluating-data-sources-and-risks) sections when making design decisions. Chainlink lists decentralized data feeds in the documentation to help developers build new applications integrated with data. Please review this page in its entirety to understand the risks and categories relevant to your data feed implementation. For a summary of data sourcing models by asset type, see [Data Sources](/data-feeds/data-sources). @@ -16,16 +16,15 @@ For a summary of data sourcing models by asset type, see [Data Sources](/data-fe This categorization is put in place to inform users about the intended use cases of feeds and help highlight some of the inherent market integrity risks surrounding the data quality of these feeds. -All feeds published on [docs.chain.link](http://docs.chain.link) are monitored and maintained to the same levels and standards. Each feed goes through a rigorous assessment process when implemented. The assessment criteria can vary depending on the product type of feed being deployed or change over time as the understanding of market integrity risks evolves. +Market price feeds incorporate three layers of aggregation at the data source, node operator, and oracle network layers, providing industry-standard security and reliability on the price data they reference. -Market price feeds incorporate three layers of aggregation at the data source, node operator, and oracle network layers, providing industry-standard security and reliability on the price data they reference. To learn more about the three layers of data aggregation, see the blog post about [Data Aggregation in Chainlink Price Feeds](https://blog.chain.link/levels-of-data-aggregation-in-chainlink-price-feeds/). Additional information about how Chainlink Data Feeds are secured can be seen in the blog post about [How Chainlink Price Feeds Secure the DeFi Ecosystem](https://blog.chain.link/chainlink-price-feeds-secure-defi/). +Data feeds are grouped into the following categories based on the level of market pricing risk, based on multiple factors, from lowest to highest: -Data feeds are grouped into the following categories based on the level of market integrity risk from lowest to highest: - -- [🟢 Low Market Risk](#-low-market-risk-feeds) -- [🟡 Medium Market Risk](#-medium-market-risk-feeds) -- [🔴 High Market Risk](#-high-market-risk-feeds) -- [🟠 New Token Feeds](#-new-token-feeds) +- [🟢 Low Market Pricing Risk](#-low-market-pricing-risk-feeds) +- [🟡 Medium Market Pricing Risk](#-medium-market-pricing-risk-feeds) +- [🟠 High Market Pricing Risk](#-high-market-pricing-risk-feeds) +- [🔴 Very High Market Pricing Risk](#-very-high-market-pricing-risk-feeds) +- [🆕 New Token Feeds](#-new-token-feeds) - [🔵 Custom Feeds](#-custom-feeds) - [⭕ Deprecating](#-deprecating) @@ -34,64 +33,71 @@ Data feeds are grouped into the following categories based on the level of marke subscribe to the [#data-feeds channel](https://discord.gg/Dqy5N9UbsR). </Aside> -### 🟢 Low Market Risk Feeds +### 🟢 Low Market Pricing Risk Feeds These are data feeds that follow a standardized data feeds workflow to report market prices for an asset pair. Chainlink node operators each query several sources for the market price and aggregate the estimates provided by those sources. -Low Market Risk feeds have the following characteristics: +Low Market Pricing Risk feeds have the following characteristics: -- Highly resilient to disruption -- Leverage many data sources -- High volumes across a large number of markets enable consistent price discovery +- More resilient to disruption than other feeds +- Leverage multiple data sources when they are available +- Higher volumes across multiple markets enables price discovery -While market risk may be low, other risks might still exist based on your use case, the blockchain on which the feed is deployed, and the conditions on that chain. +While Market Pricing Risk may be categorized as low, other risks might still exist based on your use case, data provider availability or performance, the blockchain on which the feed is deployed, and the conditions on that chain. Developers remain responsible for ensuring that protocol [risk parameters are configured appropriately](#risk-mitigation) and that the operation and performance of Low Market Pricing Risk data feeds match expectations. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. -### 🟡 Medium Market Risk Feeds +### 🟡 Medium Market Pricing Risk Feeds -These feeds also follow a standardized data feeds workflow to report market prices for an asset pair. The pair in question may have features that make it more challenging to reliably price, or potentially subject it to volatility which may pose a risk in some use cases. While the architecture of these feeds is resilient and distributed, these feeds carry additional market risk. +These feeds also follow a standardized data feeds workflow to report market prices for an asset pair. The pair in question may have features that make it more challenging to reliably price, or potentially subject it to volatility, which may pose a risk in some use cases. While the architecture of these feeds is resilient and distributed, these feeds carry additional Market Pricing Risk. -Types of market risk that may lead to a feed being categorized as Medium Market Risk include: +Types of Market Pricing Risk that may lead to a feed being categorized as Medium Market Pricing Risk include: -- Lower or inconsistent asset volume may result in periods of low liquidity in the market for such assets. This, in turn, can lead to volatile price movements +- Lower or inconsistent asset volume may result in periods of low liquidity in the market for such assets. This, in turn, can lead to volatile price movements. - A spread between the price for this asset on different trading venues or liquidity pools. - Market Concentration Risk: If the volume for a given asset is excessively concentrated on a single exchange, that trading venue could become a single point of failure for the feed. - Cross-Rate Risk: The base asset trades in large volumes against assets that are not pegged to the quote asset. As a result, the price of this specific asset pair may fluctuate even if the underlying asset is not being traded. - The asset is going through a significant market event such as a token or liquidity migration. - The asset has a high spread between data providers, the root cause of which is often one of the above factors. +- The availability of pricing sources may be subject to change based on concentration, trading venue location, and currency pairs. + +Developers remain responsible for ensuring that protocol [risk parameters are configured appropriately](#risk-mitigation) and that the operation and performance of Medium Market Pricing Risk data feeds matches expectations. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. + +### 🟠 High Market Pricing Risk Feeds -### 🔴 High Market Risk Feeds +These feeds also follow a standardized data feeds workflow to report market prices for an asset pair. However, the pair in question often exhibits a heightened degree of some of the risk factors outlined under Medium Market Pricing Risk, or a separate risk that makes the market price subject to uncertainty or volatility. In using a High Market Pricing Risk data feed you acknowledge that you understand the risks associated with such a feed and that you are solely responsible for monitoring and mitigating such risks. Developers remain responsible for ensuring that protocol [risk parameters are configured appropriately](#risk-mitigation) and that the operation and performance of High Market Pricing Risk data feeds matches expectations. High Market Pricing Risk data feeds may be deprecated. See the [Data Feed Shutdown Policy](#data-feed-shutdown-policy) for more information. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. -These feeds also follow a standardized data feeds workflow to report market prices for an asset pair. However, the pair in question often exhibits a heightened degree of some of the risk factors outlined under “Medium Market Risk”, or a separate risk that makes the market price subject to uncertainty or volatility. In using a High Market Risk data feed you acknowledge that you understand the risks associated with such a feed and that you are solely responsible for monitoring and mitigating such risks. +### 🔴 Very High Market Pricing Risk Feeds -Types of market risk that may lead to a feed being categorized as High Market Risk include: +Very High Market Pricing Risk feeds price assets with quotes that are subject to extreme levels of risk, greater than those outlined above for High Market Pricing Risk. Types of Market Pricing Risk that may lead to a feed being categorized as Very High Market Pricing Risk include, but are not limited to: - The asset is going through a significant market event such as a hack, bridge failure, or a delisting from a major exchange. - The asset or project is being deprecated in the market. - Volumes have dropped to extremely low levels. +- Reliable pricing sources for asset are extremely limited. -### 🟠 New Token Feeds +Users should wind down their reliance on these feeds and/or implement strict capital and risk management policies accounting for extreme price and market structure volatility. Very High Market Pricing Risk feeds will be wound down over time in accordance with the [Data Feed Shutdown Policy](#data-feed-shutdown-policy). In using a Very High Market Pricing Risk data feed you acknowledge that you understand the risks associated with such a feed and that you are solely responsible for monitoring and mitigating such risks. You understand that Chainlink may not provide separate monitoring for these feeds. Developers remain responsible for ensuring that protocol [risk parameters are configured appropriately](#risk-mitigation) and that the operation and performance of Very High Market Pricing Risk data feeds matches expectations. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. -When a token is newly launched, the historical data required to implement a rigorous risk assessment framework that would allow the categorization of a market data feed for that token as low, medium, or high market risk is unavailable. Consistent price discovery may involve an indeterminate amount of time. Users must understand the additional [market and volatility risks](https://docs.chain.link/data-feeds/selecting-data-feeds#evaluating-data-sources-and-risks) inherent with such assets. Users of new token feeds are responsible for independently verifying the liquidity and stability of the assets priced by the feeds that they use. -At the end of a probationary period, the status of new token feeds may be adjusted to high/medium/low market risk or in rare cases be deprecated entirely. +### 🆕 New Token Feeds + +When a token is newly launched, the historical data required to implement a rigorous risk assessment framework that would allow the categorization of a market data feed for that token as Low, Medium, or High Pricing Risk is unavailable. Consistent price discovery may involve an indeterminate amount of time. Users must understand the additional [market and volatility risks](#evaluating-data-sources-and-risks) inherent with such assets. Users of New Token feeds are responsible for independently verifying the liquidity and stability of the assets priced by the feeds that they use. At the end of a probationary period, the status of New Token feeds may be adjusted to Very High, High, Medium, or Low Market Pricing Risk, or in rare cases be deprecated entirely. For users integrating a custom feed, please review the [Custom Feed](#-custom-feeds) section for additional considerations. ### 🔵 Custom Feeds Custom Feeds are built to serve a specific use case and might not be suitable for general use or your use case's risk parameters. Users must evaluate the properties of a feed to make sure it aligns with their intended use case. [Contact the Chainlink Labs team](https://chain.link/contact?ref_id=DataFeed) if you want more detail on any specific feeds in this category. -Custom feeds have the following categories and compositions: +Custom Feeds have the following categories and compositions: -- Onchain single source feeds: These feeds take their data from an onchain source, however, the feed has only a single data provider currently supporting the feed. -- Onchain Proof of Reserve Feeds: Chainlink Proof of Reserve uses a large decentralized collection of security-reviewed and Sybil-resistant node operators to acquire and verify reserve data. In this use case, reserves reside onchain. -- Exchange Rate Feeds: These feeds read an exchange rate from an external contract onchain that is designed to allow conversion from one token to another. Chainlink does not own or control these contracts in any way. They are not equivalent to market price feeds. -- Technical Feeds: Feeds within this category measure a particular technical metric from a specified blockchain. For example, Fast Gas or Block Difficulty. -- Total Value Locked Feeds: These feeds measure the total value locked in a particular protocol. -- Custom Index Feeds: An index calculates a function of the values for multiple underlying assets. The function is specific to that index and is typically calculated by node operators following an agreed formula. -- Offchain Single Source Feeds: Some data providers use a single data source, which might be necessary if only one source exists offchain for a specific type of data. -- Offchain Proof of Reserve Feeds: Chainlink Proof of Reserve uses a large decentralized collection of security-reviewed and Sybil-resistant node operators to acquire and verify reserve data. In this use case, reserves reside offchain. -- LP Token Feeds: These feeds use a decentralized feed for the underlying asset as well as calculations to value the liquidity pool (LP) tokens. -- Wrapped Calculated Feeds: These feeds are typically pegged 1:1 to the underlying token or asset. Under normal market conditions, these feeds track their underlying value accurately. However, given that the price is a derivative formed from a calculated method, the derivative asset may not always precisely track the value of the underlying token or asset precisely. +- [🟠](#-high-market-pricing-risk-feeds) **Onchain Single Source Feeds:** These feeds take their data from an onchain source, however, the feed has only a single data provider currently supporting the feed. +- [🟡](#-medium-market-pricing-risk-feeds) **Onchain Proof of Reserve Feeds:** Chainlink Proof of Reserve uses a large decentralized collection of security-reviewed and Sybil-resistant node operators to acquire and verify reserve data. In this use case, reserves reside onchain. +- [🟡](#-medium-market-pricing-risk-feeds) **Exchange Rate Feeds:** These feeds read an exchange rate from an external contract onchain that is designed to allow conversion from one token to another. Chainlink does not own or control these contracts in any way. They are not equivalent to market price feeds. +- [🟡](#-medium-market-pricing-risk-feeds) **Technical Feeds:** Feeds within this category measure a particular technical metric from a specified blockchain. For example, Fast Gas or Block Difficulty. +- [🟡](#-medium-market-pricing-risk-feeds) **Total Value Locked Feeds:** These feeds measure the total value locked in a particular protocol. +- [🟠](#-high-market-pricing-risk-feeds) **Custom Index Feeds:** An index calculates a function of the values for multiple underlying assets. The function is specific to that index and is typically calculated by node operators following an agreed formula. +- [🟠](#-high-market-pricing-risk-feeds) **Offchain Single Source Feeds:** Some data providers use a single data source, which might be necessary if only one source exists offchain for a specific type of data. +- [🟠](#-high-market-pricing-risk-feeds) **Offchain Proof of Reserve Feeds:** Chainlink Proof of Reserve uses a large decentralized collection of security-reviewed and Sybil-resistant node operators to acquire and verify reserve data. In this use case, reserves reside offchain. +- [🟠](#-high-market-pricing-risk-feeds) **LP Token Feeds:** These feeds use a decentralized feed for the underlying asset as well as calculations to value the liquidity pool (LP) tokens. +- [🔴](#-very-high-market-pricing-risk-feeds) **Wrapped Calculated Feeds:** These feeds are typically pegged 1:1 to the underlying token or asset. Under normal market conditions, these feeds track their underlying value accurately. However, given that the price is a derivative formed from a calculated method, the derivative asset may not always precisely track the value of the underlying token or asset. -If you plan on using one of these feeds and would like to get a more detailed understanding, [contact the Chainlink Labs team](https://chain.link/contact?ref_id=DataFeed). +If you plan on using one of these feeds and would like to get a more detailed understanding, [contact the Chainlink Labs team](https://chain.link/contact?ref_id=DataFeed). Using feeds that were not specifically designed for your use case involves risk. Their use might pose risks that could result in harm to your project. Users are responsible for thoroughly vetting and validating such deployments and determining their suitability. You bear responsibility for any manner in which you use the Chainlink Network, its software, and documentation. ### ⭕ Deprecating @@ -99,9 +105,16 @@ These feeds are being deprecated. To find the deprecation dates for specific fee #### Data Feed Shutdown Policy -Data feeds managed by Chainlink Labs will be considered for deprecation if they pose a risk to the Chainlink Community and broader ecosystem, if the asset or assets on the feed have significantly deteriorated and no longer meet our Quality Assurance standards, or if the data feed has become economically unsustainable to support. +Data feeds managed by Chainlink Labs will be considered for deprecation if they pose a risk to the Chainlink Community and broader ecosystem, if the asset or assets (or their volume or liquidity) on the feed have significantly deteriorated or are unreliable and no longer meet our Quality Assurance standards, or if the data feed has become economically unsustainable to support. Users are therefore advised to ensure they have measures in place for the orderly deprecation of reliance on specific Chainlink price feeds. + +Known users of these feeds will be contacted directly about the feeds' deprecation whenever possible. Notifications will also be posted on the [Feeds Scheduled For Deprecation](/data-feeds/deprecating-feeds) page and on our [Discord channel](https://discord.com/channels/592041321326182401/991444378335838318) with two weeks of notice before they are shut down except where conditions require an accelerated deprecation. -Known users of these feeds will be contacted directly about the feeds' deprecation. Notifications will also be posted on the [Feeds Scheduled For Deprecation](/data-feeds/deprecating-feeds) page and on our [Discord channel](https://discord.com/channels/592041321326182401/991444378335838318) with two weeks of notice before they are shut down. +{/* prettier-ignore */} +<Aside type="note" title="Data Feed Shutdown Behavior"> + Once a feed is shutdown, calls to the feed will behave as follows: + - `lastAnswer` will return `0` + - `latestRoundData` will revert with no data available +</Aside> ## Market hours @@ -111,6 +124,7 @@ In addition to categories, be aware that markets for several assets are actively | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Crypto** | 24/7/365 - No market close. | | **US_Equities** | Standard US equity market hours: 09:30 - 16:00 ET M-F excluding US equity market holidays. | +| **US_Equities_24/5** | 24 hours a day, 5 days a week: 18:00 ET Sunday to 17:00 ET Friday. These feeds aggregate data across regular, pre-market, post-market, and overnight equity trading sessions. Used by [tokenized equity feeds](/data-feeds/tokenized-equity-feeds) that require continuous equity pricing outside of standard market hours. Feeds are not updated on weekends or US equity market holidays. | | **UK_ETF** | Standard UK equity market hours: 08:00 - 16:30 UK time M-F excluding UK equity market holidays. | | **Forex** | 18:00 ET Sunday to 17:00 ET Friday. <br/> The feeds also follow the global Forex market Christmas and New Year's Day holiday schedule. Many non-G12 currencies primarily trade during local market hours. It is recommended to use those feeds only during local trading hours. We generally observe normal trading within these hours. Prices outside of these hours may be subject to volatility and users are advised to implement additional controls. In addition, local holidays, natural disasters, political unrest or other exogenous shocks are liable to interrupt normal trading in less-liquid currencies. | | **Precious_Metals** | 18:00 ET Sunday to 17:00 ET Friday with a one-hour break Monday through Thursday from 17:00 to 18:00. <br/> The feeds also follow the global Forex market holiday schedule for Christmas and New Year's Day. | @@ -122,12 +136,11 @@ In addition to categories, be aware that markets for several assets are actively ## Risk Mitigation -As a development best practice, design your systems and smart contracts to be resilient and mitigate risk to your protocol and your users. Ensure that your systems can tolerate known and unknown exceptions that might occur. Some examples include but are not limited to volatile market conditions, the degraded performance of infrastructure, chains, or networks, and any other upstream outage related to data providers or node operators. You bear responsibility for any manner in which you use the Chainlink Network, its software, and documentation. +As a development best practice, design your systems and smart contracts to be resilient and mitigate risk to your protocol and your users. Ensure that your systems can tolerate known and unknown exceptions that might occur. Some examples include but are not limited to volatile market conditions, reduced price discovery availability, the degraded performance of infrastructure, chains, or networks, and any other upstream outage related to data providers or node operators. You bear responsibility for any manner in which you use the Chainlink Network, its software, and documentation. -To help you prepare for unforeseen market events, you should take additional steps to protect your application or protocol regardless of the market risk categorization of the Data Feeds your application consumes. The below tooling is put in place to mitigate extreme market events, possible malicious activity on third-party venues or contracts, potential delays, performance degradation, and outages. -Below are some examples of tooling that Chainlink users have put in place: +To help you prepare for unforeseen market events, you should take additional steps to protect your application or protocol regardless of the Market Pricing Risk categorization of the Data Feeds your application consumes. The below tooling is put in place to mitigate extreme market events, possible malicious activity on third-party venues or contracts, potential delays, performance degradation, and outages. Below are some examples of tooling that Chainlink users have put in place: -- **Circuit breakers:** In the case of an extreme price event, the contract would pause operations for a limited period of time. [Chainlink Automation](/chainlink-automation) is able to monitor data feeds to identify unexpected events. If an event were to occur, the Automation network can send an onchain transaction to pause or halt contract functionality. +- **Circuit breakers:** In the case of an extreme price event, the contract would pause operations for a limited period of time. [Chainlink Runtime Environment](/cre) is able to monitor data feeds to identify unexpected events. If an event were to occur, the Automation network can send an onchain transaction to pause or halt contract functionality. - **Contract update delays:** Contracts would not update until the protocol had received a recent fresh input from the data feed. - **Manual kill switch:** If a vulnerability or bug is discovered in one of the upstream contracts, the user can manually cease operation and temporarily sever the connection to the data feed. - **Monitoring:** Some users create their own monitoring alerts based on deviations in the data feeds that they are using. @@ -137,6 +150,10 @@ For more detailed information about some of these examples, see the [Monitoring For important updates regarding the use of Chainlink Price Feeds, users should join the official Chainlink Discord and subscribe to the [data-feeds-user-notifications channel](https://discord.gg/Dqy5N9UbsR). +### Stablecoin-specific considerations + +To protect against extreme stablecoin price events, protocols should assess upside risk and evaluate setting an explicit valuation ceiling for each stablecoin, along with mechanisms that provide proactive peg protection. One example of this approach is the Correlated-assets Price Oracle ([CAPO](https://app.aave.com/governance/v3/proposal/?proposalId=51)), which was implemented by Aave Labs with support from Chainlink Labs and adds upside protection when valuing fiat-pegged stablecoins while preserving full downside responsiveness. Other risk mitigation measures may be appropriate depending on a protocol's intended use case. Teams interested in developing similar risk mitigation measures for stablecoins can [contact the Chainlink Labs team](https://chain.link/contact?ref_id=DataFeed). Developers remain responsible for ensuring that protocol risk parameters are configured appropriately and that the operation and performance of stablecoin data feeds matches expectations. + ## Chainlink Community Deployments Chainlink technology is used by many within the blockchain community to support their use cases. Deployments built and run by community members are not tracked in the Chainlink documentation. Chainlink's community is continuously growing, and they play a vital role in developing the ecosystem, so the software and tooling are developed for anyone to use. Users have a wide variety of options for choosing how to deliver data onchain. They can deploy Chainlink nodes themselves or via the extensive network of node operators that offer services and access one of the community-managed oracle networks that support the supply of various types of data onchain. Chainlink Labs does not take responsibility for the use of Chainlink node software. @@ -165,7 +182,7 @@ If your smart contracts use data feeds, assess those data feeds for the followin ### Liquidity and its Distribution -If your smart contract relies on pricing data for a specific asset, make sure that the asset has a sufficiently healthy level of liquidity in the market to avoid price and market manipulation. Assets with low liquidity or volume can be volatile, which might negatively impact your application and its users. Malicious actors might try to exploit volatility or periods of reduced trading activity to take advantage of the logic in a smart contract and cause it to execute in a way that you did not intend. +If your smart contract relies on pricing data for a specific asset, make sure that the asset has a sufficiently healthy level of liquidity in the market to avoid price and market manipulation. Assets with low liquidity or volume can be volatile or difficult to price, which might negatively impact your application and its users. Malicious actors might try to exploit volatility or periods of reduced trading activity to take advantage of the logic in a smart contract and cause it to execute in a way that you did not intend. Some data feeds obtain their pricing data from individual exchanges rather than from aggregated price tracking services that gather their data from multiple exchanges. These are marked as such in the docs page for that feed. Assess the liquidity and reliability of that specific exchange. @@ -177,7 +194,7 @@ Design and test your contracts to handle price spikes and implement risk managem ### Single Source Data Providers -Some data providers use a single data source, which might be necessary if only one source exists onchain or offchain for a specific type of data. Evaluate data providers to make sure they provide high-quality data that your smart contracts can rely on. Any error or omission in the provider's data might negatively impact your application and its users. +Some data providers use a single data source, which might be necessary if only one source exists onchain or offchain for a specific type of data. Evaluate data providers to make sure they provide high-quality data that your smart contracts can rely on. Any error or omission in the provider's data might negatively impact your application and its users. Single Source Data Provider based feeds can be classified as high or very high market pricing risk and users should take precautions in consuming based on suitability. ### Crypto and Blockchain Actions @@ -259,3 +276,12 @@ When you use Data Feeds for ETFs or Foreign Exchange (Forex) data, be aware of t - Offchain equity and ETF assets are traded only during [standard market hours](/data-feeds/selecting-data-feeds#market-hours). Do not use these feeds outside those windows. - Assets on the Forex (Foreign Exchange) markets are traded only during [defined market hours](/data-feeds/selecting-data-feeds#market-hours). Additionally, some currencies might trade only during local banking hours. Do not use Forex feeds outside market hours for the specific currency. - UK ETF price feed answers are 15 minutes delayed from their original published source. Assets are traded only during [standard market hours](/data-feeds/selecting-data-feeds#market-hours). Do not use these feeds outside their specified hours. + +<Aside type="note" title="Disclaimer"> + Developers remain responsible for ensuring that protocol risk parameters are configured appropriately and that the + operation and performance of a Chainlink Data Feed matches expectations. The performance of a Chainlink Data Feed may + be affected by the availability or performance of a data provider. The composition or availability of a Chainlink Data + Feed may change over time. Please review this webpage in its entirety and review the [Chainlink Terms of + Service](https://chain.link/terms) for important information and disclosures. By using Chainlink Data Feeds, you + acknowledge and agree to these terms. +</Aside> diff --git a/src/content/data-feeds/starknet/index.mdx b/src/content/data-feeds/starknet/index.mdx index 40fcede33ec..df75d3235d6 100644 --- a/src/content/data-feeds/starknet/index.mdx +++ b/src/content/data-feeds/starknet/index.mdx @@ -44,7 +44,7 @@ starkli --version 0.2.8 (f59724e) ``` -Follow the official [installation guide](<(https://book.starkli.rs/installation)>) if necessary. +Follow the official [installation guide](https://book.starkli.rs/installation) if necessary. ### Read data from a Chainlink Price Feed diff --git a/src/content/data-feeds/svr-feeds/index.mdx b/src/content/data-feeds/svr-feeds/index.mdx index 59014405596..12c7b48f7ee 100644 --- a/src/content/data-feeds/svr-feeds/index.mdx +++ b/src/content/data-feeds/svr-feeds/index.mdx @@ -205,7 +205,7 @@ Traditional MEV searching depends on spotting oracle price updates in the public ### Example Application: Aave Liquidations -Aave is a lending protocol where collateralized positions must remain above a [threshold](https://aave.com/docs/concepts/liquidations) called their health factor. When an oracle price update reveals a borrower is undercollateralized, the position becomes eligible for liquidation. The searcher liquidates the position in exchange for a liquidation bonus reward. With Chainlink SVR, a searcher's liquidation transaction can be bundled with the new SVR price update through Flashbots. +Aave is a lending protocol where collateralized positions must remain above a [threshold](https://aave.com/help/borrowing/liquidations) called their health factor. When an oracle price update reveals a borrower is undercollateralized, the position becomes eligible for liquidation. The searcher liquidates the position in exchange for a liquidation bonus reward. With Chainlink SVR, a searcher's liquidation transaction can be bundled with the new SVR price update through Flashbots. For more background on how Aave liquidations work, see [Aave Documentation](https://docs.aave.com/). To understand how Chainlink SVR adds a structured auction for these Aave liquidation opportunities, read the following sections. diff --git a/src/content/data-feeds/tokenized-equity-feeds/index.mdx b/src/content/data-feeds/tokenized-equity-feeds/index.mdx new file mode 100644 index 00000000000..55f68f24a02 --- /dev/null +++ b/src/content/data-feeds/tokenized-equity-feeds/index.mdx @@ -0,0 +1,301 @@ +--- +section: dataFeeds +date: "Last Modified" +title: "Tokenized Equity Feeds" +metadata: + title: "Tokenized Equity Feeds | Chainlink Data Feeds" + description: "Learn about Chainlink Tokenized Equity Feeds for continuous 24/5 pricing of tokenized stocks and ETFs, including how they work and risk considerations for DeFi integrations." + keywords: + [ + "Tokenized Equities", + "Tokenized Stocks", + "ETF Feeds", + "Data Feeds", + "24/5 Pricing", + "RWA", + "Price Feeds", + "Equity Pricing", + ] +whatsnext: + { + "View Provider Catalog": "/data-feeds/tokenized-equity-feeds/providers", + "Find Price Feed Addresses": "/data-feeds/price-feeds/addresses", + "Learn about developer responsibilities": "/data-feeds/developer-responsibilities", + } +--- + +import { ClickToZoom } from "@components" +import TokenizedEquityFeeds from "@features/tokenized-equity-feeds/common/TokenizedEquityFeeds.astro" +import { FeedList } from "@features/feeds" + +<TokenizedEquityFeeds section="tokenizedEquityNote" /> + +## What are tokenized equities? + +Tokenized equities are blockchain tokens that represent ownership or economic exposure to traditional stocks and ETFs. These tokens are distinct financial instruments issued by token issuers, not the underlying equities themselves. Tokenized equity feeds deliver the **primary market price representing the intrinsic value of the equity token** – this is the calculated theoretical token value and may account for long-term total return adjustments such as dividends or corporate actions. + +## About tokenized equity feeds + +Chainlink Tokenized Equity Feeds provide continuous 24/5 pricing for tokenized representations of US equities and ETFs. These feeds deliver the calculated primary market price of the token as determined by the issuer's pricing methodology, enabling DeFi protocols to accurately value tokenized equities across all major trading sessions in US markets, including regular hours, pre-market, post-market, and overnight (Eastern Standard Time). + +Tokenized equity feeds behave differently from standard crypto price feeds due to structural connections with underlying traditional equity markets affecting asset liquidity and pricing. Given the specialized nature of these feeds, all developers must reach out to Chainlink Labs prior to integrating these feeds and also review the [key differences](#key-differences-from-standard-feeds) and [risks](#risks) sections to understand how these characteristics may affect your application. + +See the [Provider Catalog](/data-feeds/tokenized-equity-feeds/providers) to view available feeds and issuer-specific implementations. + +<ClickToZoom + src="/images/data-feed/tokenized-equity/tokenized-equity-diagram.png" + caption="Tokenized equity feeds aggregate equity prices from market data providers and issuer-specific logic from asset issuers through the Chainlink DON to deliver token prices to consumer contracts." +/> + +## Why use tokenized equity feeds? + +Tokenized equities bring traditional stocks and ETFs onchain, but integrating them into DeFi protocols creates a fundamental challenge: US equity markets operate only 6.5 hours per trading day during regular hours, yet DeFi protocols operate continuously. Interest accrues around the clock, liquidation thresholds are monitored constantly, and risk parameters remain active regardless of underlying market hours. + +Chainlink Tokenized Equity Feeds help bridge this gap between TradFi and DeFi markets by: + +- **Providing continuous 24/5 pricing**: A single feed that spans regular, pre-market, post-market, and overnight sessions +- **Simplifying integration**: Consume one feed across trading sessions instead of managing multiple session-specific data sources +- **Applying session-aware smoothing**: Intelligent pricing algorithms that aim to reduce certain price anomalies during session transitions +- **Maintaining benchmark accuracy**: Optimized algorithms that are designed to track consolidated tape benchmarks with high fidelity +- **Performing tokenized price calculations**: Returning real-time calculated primary market valuations of tokenized equities based on the issuer's multiplier values. + +## Available tokenized equity feeds + +The following table shows all available tokenized equity feeds. + +<FeedList client:idle initialNetwork="ethereum-mainnet" dataFeedType="tokenizedEquity" /> + +## How tokenized equity feeds work + +Tokenized equity feeds leverage Chainlink's decentralized oracle infrastructure to aggregate price data from multiple trading sessions and apply session-aware smoothing algorithms. The feeds combine data from various trading venues into a single continuous 24/5 price, handling the complexity of multi-session equity markets. + +### Session coverage + +US equity markets exhibit distinct liquidity regimes throughout the 24-hour cycle: + +| Session | Hours (ET) | Liquidity | Characteristics | +| :-------------- | :-------------------- | :-------- | :-------------------------------------------- | +| Pre-Market | 04:00 – 09:30 | Rising | Increasing activity as regular hours approach | +| Regular Trading | 09:30 – 16:00 | Deep | Full liquidity, primary price discovery | +| Post-Market | 16:00 – 20:00 | Declining | Reduced liquidity, wider spreads | +| Overnight | 20:00 – 04:00 | Thin | Limited venues, potential for price spikes | +| Weekend | Fri 20:00 – Sun 20:00 | Zero | Traditional markets closed | + +### Session-aware smoothing + +To enable reliable, 24/5 continuous pricing, tokenized equity feeds apply intelligent smoothing during session transitions to target pricing integrity under different liquidity conditions. The smoothing methodology: + +1. **Tracks benchmark prices accurately** during liquid regular sessions +1. **Filters microstructure noise** during illiquid session transitions +1. **Reduces the risk of phantom liquidations** from transient price spikes in thin markets +1. **Converges quickly** after legitimate large price movements +1. **Minimizes tracking lag** to reduce mispricing during active trading + +Please note that while intelligent smoothing is designed to mitigate these issues, tokenized equities' structural connections with underlying traditional equity markets, liquidity, and pricing considerations require protocols to ensure performance of Chainlink Tokenized Equity Feeds matches expectations and is appropriate for the intended use case. + +### Input sources + +Tokenized equity feeds combine multiple input sources: + +- **Regular hours data**: Multi-sourced from consolidated tape data with deep liquidity +- **Extended hours data**: Pre-market and post-market venue data +- **Overnight data**: Data from overnight trading venues + +_Extended and overnight session data may be sourced from fewer providers than regular hours data, reflecting the reduced number of venues operating during these periods. See the [Limited Provider Coverage](#limited-provider-coverage-during-extended-and-overnight-sessions) risk section for details._ + +## Key differences from standard feeds + +While tokenized equity feeds use the same Chainlink infrastructure as standard crypto price feeds, they have distinct behaviors you should understand before integrating. + +### Continuous vs. point-in-time pricing + +Standard crypto price feeds reflect a single aggregated market price at a point in time from 24/7 markets. Tokenized equity feeds combine data from multiple trading sessions that have different operating hours, update frequencies, liquidity profiles, and data sources. The feed value represents a calculated return using the best mid-price for continuous 24/5 coverage of underlying equity markets. + +### Smoothing during transitions + +Standard feeds report raw aggregated prices. Tokenized equity feeds apply smoothing algorithms during session transitions in an effort to filter out microstructure noise and mitigate artificial volatility. This means: + +- Brief price spikes in illiquid sessions are dampened +- Convergence to new price levels after gaps is gradual rather than instantaneous +- The reported price may temporarily lag during rapid price movements + +For more information about this risk, see [Smoothing-induced Tracking Lag](#smoothing-induced-tracking-lag) below. + +### Variable data quality by session + +The reliability and accuracy of tokenized equity feeds varies by trading session: + +| Session | Data Quality | Provider Coverage | Update Frequency | +| :-------- | :----------- | :--------------------- | :--------------- | +| Regular | Highest | Multiple providers | Highest | +| Extended | Moderate | Limited providers | Moderate | +| Overnight | Lower | Very limited | Lower | +| Weekend | N/A | No traditional trading | Stale | + +### Provider-specific behaviors + +Tokenized equity feeds for assets from different issuers may differ in terms of their behavior and composition. Review the provider-specific documentation in the [Provider Catalog](/data-feeds/tokenized-equity-feeds/providers) before integrating one of these feeds. + +--- + +## Risks + +Tokenized equity feeds introduce specific risks related to the nature of traditional equity markets, multi-session data aggregation, smoothing algorithms, and data sourcing. Users must understand these factors and implement appropriate safeguards. + +### Limited provider coverage during extended and overnight sessions + +Extended and overnight session price data is sourced from a more limited number of data providers compared to regular hours, making these sessions less reliable than regular hours feeds, which are aggregated from a broader set of providers. + +If providers experience downtime, technical failures, or connectivity disruption, the feed may flatline or report stale values. Such issues may lead to mispricing, failed liquidations, and potential bad debt accumulation. + +#### Mitigation + +- Implement staleness detection by monitoring the feed's last update timestamp +- Define protocol behavior for when data stops updating (pause operations, use bounded trading ranges, or implement fallback logic) +- Consider restricting high-risk operations (large liquidations, new positions) during extended and overnight sessions + +### Structural illiquidity during extended hours + +Pre-market, post-market, and overnight sessions are inherently less liquid than regular trading hours. This results in: + +- **Wider bid-ask spreads**: Higher transaction costs and less reliable mid-prices +- **Stale ticks**: Longer intervals between price updates +- **Price gaps**: Larger price movements on individual trades +- **Higher volatility**: Increased susceptibility to large orders moving prices + +These conditions are inherent to the underlying markets, not the feed itself, but will be visible in the published data. + +#### Mitigation + +- Evaluate whether full 24/5 coverage is appropriate for your use case, or if restricting operations to regular hours is safer +- Configure session-specific risk thresholds, circuit breakers, or mode switching aligned with your risk appetite +- Apply additional safeguards (wider liquidation buffers, reduced leverage) during lower-liquidity sessions +- Validate configurations during integration testing, not post-deployment + +### Price jumps at session transitions + +When transitioning between sessions (Regular ↔ Extended ↔ Overnight), price dislocations can occur due to: + +- Different liquidity conditions between sessions +- Different venues and participants per session +- Accumulated order flow during closed periods +- News events occurring outside regular hours +- Shifts in data provider coverage between sessions (i.e., different cohorts of data providers contributing to the aggregated price) + +These are expected market microstructure effects, not data quality issues. Typical jumps are minor, but larger spikes are possible during low-liquidity environments or impactful news cycles. + +#### Mitigation + +- Implement transition-aware logic that expects and handles price gaps +- Consider pausing or restricting operations during transition windows +- Apply additional smoothing or price change limits during transitions +- Use time-weighted averages (TWAP) or exponential moving averages (EMA) for risk-sensitive calculations + +### Smoothing-induced tracking lag + +The session-aware smoothing that mitigates phantom liquidations also introduces tracking lag: a delay between market price movements and the reported feed price. During rapid legitimate price moves: + +- The smoothed price will temporarily trail the true market price +- Convergence typically occurs within seconds to tens of seconds +- In extreme cases, this may result in delayed liquidations or arbitrage opportunities + +#### Mitigation + +- Understand the trade-off: smoothing protects against false liquidations but delays real ones +- Configure your protocol's risk parameters to account for potential tracking lag +- Consider the tracking lag characteristics when setting liquidation thresholds +- Monitor for persistent deviation between tokenized equity feeds and other market data sources + +### Weekend and holiday behavior + +Traditional equity markets are closed on weekends and holidays. During these periods: + +- The feed will report the last closing price prior to the holiday market close +- No new price discovery occurs in the underlying markets +- The staleness indicator will show increasingly old timestamps + +This reflects true underlying market inactivity rather than an outage or failure. + +#### Mitigation + +- Treat weekends and holidays as expected states requiring specific protocol behavior +- Options include: pausing operations, allowing restricted trading within bounded ranges, or referencing tokenized asset prices on secondary markets +- Incorporate authoritative exchange holiday calendars (NYSE/NASDAQ for US equities) into your integration +- Define deterministic behaviors for these periods before deployment + +### Corporate actions + +Traditional equities are subject to corporate actions that can dramatically change asset prices: + +- **Stock splits and reverse splits**: Can cause overnight price changes of 2x, 10x, or more +- **Dividends**: Ex-dividend date adjustments affect pricing +- **Mergers and acquisitions**: May cause trading halts or significant price changes +- **Spin-offs**: New securities with separate pricing + +These actions are usually announced outside regular trading hours. The feed will reflect these price changes when markets reopen, which may appear as sudden large moves. + +#### Mitigation + +- Actively monitor corporate action announcements for assets in your protocol +- Adjust pricing logic, risk parameters, and position limits around corporate action dates +- Consider pausing markets during corporate action windows +- Implement maximum price change limits with manual review for extreme moves + +### Market closures and halts not explicitly flagged + +Tokenized equity feeds do not explicitly flag: + +- Exchange public holidays +- Trading halts (regulatory, news-pending, circuit breakers) +- Other operational closures + +During these periods, the feed may appear stale or flatline. This reflects true market inactivity, not a data quality issue. + +#### Mitigation + +- Implement staleness checks comparing the feed's last update timestamp to current time +- Define protocol behavior for stale data scenarios +- Monitor exchange halt notifications independently +- Do not rely solely on feed freshness to determine market status. Users should incorporate external market status sources where available. + +--- + +## Best practices + +### Protocol design + +- **Set deviation limits**: Cap maximum acceptable price changes per update or per time window +- **Define fallback behavior**: Determine what happens if the feed stops updating or deviates beyond thresholds +- **Implement session awareness**: Consider different risk parameters for different trading sessions +- **Test extensively**: Validate protocol behavior during session transitions, weekends, and simulated failure scenarios before production deployment + +### Monitoring + +- **Track staleness**: Alert when no new updates arrive within expected frequency +- **Monitor deviation**: Compare tokenized equity feed values against other market data sources when available +- **Log session transitions**: Track behavior during session changes to identify patterns +- **Set up alerts**: Notify operators of unusual price movements, extended staleness, or deviation from expected ranges + +### Integration testing + +Before deploying to production: + +1. Test behavior during each trading session (regular, extended, overnight) +1. Validate handling of session transitions +1. Simulate weekend and holiday behavior +1. Test failure scenarios (stale data, extreme price moves, data gaps) +1. Verify your staleness detection and fallback logic works correctly + +When using tokenized equity feeds, you inherit all responsibilities associated with standard price feeds plus additional responsibilities for understanding session-specific risks, equity market dynamics, and multi-source data quality. Review the [Developer Responsibilities](/data-feeds/developer-responsibilities) page for comprehensive guidance. + +--- + +## FAQ + +### How is market data sourced for tokenized equity feed calculation? + +Tokenized equity feeds use the [Data Streams v11 report schema](/data-streams/reference/report-schema-v11) for sourcing the underlying equity market price. + +### How are total return values (stock splits, multipliers, market pauses) determined? + +These values are sourced from the asset issuer. Learn more in the [Provider Catalog](/data-feeds/tokenized-equity-feeds/providers). diff --git a/src/content/data-feeds/tokenized-equity-feeds/ondo.mdx b/src/content/data-feeds/tokenized-equity-feeds/ondo.mdx new file mode 100644 index 00000000000..19fc2e7b62c --- /dev/null +++ b/src/content/data-feeds/tokenized-equity-feeds/ondo.mdx @@ -0,0 +1,146 @@ +--- +section: dataFeeds +date: "Last Modified" +title: "Ondo Finance Global Markets (GM)" +metadata: + title: "Ondo Finance Tokenized Equity Feeds | Chainlink Data Feeds" + description: "Learn about Chainlink tokenized equity feeds for Ondo Finance, including Total Return Value calculation, multiplier handling, and corporate action management." + keywords: + [ + "Ondo Finance", + "Tokenized Equities", + "Total Return Value", + "sValue", + "Multiplier", + "Corporate Actions", + "SyntheticSharesOracle", + ] +whatsnext: + { + "View Provider Catalog": "/data-feeds/tokenized-equity-feeds/providers", + "Learn about tokenized equity feeds": "/data-feeds/tokenized-equity-feeds", + "Find Price Feed Addresses": "/data-feeds/price-feeds/addresses", + } +--- + +import { Aside, ClickToZoom } from "@components" +import TokenizedEquityFeeds from "@features/tokenized-equity-feeds/common/TokenizedEquityFeeds.astro" +import { FeedList } from "@features/feeds" + +<TokenizedEquityFeeds section="tokenizedEquityNote" /> + +Chainlink provides tokenized equity feeds for Ondo Finance Global Markets (GM) tokenized equities. These feeds differ from standard market-rate feeds in that they report **Total Return Values** rather than raw equity prices. + +## Available Ondo tokenized equity feeds + +The following table shows the available Ondo tokenized equity feeds. + +<FeedList client:idle initialNetwork="ethereum-mainnet" dataFeedType="tokenizedEquity" tokenizedEquityProvider="ondo" /> + +## Total Return Value calculation + +Ondo tokenized equity feeds calculate the token price using the following formula: + +``` +Token Price = Underlying Equity Market Price × Multiplier (sValue) +``` + +Where: + +- **Underlying Equity Market Price**: Sourced from Chainlink's 24/5 equity price feeds, which aggregate data across regular, pre-market, post-market, and overnight trading sessions +- **Multiplier (`sValue`)**: Sourced from Ondo's `SyntheticSharesOracle` contract, which tracks dividend reinvestments and corporate action adjustments (see [Corporate action handling](#corporate-action-handling) below). + +This approach ensures that the token price reflects the total return of the underlying equity, including dividend reinvestments and corporate action adjustments, rather than just the current market price per share. + +## How the multiplier works + +The multiplier (`sValue`) accounts for events that change the relationship between token quantity and underlying equity value: + +| Event Type | Multiplier Behavior | Example | +| :--------------------------- | :------------------------------------ | :---------------------- | +| Dividend reinvestment | Small increase (less than 1% per day) | `sValue`: 1.000 → 1.008 | +| Stock split (10:1 example) | Large increase | `sValue`: 1.0 → 10.0 | +| Reverse split (1:10 example) | Large decrease | `sValue`: 10.0 → 1.0 | +| Spin-offs | Adjustment to reflect new value | Varies by event | + +The `SyntheticSharesOracle` contract enforces two update paths: + +- **Small updates** (≤1% per 24-hour period): Applied immediately via automated processes. These handle routine dividend reinvestments. +- **Large updates** (>1%): Requires a scheduled pause window and manual confirmation. These handle major corporate actions like stock splits. + +## Corporate action handling + +Large corporate actions require special handling to maintain price continuity. The system operates in two modes: + +**Normal mode**: The feed returns the current stock price multiplied by the current `sValue`. + +**Corporate action mode**: When a large corporate action is scheduled, the system enters a pause state where: + +1. The pause is scheduled at least 24 hours in advance +1. At the scheduled pause time, the price freezes at the last known good value +1. The new `sValue` is staged but not yet applied +1. After the corporate action takes effect and Ondo confirms that both the stock price and `sValue` reflect the new values correctly, the system is manually unpaused +1. The new `sValue` takes effect, and normal operation resumes + +<ClickToZoom + src="/images/data-feed/tokenized-equity/ondo-tokenized-equity-pause-behavior.png" + caption="State transitions between Normal Mode and Corporate Action Mode based on SyntheticSharesOracle responses. When paused is true, the feed freezes at the last known good price until the new sValue is confirmed and the system is unpaused." +/> + +This pause mechanism ensures price continuity during corporate actions. For example, during a 10:1 stock split: + +| Stage | Stock Price | `sValue` | Token Price | +| :------------ | :---------- | :------------ | :------------ | +| Before split | $200 | 1.0 | $200 | +| During pause | Frozen | Pending: 10.0 | $200 (frozen) | +| After unpause | $20 | 10.0 | $200 | + +The token price remains continuous at $200 throughout the event, even though the underlying equity market price dropped from $200 to $20. + +<Aside type="note"> + When the `SyntheticSharesOracle` contract returns `paused = true`, the Chainlink feed freezes at the last known good + price. Integrators should be aware that during pause windows: + +- The feed will not update until manually unpaused +- The pause duration depends on when Ondo confirms the corporate action has been correctly applied +- A minimum pause duration (at least 10 minutes) is enforced to prevent premature unpausing + +</Aside> + +## Example scenarios + +**Normal operation** + +``` +- Stock price: $200 → $201 +- sValue: 1.000 (unchanged) +- Token price: $201 +``` + +**Dividend reinvestment** (small `sValue` drift) + +``` +- Stock price: $200 +- sValue: 1.000 → 1.008 (0.8% increase, within allowed drift) +- Token price: $201.60 +``` + +**Stock split** (10:1, scheduled corporate action) + +``` +1. Ondo schedules pause for Tuesday 8pm with `newSValue = 10` +2. At 8pm, feed freezes at current token price +3. Market opens Wednesday with stock price at $20 (post-split) +4. Ondo confirms alignment and unpauses +5. sValue becomes 10.0, token price = $20 × 10 = $200 (continuous) +``` + +**Split with timing mismatch** (stock price updates before `sValue`) + +``` +- Scheduled pause at Tuesday 8pm with `newSValue = 10` +- At 8:01pm: stock price = $20, sValue = 1.0 (not yet updated) +- Result: Feed remains frozen at the pre-pause price until Ondo confirms the sValue update and unpauses +``` + +This fail-safe behavior prevents incorrect token prices from being published when the stock price and `sValue` are temporarily out of sync. diff --git a/src/content/data-feeds/tokenized-equity-feeds/providers.mdx b/src/content/data-feeds/tokenized-equity-feeds/providers.mdx new file mode 100644 index 00000000000..6fae4a1ac6b --- /dev/null +++ b/src/content/data-feeds/tokenized-equity-feeds/providers.mdx @@ -0,0 +1,31 @@ +--- +section: dataFeeds +date: "Last Modified" +title: "Asset Issuer Catalog" +metadata: + title: "Tokenized Equity Feed Providers | Chainlink Data Feeds" + description: "View the catalog of tokenized equity feed providers supported by Chainlink, including provider-specific implementations and corporate action handling." + keywords: ["Tokenized Equities", "Provider Catalog", "Ondo Finance", "Data Feeds", "Total Return Value"] +whatsnext: + { + "Learn about Ondo Finance feeds": "/data-feeds/tokenized-equity-feeds/ondo", + "Find Price Feed Addresses": "/data-feeds/price-feeds/addresses", + "Learn about developer responsibilities": "/data-feeds/developer-responsibilities", + } +--- + +import TokenizedEquityFeeds from "@features/tokenized-equity-feeds/common/TokenizedEquityFeeds.astro" + +<TokenizedEquityFeeds section="tokenizedEquityNote" /> + +Tokenized equity feeds have issuer-specific implementations that affect pricing methodology, data handling, and operational behavior. This page catalogs the available issuers and their key characteristics. + +## Available providers + +| Provider | Feed Type | Price Calculation | Corporate Action Handling | Documentation | Issuer Contact | +| :----------- | :----------------- | :----------------------------------------------------- | :----------------------------------- | :------------------------------------------------------ | :------------------------------------ | +| Ondo Finance | Total Return Value | Underlying Equity Market Price × Multiplier (`sValue`) | Pause-based with manual confirmation | [View details](/data-feeds/tokenized-equity-feeds/ondo) | [Contact page](https://ondo.finance/) | + +## Provider-specific considerations + +Each provider may implement tokenized equity feeds differently based on their token design and corporate action handling requirements. Review the provider-specific documentation and contact Chainlink Labs at [chainlink_data_feeds@smartcontract.com](mailto:chainlink_data_feeds@smartcontract.com) before integrating their tokenized equity feeds into your protocol. diff --git a/src/content/data-streams/billing.mdx b/src/content/data-streams/billing.mdx index 5ac1b14b781..4344e7d6a35 100644 --- a/src/content/data-streams/billing.mdx +++ b/src/content/data-streams/billing.mdx @@ -22,12 +22,11 @@ import { Aside, ClickToZoom } from "@components" integrating Chainlink Data Streams with your applications. </Aside> -Chainlink Data Streams offers two billing models: - -1. **Subscription model**: A subscription-based billing option. - -1. **Pay-per-report model**: You pay to verify reports from Data Streams onchain using the verifier contract. You pay per report verified. If you verify multiple reports in a batch, you pay for all of the reports included in that batch. - - The verification price is 0.35 USD per report. Chainlink Data Streams supports fee payments in LINK and in alternative assets, which currently includes native blockchain gas tokens and their ERC20-wrapped version. Payments made in alternative assets have a 10% surcharge when compared to LINK payments. +Chainlink Data Streams uses a subscription-based billing option. [Contact us](https://chainlinkcommunity.typeform.com/datastreams?#ref_id=docs) to learn more about Mainnet pricing and subscription options. + +<Aside type="caution" title="[Deprecated] Pay-per-verification model"> + The pay-per-verification billing model has been deprecated. <br /> To learn more about the subscription model, please{" "} + <a href="https://chainlinkcommunity.typeform.com/datastreams?#ref_id=docs">contact us</a>. +</Aside> diff --git a/src/content/data-streams/concepts/best-practices.mdx b/src/content/data-streams/concepts/best-practices.mdx index 67bdbb86243..abf7033cada 100644 --- a/src/content/data-streams/concepts/best-practices.mdx +++ b/src/content/data-streams/concepts/best-practices.mdx @@ -25,6 +25,8 @@ whatsnext: "Find the schema of data to expect from Data Streams reports: Crypto": "/data-streams/reference/report-schema-v3", "Find the schema of data to expect from Data Streams reports: RWA": "/data-streams/reference/report-schema-v8", "Learn about Data Streams market hours and schedules": "/data-streams/market-hours", + "Learn how to handle market events": "/data-streams/rwa-streams/handling-market-events", + "Learn how to handle stock splits": "/data-streams/tokenized-asset-streams/handling-stock-splits", } --- @@ -41,252 +43,11 @@ This page provides best practices and recommendations for using Chainlink Data S ## Real-World Assets (RWA) -Apply these RWA best practices when integrating or operating markets that use tokenized real-world assets. Developers and operators are responsible for assessing market integrity, implementing mitigations, and managing application-level risks — see the [Developer Responsibilities](/data-streams/developer-responsibilities) guidance for details. +For best practices regarding RWA streams: -### Market Hours +- **24/5 US Equities**: See the [24/5 US Equities User Guide](/data-streams/rwa-streams/24-5-us-equities-user-guide) for continuous price feed construction, edge cases, and risk management. +- **Market Events**: See the [Handling Market Events](/data-streams/rwa-streams/handling-market-events) guide for market hours, volatility, and corporate actions. -Markets for Real-World Assets (RWA) operate during specific hours and are subject to various market conditions that can create risks for applications. The following sections outline common market issues and how to mitigate them. +## Tokenized Assets -<Aside type="note" title="Market Hours Overview"> - For detailed market hours and trading schedules, see the <a href="/data-streams/market-hours">Market Hours</a> page. -</Aside> - -#### Market gaps - -Market gaps occur when there are interruptions in trading or price discovery, leading to periods where the last available price may not reflect current market conditions. These gaps can create risks, particularly around market opens, closures, and unexpected disruptions. - -#### Market close - -Large price jumps between trading sessions due to after-hours news. - -A large price jump at market open could cause sudden liquidations, potentially leaving the perpetual DEX with bad debt if a trader's collateral is insufficient to cover the losses. - -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until market open.</li><li>`marketStatus`: 1 = Market Closed.</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Keep markets closed while `marketStatus = 1` to prevent users trading at unfair prices.<br/><br/> Leverage available should be set in line with the asset average volatility to avoid bad debt if a trader's collateral is insufficient to cover the losses. | - -#### Price formation at open/close - -Certain assets (e.g., FX open on Sunday afternoon) experience gradual price discovery due to fragmented liquidity and delayed trading activity. - -The perpetual DEX should avoid opening their market with the last close price. - -| Data Stream behavior | User guidance | -| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until a bid/ask becomes available or a transaction occurs.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Wait until `lastUpdateTimestamp` is current before opening the market so traders don't execute on stale quotes. | - -#### Sudden failures - -Unexpected system outages, order execution failures, or data feed disruptions can occur. - -The price will be flat during that period, meaning if a perp DEX lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. - -| Data Stream behavior | User guidance | -| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus = 2` but `lastUpdateTimestamp` is stale. | - -#### Trading halts - -Stocks can be halted due to extreme volatility (e.g., limit up/down rules) or regulatory actions. - -The price will be flat during that period, meaning if a perp DEX lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. - -| Data Stream behavior | User guidance | -| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus = 2` but `lastUpdateTimestamp` is stale. | - ---- - -### Volatility & low liquidity - -During periods of high volatility or low liquidity, price movements can become unpredictable and exaggerated. These conditions can increase the risk of sudden liquidations and bad debt accumulation, requiring careful risk management strategies. - -#### Algorithmic & HFT activity - -Rapid-fire trading by algos can create unpredictable price movements. - -High volatility can lead to liquidation and potential bad debt accumulation. - -| Data Stream behavior | User guidance | -| :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | - -#### Low liquidity at open/close - -Reduced market depth at trading session transitions can lead to higher volatility and spreads. - -High volatility can lead to liquidation and potential bad debt accumulation. - -| Data Stream behavior | User guidance | -| :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | - ---- - -### Corporate actions - -Corporate actions are events initiated by publicly traded companies that can significantly impact stock prices and trading behavior. These actions are usually announced outside regular trading hours and can cause substantial price movements when markets reopen. Users should monitor these events closely as they can lead to sudden price adjustments that may trigger unexpected liquidations or require position modifications. - -#### Bankruptcy & delisting - -Bankruptcy can lead to delisting or complete loss of equity value. - -Delisting will zero out prices for the asset. - -| Data Stream behavior | User guidance | -| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until a new price is available.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Closing timestamp of the last session.</li></ul> | Monitor delisting news during `marketStatus` = `1` and close markets permanently once confirmed. | - -#### Spin-offs - -When a company spins off a business unit into a separate publicly traded entity, the parent company's stock may adjust accordingly, while the spun-off company's shares begin trading independently. - -Positions may need to be manually adjusted if the DEX doesn't support tracking the new entity. - -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until the first post-spin trade.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements while `marketStatus = 1`.<br/><br/>Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br/><br/>If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | - -#### Stock splits & reverse splits - -<Aside type="note" title="Tokenized Stocks Guidance"> - Tokenized stocks such as [Backed xStock](/data-streams/reference/report-schema-v10) handle stock splits differently - using activation dates and staged multipliers to maintain price continuity. [Learn more about advanced stock split - handling](#handling-stock-splits-for-tokenized-assets). -</Aside> - -A stock split increases the number of shares while reducing the price per share (e.g., 2-for-1 split), often making shares more accessible to investors. A reverse split does the opposite, consolidating shares to increase the price per share. - -A 2-for-1 split would reduce the price by 50% from the previous trading session, any leveraged user could get liquidated. - -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until the split-adjusted price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements while `marketStatus = 1`.<br/><br/>Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br/><br/>If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | - -#### Mergers & acquisitions (M&A) - -If a company is being acquired, its stock price may rise to reflect the acquisition premium. The acquiring company's stock might fluctuate based on investor sentiment regarding the deal's financial and strategic impact. - -Announcements can cause sharp price spikes or sustained moves. - -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | - -#### Share buybacks & stock issuance - -Reduced share supply from a buyback can drive stock prices higher, while an increase in share supply can lead to price dilution. - -Announcements can cause sharp price spikes or sustained moves. - -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | - -#### Dividends - -A company's stock price typically adjusts to reflect dividend payments. For example, when a company declares a 10% dividend, its stock price often drops by a similar amount on the ex-dividend date, as new buyers are no longer entitled to that dividend. - -Announcements can cause sharp price spikes or sustained moves. - -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until the ex-date trade prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | - ---- - -### Handling stock splits for tokenized assets - -Corporate actions, such as stock splits and reverse splits, require precise handling for tokenized assets to ensure price continuity and avoid disruptions. These events alter per‑share pricing while leaving the underlying economic exposure unchanged. They can produce abrupt per‑share price moves and must be handled carefully to avoid incorrect onchain price computations and unexpected liquidations. - -In the [v10 report schema](/data-streams/reference/report-schema-v10), continuity is preserved by staging a multiplier change with a scheduled `activationDateTime` so the Theoretical Price (`price` \* `currentMultiplier`) remains continuous. Split ratios are typically known in advance, but activation may occur while markets are closed, so some external price sources may not reflect the split until trading resumes. - -<Aside type="note" title="Note"> - This guidance is designed for multiplier handling in the [v10 report - schema](/data-streams/reference/report-schema-v10) and what integrators should expect around activation windows and - protocol behavior. Similar principles may apply to future schemas that host tokenized stocks, but applicability and - exact behavior will depend on each schema's design and are not guaranteed. -</Aside> - -#### Guiding principle - -Follow these principles when handling multiplier changes during corporate actions: - -1. The protocol considers the Theoretical Price as `price` \* `currentMultiplier`. -1. Ahead of the event, `newMultiplier` and `activationDateTime` are staged. -1. At `activationDateTime` (Unix), `currentMultiplier` becomes `newMultiplier`. - - The underlying `price` from traditional markets should start reflecting the split the next time trading opens, so at the next `price` update, the Theoretical Price should remain continuous. - -#### Example (10:1 split, AAPL) - -The following hypothetical scenario demonstrates how a 10:1 AAPL stock split is handled through the staged multiplier system, showing the progression from announcement through protocol reopening with proper price continuity maintained throughout. - -The following timeline outlines the key events and actions taken at each stage: - -- **T-2**: [Split announcement and multiplier staging](#announcement-t-2) -- **T-1**: [Protocol preparation and monitoring setup](#protocol-engagement-t-1) -- **T0**: [Multiplier activation (split effective date)](#activation-t0) -- **T+1**: [Market reopening with adjusted prices](#market-reopening-t1) -- **T+2**: [Protocol resumption after verification](#protocol-reopening-t2) - -##### Announcement (T-2) - -A 10:1 AAPL stock split is announced. [The report](/data-streams/reference/report-schema-v10) updates to stage the split: - -- `newMultiplier` is set to 10x the value of `currentMultiplier`. -- `activationDateTime` is set to the Unix timestamp of the split. -- `currentMultiplier` is unaffected until activation. - -##### Protocol engagement (T-1) - -At this stage, users are advised to monitor for changes in `activationDateTime` and inspect the upcoming change to prepare appropriate action, such as preparing the protocol for a pause around the `activationDateTime` in order to ensure appropriate handling of the stock split. - -##### Activation (T0) - -When the provider applies the split, [the report](/data-streams/reference/report-schema-v10) updates: - -- `newMultiplier` remains the current value. -- `activationDateTime` is set to `0`. -- `currentMultiplier` is updated to the same value as `newMultiplier`. - -<Aside type="danger" title="Important"> - If activation occurs while the underlying market is closed, prices may still show the pre‑event last trade. Do not - compute the Theoretical Price during this pre-adjustment window. Monitor `marketStatus` and keep the protocol paused - until the first post‑event trade prints and the Theoretical Price is continuous. -</Aside> - -If activation occurs while the underlying market is closed, prices may still show the pre‑event last trade. Do not compute the Theoretical Price during this pre-adjustment window. Monitor `marketStatus` and keep the protocol paused until the first post‑event trade prints and the Theoretical Price is continuous. - -##### Market reopening (T1) - -The stock split has taken effect. Generally, this occurs after the market closes or over the weekend, meaning `price` may not yet reflect the new economic value per share. Upon the market reopening, `price` should start reflecting the split-adjusted value. - -##### Protocol reopening (T2) - -Users should pause markets before `activationDateTime` and keep them paused until: - -- The market has reopened (monitor `marketStatus`) -- `price` has updated in line with the split ratio (e.g., 10:1) -- You have confirmed that the Theoretical Price matches expectations - -After all the above checks have been confirmed, users can unpause their protocol and continue and resume normal operation. - -#### Activation-time convention - -Each tokenized asset issuer sets its own activation time. For example, the xStocks default `activationDateTime` is 00:00 UTC on the effective date. Once `activationDateTime` is reached, `currentMultiplier` becomes `newMultiplier`. - -Because underlying venues may be closed at activation, some external price sources may not reflect the split immediately. If `activationDateTime` occurs while the underlying market is closed, the report’s `currentMultiplier` will become `newMultiplier`; however, `price` can remain at the pre-event level until the market reopens. During this post-activation, pre-adjustment interval (after the multiplier has changed but before the underlying `price` updates), the Theoretical Price can be incorrect. Use `marketStatus` to pause until `price` reflects the event. - -#### Integrator risk & handling - -Computing `price` \* `currentMultiplier` when the price has not adjusted (e.g., market closed) can produce large errors. It is critical to ensure that the Theoretical Price is again reflective of actual market conditions before allowing live trading. - -Treat any multiplier change (splits, dividends, etc) and `activationDateTime` as a maintenance window; pause/guard the protocol, then verify post-activation conditions before resuming. - -<Aside type="caution" title="Integrator Responsibility"> - It is the integrator's responsibility to perform proper handling and risk management. Failure to follow these best - practices may result in significant financial losses. Ensure that all multiplier changes, activation windows, and - post-activation conditions are verified before resuming operations. -</Aside> - -For broader guidance around market hours and event handling, refer to the [Market Hours](#market-hours) guidance. +For best practices regarding stock splits and reverse splits for tokenized assets, please see the [Handling Stock Splits](/data-streams/tokenized-asset-streams/handling-stock-splits) guide. diff --git a/src/content/data-streams/concepts/calculated-streams.mdx b/src/content/data-streams/concepts/calculated-streams.mdx new file mode 100644 index 00000000000..0e079382d4c --- /dev/null +++ b/src/content/data-streams/concepts/calculated-streams.mdx @@ -0,0 +1,186 @@ +--- +section: dataStreams +date: "Last Modified" +title: "Calculated Streams" +metadata: + title: "Chainlink Calculated Streams | Derived Data Stream Values" + description: "Learn about Calculated Streams in Chainlink Data Streams - streams whose values are derived from multiple underlying inputs using predefined expressions." + keywords: + [ + "Calculated Streams", + "Data Streams", + "Derived Values", + "Index Pricing", + "Collateral Values", + "Tokenized Assets", + "Stream Calculations", + ] +whatsnext: + { + "Find the list of available Exchange Rate streams": "/data-streams/exchange-rate-streams", + "Learn about Data Streams architecture": "/data-streams/architecture", + "Data Streams Best Practices": "/data-streams/concepts/best-practices", + } +--- + +import { Aside, ClickToZoom } from "@components" + +Calculated streams are Chainlink data streams whose values are derived by applying arithmetic expressions to multiple underlying inputs. + +All Data Streams use a [Decentralized Oracle Network (DON)](/data-streams/architecture) where nodes reach consensus and publish signed reports. Traditional Data Streams aggregate market data from multiple independent providers, ensuring no single data source can compromise the stream's integrity. + +Instead of aggregating only raw market data, calculated streams compute derived values using predefined formulas applied to various inputs, including existing data streams, onchain state, and offchain APIs. Some inputs are decentralized aggregates (for example, crypto price streams from multiple independent providers), while others may come from a single protocol or API (for example, a specific vault contract or yield provider). Because a calculated stream depends on all of these inputs, you should evaluate their dependencies and failure modes carefully before using it in a value-securing application. + +<Aside type="caution" title="Important Considerations"> + Calculated streams behave differently from standard streams in important ways. Before integrating a calculated stream, + review the <a href="#key-differences-from-standard-streams">key differences</a> and{" "} + <a href="#risks-and-mitigation">risks and mitigation</a> sections to understand how these differences may affect your + application. +</Aside> + +## Why use calculated streams? + +- **Simpler integrations**: Consume one stream instead of implementing calculation logic in your contracts or backend +- **Canonical formulas**: All integrators use the same formula and inputs, ensuring consistency across protocols +- **Managed infrastructure**: Chainlink handles RPC calls, API integrations, and the calculation pipeline + +## How to identify calculated streams + +Calculated streams are marked with a <span style="display: inline-block; font-size: 0.75rem; padding: 2px 6px; margin-left: 4px; border-radius: 4px; background: var(--blue-100); color: var(--blue-700); font-weight: 500; vertical-align: middle;">Calculated</span> badge in the Data Streams feed list. + +## How calculated streams work + +Calculated streams leverage existing Data Streams infrastructure. Data providers feed market data into the DON, which produces base streams. The DON then uses these base streams—along with onchain state and offchain APIs—as inputs to calculate derived values. + +<ClickToZoom + src="/images/data-streams/calculated-streams-diagram.png" + alt="Calculated Streams architecture diagram showing data providers feeding into LLO DON nodes, which perform index price calculations and output to channels containing multiple streams." +/> + +### Architecture flow + +1. **Data collection**: The DON retrieves inputs specific to each calculated stream, which may include: + - Existing Data Streams (market prices from multiple independent data providers) + - Onchain state via RPC calls (vault balances, token supplies, contract data) + - Offchain data via APIs (yield rates, interest components, external reference data) +2. **Calculation**: The DON applies the predefined formula to combine the inputs +3. **Consensus and signing**: Nodes reach consensus on the calculated value and sign the report +4. **Publication**: Calculated streams are published through the Data Streams Aggregation Network + +### Input sources + +The inputs for a calculated stream depend on what it's computing. A stream might use: + +#### Existing Data Streams + +Market prices already aggregated from multiple independent sources (3+ providers). Example: using individual crypto asset prices as inputs for an index calculation. + +#### Onchain state + +Protocol-specific data read via RPC, such as vault balances, token supplies, or smart contract state. May come from a single protocol's contracts. + +#### Offchain APIs + +External data from specific trusted providers, such as yield rates or reference values. May come from a single API endpoint. + +### Calculation and output + +The DON executes the predefined formula (weighted averages, ratios, sums, etc.) using the latest available inputs. The calculated value is packaged into a signed report with standard metadata (timestamps, fees) and published through the Data Streams Aggregation Network. You consume these reports using the same REST APIs, WebSocket connections, and onchain verification as traditional streams. + +## Example: Tokenized yield product + +A calculated stream for a tokenized yield-bearing vault might combine: + +- **Vault balance (onchain)**: Total assets in the vault contract +- **Token supply (onchain)**: Circulating supply of vault shares +- **Accrued yield (offchain)**: Interest from an external API + +**Formula:** `(vault balance + accrued yield) / token supply` + +**Result**: a price per share that reflects the vault's total value including pending yield. + +Without this stream, protocols accepting the vault token as collateral would need to query the vault contract, fetch accrued interest from the yield provider's API, perform the calculation themselves, and keep this logic synchronized across all integrators. A calculated stream helps ensure integrators apply the same pricing logic and update together when the underlying formula or yield source changes. + +## Key differences from standard streams + +While calculated streams use the same infrastructure and delivery mechanisms as standard streams, they have distinct behaviors you should understand before integrating. For mitigation strategies, see [Risks and mitigation](#risks-and-mitigation). + +### Report availability + +Standard streams aggregate data from multiple independent providers, so they remain available as long as enough providers are reporting. Calculated streams depend on **all** of their inputs being available. If any required input becomes unavailable or returns errors, the calculated **stream stops producing reports until all inputs recover**. This prevents potentially incorrect values from being published. + +### Input reliability + +Standard streams source data exclusively from decentralized aggregates of multiple independent data providers. Calculated streams may include a mix of: + +- **Decentralized aggregates**: Existing Data Streams with multiple independent sources (similar reliability to standard streams) +- **Single-source inputs**: Specific protocol contracts or APIs where availability depends on a single system + +Single-source inputs carry higher risk. If that source experiences downtime, report production halts entirely until it recovers. Review the input sources for any calculated stream you plan to use. + +### Timing characteristics + +Standard streams reflect a single aggregated market price at a point in time. Calculated streams combine multiple inputs that may update at different frequencies and reflect slightly different timestamps. The calculated value is an approximation based on the latest available data from each input, not a single-block atomic snapshot. + +During rapid changes (large deposits, withdrawals, or sharp market moves), you may observe temporary differences between the calculated stream value and values from other sources like block explorers or protocol dashboards. These differences typically resolve as all inputs update to reflect the new state. + +--- + +## Risks and mitigation + +Calculated streams inherit risks from their underlying inputs and introduce additional considerations. Use these strategies to mitigate potential issues. + +### Handling report gaps + +Because calculated streams stop producing reports when any input fails, your application must handle gaps in report availability. + +#### Mitigation + +- Design your protocol to handle report gaps gracefully (pause operations, use last-known values with appropriate staleness checks, or implement fallbacks based on your risk tolerance) +- Implement staleness checks to detect when reports stop arriving and trigger appropriate protocol responses +- Set alerts for report gaps to detect input source issues early + +### Single-source input reliability + +Single-source inputs (specific APIs or contracts) may have lower availability than decentralized aggregates. + +#### Mitigation + +- Understand your input sources and assess the reliability of each, particularly single-source APIs or contracts +- For critical applications, consider independently monitoring the availability of single-source inputs +- Define acceptable downtime thresholds and corresponding protocol responses + +### Timing discrepancies + +Temporary differences between the calculated stream and other data sources are expected during rapid changes. + +#### Mitigation + +- Implement max deviation checks against expected ranges +- Use time-weighted averages or circuit breakers for extreme moves +- Monitor trends over time rather than reacting to individual updates +- Compare calculated values against market references when available (e.g., spot prices for index tokens) + +<Aside type="note" title="Developer Responsibilities"> + When using calculated streams, you inherit all responsibilities associated with the underlying inputs plus additional + responsibilities for monitoring calculation health and managing time-sensitivity requirements. Review the{" "} + <a href="/data-streams/developer-responsibilities">Developer Responsibilities</a> page for comprehensive guidance on + risk assessment and mitigation techniques. +</Aside> + +--- + +## Best practices + +### Protocol design + +- Set deviation limits to cap price changes per update or time window +- Define fallback behavior if the stream stops updating or jumps beyond thresholds +- Test your protocol's behavior during report gaps before deploying to production + +### Monitoring + +- Set alerts for report gaps to detect when no new reports arrive within your expected update frequency +- Track the calculated stream value over time to establish normal behavior patterns +- Monitor key inputs independently when feasible (vault balances, token supplies, API availability) to identify which input may be causing issues +- Alert on movements outside your expected range diff --git a/src/content/data-streams/deprecating-streams.mdx b/src/content/data-streams/deprecating-streams.mdx new file mode 100644 index 00000000000..19fcacda6cb --- /dev/null +++ b/src/content/data-streams/deprecating-streams.mdx @@ -0,0 +1,11 @@ +--- +title: "Deprecation of Chainlink Data Streams" +section: dataStreams +metadata: + description: "Deprecation of Chainlink Data Streams" +date: Last Modified +--- + +import StreamsPage from "@features/streams/components/StreamsPage.astro" + +<StreamsPage ecosystem="deprecating" /> diff --git a/src/content/data-streams/llms-full.txt b/src/content/data-streams/llms-full.txt index cb108052299..908d945b834 100644 --- a/src/content/data-streams/llms-full.txt +++ b/src/content/data-streams/llms-full.txt @@ -111,17 +111,6 @@ Automatic failover handles availability and traffic routing in the following sce --- -# Tokenized Asset Data Streams -Source: https://docs.chain.link/data-streams/backed-streams - -<Aside type="danger" title="Weekend Usage Disclaimer"> - **Users should not use these streams during weekends** due to limited exchange activity. - - If usage is necessary, increase fees to mitigate risks. Developers are solely responsible for monitoring and mitigating market integrity risks, as outlined in the [Developer Responsibilities](/data-streams/developer-responsibilities) documentation. -</Aside> - ---- - # Data Streams Billing Source: https://docs.chain.link/data-streams/billing @@ -130,16 +119,15 @@ Source: https://docs.chain.link/data-streams/billing integrating Chainlink Data Streams with your applications. </Aside> -Chainlink Data Streams offers two billing models: - -1. **Subscription model**: A subscription-based billing option. - -2. **Pay-per-report model**: You pay to verify reports from Data Streams onchain using the verifier contract. You pay per report verified. If you verify multiple reports in a batch, you pay for all of the reports included in that batch. - - The verification price is 0.35 USD per report. Chainlink Data Streams supports fee payments in LINK and in alternative assets, which currently includes native blockchain gas tokens and their ERC20-wrapped version. Payments made in alternative assets have a 10% surcharge when compared to LINK payments. +Chainlink Data Streams uses a subscription-based billing option. [Contact us](https://chainlinkcommunity.typeform.com/datastreams?#ref_id=docs) to learn more about Mainnet pricing and subscription options. +<Aside type="caution" title="[Deprecated] Pay-per-verification model"> + The pay-per-verification billing model has been deprecated. <br /> To learn more about the subscription model, please{" "} + <a href="https://chainlinkcommunity.typeform.com/datastreams?#ref_id=docs">contact us</a>. +</Aside> + --- # Data Streams Best Practices @@ -156,255 +144,174 @@ This page provides best practices and recommendations for using Chainlink Data S ## Real-World Assets (RWA) -Apply these RWA best practices when integrating or operating markets that use tokenized real-world assets. Developers and operators are responsible for assessing market integrity, implementing mitigations, and managing application-level risks — see the [Developer Responsibilities](/data-streams/developer-responsibilities) guidance for details. - -### Market Hours - -Markets for Real-World Assets (RWA) operate during specific hours and are subject to various market conditions that can create risks for applications. The following sections outline common market issues and how to mitigate them. - -<Aside type="note" title="Market Hours Overview"> - For detailed market hours and trading schedules, see the <a href="/data-streams/market-hours">Market Hours</a> page. -</Aside> - -#### Market gaps - -Market gaps occur when there are interruptions in trading or price discovery, leading to periods where the last available price may not reflect current market conditions. These gaps can create risks, particularly around market opens, closures, and unexpected disruptions. - -#### Market close - -Large price jumps between trading sessions due to after-hours news. - -A large price jump at market open could cause sudden liquidations, potentially leaving the perpetual DEX with bad debt if a trader's collateral is insufficient to cover the losses. - -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until market open.</li><li>`marketStatus`: 1 = Market Closed.</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Keep markets closed while `marketStatus = 1` to prevent users trading at unfair prices.<br /><br /> Leverage available should be set in line with the asset average volatility to avoid bad debt if a trader's collateral is insufficient to cover the losses. | - -#### Price formation at open/close - -Certain assets (e.g., FX open on Sunday afternoon) experience gradual price discovery due to fragmented liquidity and delayed trading activity. - -The perpetual DEX should avoid opening their market with the last close price. - -| Data Stream behavior | User guidance | -| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until a bid/ask becomes available or a transaction occurs.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Wait until `lastUpdateTimestamp` is current before opening the market so traders don't execute on stale quotes. | - -#### Sudden failures - -Unexpected system outages, order execution failures, or data feed disruptions can occur. +For best practices regarding RWA streams: -The price will be flat during that period, meaning if a perp DEX lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. - -| Data Stream behavior | User guidance | -| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus = 2` but `lastUpdateTimestamp` is stale. | +- **24/5 US Equities**: See the [24/5 US Equities User Guide](/data-streams/rwa-streams/24-5-us-equities-user-guide) for continuous price feed construction, edge cases, and risk management. +- **Market Events**: See the [Handling Market Events](/data-streams/rwa-streams/handling-market-events) guide for market hours, volatility, and corporate actions. -#### Trading halts +## Tokenized Assets -Stocks can be halted due to extreme volatility (e.g., limit up/down rules) or regulatory actions. +For best practices regarding stock splits and reverse splits for tokenized assets, please see the [Handling Stock Splits](/data-streams/tokenized-asset-streams/handling-stock-splits) guide. -The price will be flat during that period, meaning if a perp DEX lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. +--- -| Data Stream behavior | User guidance | -| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus = 2` but `lastUpdateTimestamp` is stale. | +# Calculated Streams +Source: https://docs.chain.link/data-streams/concepts/calculated-streams -*** +Calculated streams are Chainlink data streams whose values are derived by applying arithmetic expressions to multiple underlying inputs. -### Volatility & low liquidity +All Data Streams use a [Decentralized Oracle Network (DON)](/data-streams/architecture) where nodes reach consensus and publish signed reports. Traditional Data Streams aggregate market data from multiple independent providers, ensuring no single data source can compromise the stream's integrity. -During periods of high volatility or low liquidity, price movements can become unpredictable and exaggerated. These conditions can increase the risk of sudden liquidations and bad debt accumulation, requiring careful risk management strategies. +Instead of aggregating only raw market data, calculated streams compute derived values using predefined formulas applied to various inputs, including existing data streams, onchain state, and offchain APIs. Some inputs are decentralized aggregates (for example, crypto price streams from multiple independent providers), while others may come from a single protocol or API (for example, a specific vault contract or yield provider). Because a calculated stream depends on all of these inputs, you should evaluate their dependencies and failure modes carefully before using it in a value-securing application. -#### Algorithmic & HFT activity +<Aside type="caution" title="Important Considerations"> + Calculated streams behave differently from standard streams in important ways. Before integrating a calculated stream, + review the <a href="#key-differences-from-standard-streams">key differences</a> and{" "} + <a href="#risks-and-mitigation">risks and mitigation</a> sections to understand how these differences may affect your + application. +</Aside> -Rapid-fire trading by algos can create unpredictable price movements. +## Why use calculated streams? -High volatility can lead to liquidation and potential bad debt accumulation. +- **Simpler integrations**: Consume one stream instead of implementing calculation logic in your contracts or backend +- **Canonical formulas**: All integrators use the same formula and inputs, ensuring consistency across protocols +- **Managed infrastructure**: Chainlink handles RPC calls, API integrations, and the calculation pipeline -| Data Stream behavior | User guidance | -| :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | +## How to identify calculated streams -#### Low liquidity at open/close +Calculated streams are marked with a <span style="display: inline-block; font-size: 0.75rem; padding: 2px 6px; margin-left: 4px; border-radius: 4px; background: var(--blue-100); color: var(--blue-700); font-weight: 500; vertical-align: middle;">Calculated</span> badge in the Data Streams feed list. -Reduced market depth at trading session transitions can lead to higher volatility and spreads. +## How calculated streams work -High volatility can lead to liquidation and potential bad debt accumulation. +Calculated streams leverage existing Data Streams infrastructure. Data providers feed market data into the DON, which produces base streams. The DON then uses these base streams—along with onchain state and offchain APIs—as inputs to calculate derived values. -| Data Stream behavior | User guidance | -| :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | +### Architecture flow -*** +1. **Data collection**: The DON retrieves inputs specific to each calculated stream, which may include: + - Existing Data Streams (market prices from multiple independent data providers) + - Onchain state via RPC calls (vault balances, token supplies, contract data) + - Offchain data via APIs (yield rates, interest components, external reference data) +2. **Calculation**: The DON applies the predefined formula to combine the inputs +3. **Consensus and signing**: Nodes reach consensus on the calculated value and sign the report +4. **Publication**: Calculated streams are published through the Data Streams Aggregation Network -### Corporate actions +### Input sources -Corporate actions are events initiated by publicly traded companies that can significantly impact stock prices and trading behavior. These actions are usually announced outside regular trading hours and can cause substantial price movements when markets reopen. Users should monitor these events closely as they can lead to sudden price adjustments that may trigger unexpected liquidations or require position modifications. +The inputs for a calculated stream depend on what it's computing. A stream might use: -#### Bankruptcy & delisting +#### Existing Data Streams -Bankruptcy can lead to delisting or complete loss of equity value. +Market prices already aggregated from multiple independent sources (3+ providers). Example: using individual crypto asset prices as inputs for an index calculation. -Delisting will zero out prices for the asset. +#### Onchain state -| Data Stream behavior | User guidance | -| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until a new price is available.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Closing timestamp of the last session.</li></ul> | Monitor delisting news during `marketStatus` = `1` and close markets permanently once confirmed. | +Protocol-specific data read via RPC, such as vault balances, token supplies, or smart contract state. May come from a single protocol's contracts. -#### Spin-offs +#### Offchain APIs -When a company spins off a business unit into a separate publicly traded entity, the parent company's stock may adjust accordingly, while the spun-off company's shares begin trading independently. +External data from specific trusted providers, such as yield rates or reference values. May come from a single API endpoint. -Positions may need to be manually adjusted if the DEX doesn't support tracking the new entity. +### Calculation and output -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until the first post-spin trade.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements while `marketStatus = 1`.<br /><br />Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br /><br />If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | +The DON executes the predefined formula (weighted averages, ratios, sums, etc.) using the latest available inputs. The calculated value is packaged into a signed report with standard metadata (timestamps, fees) and published through the Data Streams Aggregation Network. You consume these reports using the same REST APIs, WebSocket connections, and onchain verification as traditional streams. -#### Stock splits & reverse splits +## Example: Tokenized yield product -<Aside type="note" title="Tokenized Stocks Guidance"> - Tokenized stocks such as [Backed xStock](/data-streams/reference/report-schema-v10) handle stock splits differently - using activation dates and staged multipliers to maintain price continuity. [Learn more about advanced stock split - handling](#handling-stock-splits-for-tokenized-assets). -</Aside> +A calculated stream for a tokenized yield-bearing vault might combine: -A stock split increases the number of shares while reducing the price per share (e.g., 2-for-1 split), often making shares more accessible to investors. A reverse split does the opposite, consolidating shares to increase the price per share. +- **Vault balance (onchain)**: Total assets in the vault contract +- **Token supply (onchain)**: Circulating supply of vault shares +- **Accrued yield (offchain)**: Interest from an external API -A 2-for-1 split would reduce the price by 50% from the previous trading session, any leveraged user could get liquidated. +**Formula:** `(vault balance + accrued yield) / token supply` -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until the split-adjusted price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements while `marketStatus = 1`.<br /><br />Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br /><br />If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | +**Result**: a price per share that reflects the vault's total value including pending yield. -#### Mergers & acquisitions (M\&A) +Without this stream, protocols accepting the vault token as collateral would need to query the vault contract, fetch accrued interest from the yield provider's API, perform the calculation themselves, and keep this logic synchronized across all integrators. A calculated stream helps ensure integrators apply the same pricing logic and update together when the underlying formula or yield source changes. -If a company is being acquired, its stock price may rise to reflect the acquisition premium. The acquiring company's stock might fluctuate based on investor sentiment regarding the deal's financial and strategic impact. +## Key differences from standard streams -Announcements can cause sharp price spikes or sustained moves. +While calculated streams use the same infrastructure and delivery mechanisms as standard streams, they have distinct behaviors you should understand before integrating. For mitigation strategies, see [Risks and mitigation](#risks-and-mitigation). -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | +### Report availability -#### Share buybacks & stock issuance +Standard streams aggregate data from multiple independent providers, so they remain available as long as enough providers are reporting. Calculated streams depend on **all** of their inputs being available. If any required input becomes unavailable or returns errors, the calculated **stream stops producing reports until all inputs recover**. This prevents potentially incorrect values from being published. -Reduced share supply from a buyback can drive stock prices higher, while an increase in share supply can lead to price dilution. +### Input reliability -Announcements can cause sharp price spikes or sustained moves. +Standard streams source data exclusively from decentralized aggregates of multiple independent data providers. Calculated streams may include a mix of: -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | +- **Decentralized aggregates**: Existing Data Streams with multiple independent sources (similar reliability to standard streams) +- **Single-source inputs**: Specific protocol contracts or APIs where availability depends on a single system -#### Dividends +Single-source inputs carry higher risk. If that source experiences downtime, report production halts entirely until it recovers. Review the input sources for any calculated stream you plan to use. -A company's stock price typically adjusts to reflect dividend payments. For example, when a company declares a 10% dividend, its stock price often drops by a similar amount on the ex-dividend date, as new buyers are no longer entitled to that dividend. +### Timing characteristics -Announcements can cause sharp price spikes or sustained moves. +Standard streams reflect a single aggregated market price at a point in time. Calculated streams combine multiple inputs that may update at different frequencies and reflect slightly different timestamps. The calculated value is an approximation based on the latest available data from each input, not a single-block atomic snapshot. -| Data Stream behavior | User guidance | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | -| <ul><li>`midPrice`: Closing price is repeated until the ex-date trade prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | +During rapid changes (large deposits, withdrawals, or sharp market moves), you may observe temporary differences between the calculated stream value and values from other sources like block explorers or protocol dashboards. These differences typically resolve as all inputs update to reflect the new state. *** -### Handling stock splits for tokenized assets - -Corporate actions, such as stock splits and reverse splits, require precise handling for tokenized assets to ensure price continuity and avoid disruptions. These events alter per‑share pricing while leaving the underlying economic exposure unchanged. They can produce abrupt per‑share price moves and must be handled carefully to avoid incorrect onchain price computations and unexpected liquidations. - -In the [v10 report schema](/data-streams/reference/report-schema-v10), continuity is preserved by staging a multiplier change with a scheduled `activationDateTime` so the Theoretical Price (`price` \* `currentMultiplier`) remains continuous. Split ratios are typically known in advance, but activation may occur while markets are closed, so some external price sources may not reflect the split until trading resumes. - -<Aside type="note" title="Note"> - This guidance is designed for multiplier handling in the [v10 report - schema](/data-streams/reference/report-schema-v10) and what integrators should expect around activation windows and - protocol behavior. Similar principles may apply to future schemas that host tokenized stocks, but applicability and - exact behavior will depend on each schema's design and are not guaranteed. -</Aside> - -#### Guiding principle - -Follow these principles when handling multiplier changes during corporate actions: +## Risks and mitigation -1. The protocol considers the Theoretical Price as `price` \* `currentMultiplier`. -2. Ahead of the event, `newMultiplier` and `activationDateTime` are staged. -3. At `activationDateTime` (Unix), `currentMultiplier` becomes `newMultiplier`. - - The underlying `price` from traditional markets should start reflecting the split the next time trading opens, so at the next `price` update, the Theoretical Price should remain continuous. +Calculated streams inherit risks from their underlying inputs and introduce additional considerations. Use these strategies to mitigate potential issues. -#### Example (10:1 split, AAPL) +### Handling report gaps -The following hypothetical scenario demonstrates how a 10:1 AAPL stock split is handled through the staged multiplier system, showing the progression from announcement through protocol reopening with proper price continuity maintained throughout. +Because calculated streams stop producing reports when any input fails, your application must handle gaps in report availability. -The following timeline outlines the key events and actions taken at each stage: +#### Mitigation -- **T-2**: [Split announcement and multiplier staging](#announcement-t-2) -- **T-1**: [Protocol preparation and monitoring setup](#protocol-engagement-t-1) -- **T0**: [Multiplier activation (split effective date)](#activation-t0) -- **T+1**: [Market reopening with adjusted prices](#market-reopening-t1) -- **T+2**: [Protocol resumption after verification](#protocol-reopening-t2) +- Design your protocol to handle report gaps gracefully (pause operations, use last-known values with appropriate staleness checks, or implement fallbacks based on your risk tolerance) +- Implement staleness checks to detect when reports stop arriving and trigger appropriate protocol responses +- Set alerts for report gaps to detect input source issues early -##### Announcement (T-2) +### Single-source input reliability -A 10:1 AAPL stock split is announced. [The report](/data-streams/reference/report-schema-v10) updates to stage the split: +Single-source inputs (specific APIs or contracts) may have lower availability than decentralized aggregates. -- `newMultiplier` is set to 10x the value of `currentMultiplier`. -- `activationDateTime` is set to the Unix timestamp of the split. -- `currentMultiplier` is unaffected until activation. +#### Mitigation -##### Protocol engagement (T-1) +- Understand your input sources and assess the reliability of each, particularly single-source APIs or contracts +- For critical applications, consider independently monitoring the availability of single-source inputs +- Define acceptable downtime thresholds and corresponding protocol responses -At this stage, users are advised to monitor for changes in `activationDateTime` and inspect the upcoming change to prepare appropriate action, such as preparing the protocol for a pause around the `activationDateTime` in order to ensure appropriate handling of the stock split. +### Timing discrepancies -##### Activation (T0) +Temporary differences between the calculated stream and other data sources are expected during rapid changes. -When the provider applies the split, [the report](/data-streams/reference/report-schema-v10) updates: +#### Mitigation -- `newMultiplier` remains the current value. -- `activationDateTime` is set to `0`. -- `currentMultiplier` is updated to the same value as `newMultiplier`. +- Implement max deviation checks against expected ranges +- Use time-weighted averages or circuit breakers for extreme moves +- Monitor trends over time rather than reacting to individual updates +- Compare calculated values against market references when available (e.g., spot prices for index tokens) -<Aside type="danger" title="Important"> - If activation occurs while the underlying market is closed, prices may still show the pre‑event last trade. Do not - compute the Theoretical Price during this pre-adjustment window. Monitor `marketStatus` and keep the protocol paused - until the first post‑event trade prints and the Theoretical Price is continuous. +<Aside type="note" title="Developer Responsibilities"> + When using calculated streams, you inherit all responsibilities associated with the underlying inputs plus additional + responsibilities for monitoring calculation health and managing time-sensitivity requirements. Review the{" "} + <a href="/data-streams/developer-responsibilities">Developer Responsibilities</a> page for comprehensive guidance on + risk assessment and mitigation techniques. </Aside> -If activation occurs while the underlying market is closed, prices may still show the pre‑event last trade. Do not compute the Theoretical Price during this pre-adjustment window. Monitor `marketStatus` and keep the protocol paused until the first post‑event trade prints and the Theoretical Price is continuous. - -##### Market reopening (T1) - -The stock split has taken effect. Generally, this occurs after the market closes or over the weekend, meaning `price` may not yet reflect the new economic value per share. Upon the market reopening, `price` should start reflecting the split-adjusted value. - -##### Protocol reopening (T2) - -Users should pause markets before `activationDateTime` and keep them paused until: - -- The market has reopened (monitor `marketStatus`) -- `price` has updated in line with the split ratio (e.g., 10:1) -- You have confirmed that the Theoretical Price matches expectations - -After all the above checks have been confirmed, users can unpause their protocol and continue and resume normal operation. - -#### Activation-time convention - -Each tokenized asset issuer sets its own activation time. For example, the xStocks default `activationDateTime` is 00:00 UTC on the effective date. Once `activationDateTime` is reached, `currentMultiplier` becomes `newMultiplier`. - -Because underlying venues may be closed at activation, some external price sources may not reflect the split immediately. If `activationDateTime` occurs while the underlying market is closed, the report’s `currentMultiplier` will become `newMultiplier`; however, `price` can remain at the pre-event level until the market reopens. During this post-activation, pre-adjustment interval (after the multiplier has changed but before the underlying `price` updates), the Theoretical Price can be incorrect. Use `marketStatus` to pause until `price` reflects the event. +*** -#### Integrator risk & handling +## Best practices -Computing `price` \* `currentMultiplier` when the price has not adjusted (e.g., market closed) can produce large errors. It is critical to ensure that the Theoretical Price is again reflective of actual market conditions before allowing live trading. +### Protocol design -Treat any multiplier change (splits, dividends, etc) and `activationDateTime` as a maintenance window; pause/guard the protocol, then verify post-activation conditions before resuming. +- Set deviation limits to cap price changes per update or time window +- Define fallback behavior if the stream stops updating or jumps beyond thresholds +- Test your protocol's behavior during report gaps before deploying to production -<Aside type="caution" title="Integrator Responsibility"> - It is the integrator's responsibility to perform proper handling and risk management. Failure to follow these best - practices may result in significant financial losses. Ensure that all multiplier changes, activation windows, and - post-activation conditions are verified before resuming operations. -</Aside> +### Monitoring -For broader guidance around market hours and event handling, refer to the [Market Hours](#market-hours) guidance. +- Set alerts for report gaps to detect when no new reports arrive within your expected update frequency +- Track the calculated stream value over time to establish normal behavior patterns +- Monitor key inputs independently when feasible (vault balances, token supplies, API availability) to identify which input may be causing issues +- Alert on movements outside your expected range --- @@ -609,6 +516,13 @@ Chainlink Data Streams source pricing data from multiple independent aggregators --- +# Deprecation of Chainlink Data Streams +Source: https://docs.chain.link/data-streams/deprecating-streams + +<StreamsPage ecosystem="deprecating" /> + +--- + # Developer Responsibilities: Market Integrity and Application Code Risks Source: https://docs.chain.link/data-streams/developer-responsibilities @@ -845,6 +759,23 @@ RWA markets operate during specific hours, with breaks for holidays and sometime | **Precious Metals (Spot)**<br />(XAU, XAG) | **18:00 Sun** | **17:00 Fri** | 17:00–18:00 Mon-Thu | Jan 1, Good Fri, Dec 25 | | **Commodities** <br /> (WTI Synthetic Spot) | **18:00 Sun** | **17:00 Fri** | 17:00–18:00 Mon-Thu | [NYMEX holiday calendar](https://www.cmegroup.com/tools-information/holiday-calendar/) | +### US Equities 24/5 Trading Sessions + +For feeds using the [RWA Advanced (v11) schema](/data-streams/reference/report-schema-v11), US Equities are available across three distinct trading sessions, providing 24/5 coverage: + +| Session | Hours (ET) | `marketStatus` Value | Description | +| ------------------- | ------------------------------------- | ------------------------------------ | ---------------------------------------------- | +| **Regular Hours** | 9:30am–4:00pm Mon–Fri | `2` (Regular hours) | Primary trading session with highest liquidity | +| **Extended Hours** | 4:00am–9:30am & 4:00pm–8:00pm Mon–Fri | `1` (Pre-market) & `3` (Post-market) | Pre-market and post-market sessions | +| **Overnight Hours** | 8:00pm–4:00am Sun evening–Fri morning | `4` (Overnight) | Overnight session with limited liquidity | + +**Additional `marketStatus` values:** + +- `0` (Unknown) — Market status cannot be determined +- `5` (Weekend) — Weekend period: 8:00pm Fri–8:00pm Sun + +See the [24/5 US Equities User Guide](/data-streams/rwa-streams/24-5-us-equities-user-guide) for detailed information on building continuous price feeds and managing session transitions. + \* Times shown as **HH:MM ET**.\ \*\* Half-day trading may apply on the eve of certain U.S. holidays (e.g., Jul 3, Nov 28). Consult the linked exchange calendars for exact cut-off times. @@ -856,13 +787,6 @@ For comprehensive guidance on managing risks related to market hours, market gap --- -# Net Asset Value (NAV) Data Streams -Source: https://docs.chain.link/data-streams/nav-streams - -<FeedPage dataFeedType="streamsNav" initialNetwork="arbitrum" allowNetworkTableExpansion={true} defaultNetworkTableExpanded={false} /> - ---- - # Data Streams Candlestick API Source: https://docs.chain.link/data-streams/reference/candlestick-api @@ -937,9 +861,9 @@ curl -X POST \ **`/api/v1/symbol_info`** -| Type | Description | Parameter(s) | -| :------- | :------------------------------------------------------- | :----------------------------------------------------------------------------------------------- | -| HTTP GET | Gets a list of all supported symbols on the environment. | <ul><li>`group` (optional): Filter symbols by group. Currently only supports "crypto".</li></ul> | +| Type | Description | Parameter(s) | +| :------- | :------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------- | +| HTTP GET | Gets a list of all supported symbols on the environment. | <ul><li>`group` (optional): Filter symbols by group. See [`/groups`](#get-list-of-supported-groups) for available groups.</li></ul> | ##### Sample request @@ -976,26 +900,85 @@ curl -X GET \ | `401` | `Unauthorized - Authorization header is required \|\| Invalid authorization header format \|\| token signature is invalid: signature is invalid \|\| ...` | The authorization header was missing or invalid. | | `500` | `Error - Something went wrong` | An unexpected server error occurred. | +### Get list of supported groups + +##### Endpoint + +**`/api/v1/groups`** + +| Type | Description | Parameter(s) | +| :------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------- | +| HTTP GET | Gets a list of all supported symbol types on the environment. Any group name returned can be used as a filter in the `/symbol_info` endpoint. | None | + +##### Sample request + +```bash +curl -X GET \ + -H "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \ + https://priceapi.testnet-dataengine.chain.link/api/v1/groups +``` + +##### Response + +- **Status**: `200` + + ```json + { + "s": "ok", + "d": { + "groups": [{ "id": "crypto" }, { "id": "equities" }, { "id": "forex" }, { "id": "equity" }] + } + } + ``` + + | Field | Type | Description | + | :------- | :------- | :--------------------------------- | + | `s` | `string` | The status of the request. | + | `d` | `object` | The data returned by the API call. | + | `groups` | `array` | Array of supported groups. | + +##### Error Responses + +| Status Code | Error Message | Description | +| :---------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------- | +| `401` | `Unauthorized - Authorization header is required \|\| Invalid authorization header format \|\| token signature is invalid: signature is invalid \|\| ...` | The authorization header was missing or invalid. | +| `500` | `Error - Something went wrong` | An unexpected server error occurred. | + ### Get candlestick data (column format) ##### Endpoint **`/api/v1/history`** -| Type | Description | Parameter(s) | -| :------- | :-------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| HTTP GET | Gets candlestick data in column format. | <ul><li>`symbol`: The symbol to query.</li><li>`resolution`: Resolution of the data (required but not used, use "1m").</li><li>`from`: Unix timestamp of the leftmost required bar (inclusive).</li><li>`to`: Unix timestamp of the rightmost required bar (inclusive).</li></ul> | +| Type | Description | Parameter(s) | +| :------- | :-------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| HTTP GET | Gets candlestick data in column format. | <ul><li>`symbol`: The symbol to query.</li><li>`resolution`: Resolution of the data. E.g., "1m". Must match [supported resolutions](#supported-resolutions).</li><li>`from`: Unix timestamp of the leftmost required bar (inclusive).</li><li>`to`: Unix timestamp of the rightmost required bar (inclusive).</li></ul> | + +#### Supported resolutions + +The resolution you provide must be within the supported boundaries for the given time window size: -**Note**: The resolution of the data is currently based on the size of the time window: +| Time window size | Supported resolutions | +| :------------------------ | :------------------------------- | +| 1 min - 24 hours | 1 minute - 24 hours (1m - 24h) | +| 1 - 5 days | 5 minutes - 5 days (5m - 5d) | +| 5 - 30 days | 30 minutes - 30 days (30m - 30d) | +| 30 - 90 days | 1 hour - 90 days (1h - 90d) | +| 90 - 180 days | 2 hours - 180 days (2h - 6M) | +| 180 - 365 days | 24 hours - 365 days (24h - 1y) | +| 365 - 1825 days (1-5 yrs) | 1 week - 5 years (1w - 5y) | +| Over 1825 days (> 5 yrs) | Over 1 month | -| Max time window size | Resolution of candles | -| :------------------- | :-------------------- | -| \<= 24 hours | 1 minute | -| \<= 5 days | 5 minutes | -| \<= 30 days | 30 minutes | -| \<= 90 days | 1 hour | -| \<= 6 months | 2 hours | -| > 6 months | 1 day | +Resolutions can be provided in the following units: + +| Name | Unit | Example | +| :------ | :--- | :------ | +| minutes | m | 5m | +| hours | h | 3h | +| days | d | 1d | +| weeks | w | 2w | +| months | M | 6M | +| years | y | 2y | ##### Sample request @@ -1048,9 +1031,9 @@ curl -X GET \ **`/api/v1/history/rows`** -| Type | Description | Parameter(s) | -| :------- | :----------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| HTTP GET | Gets candlestick data in row format. | <ul><li>`symbol`: The symbol to query.</li><li>`resolution`: Resolution of the data (required but not used, use "1m").</li><li>`from`: Unix timestamp of the leftmost required bar (inclusive).</li><li>`to`: Unix timestamp of the rightmost required bar (inclusive).</li></ul> | +| Type | Description | Parameter(s) | +| :------- | :----------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| HTTP GET | Gets candlestick data in row format. | <ul><li>`symbol`: The symbol to query.</li><li>`resolution`: Resolution of the data. E.g., "1m". Must match [supported resolutions](#supported-resolutions).</li><li>`from`: Unix timestamp of the leftmost required bar (inclusive).</li><li>`to`: Unix timestamp of the rightmost required bar (inclusive).</li></ul> | ##### Sample request @@ -5128,21 +5111,21 @@ The [RWA Advanced (v11)](/data-streams/reference/report-schema-v11) report schem These advanced fields enable protocols to implement more sophisticated risk management and settlement logic. Where applicable, streams using this schema can provide coverage across extended trading sessions including pre-market, post-market, and overnight hours — though extended hours availability varies by stream. See individual [RWA stream details](/data-streams/rwa-streams?schema=v11) for specific coverage and the [RWA Advanced (v11) reference](/data-streams/reference/report-schema-v11) for complete field specifications. -## Net Asset Value (NAV) +## SmartData -[Chainlink NAV streams](/data-streams/nav-streams) use the [NAV (v9)](/data-streams/reference/report-schema-v9) report schema to provide real-time, tamper-proof access to the Net Asset Value (`navPerShare`) of tokenized assets, funds, or portfolios. Each report includes NAV per share (`navPerShare`), NAV date (`navDate`), assets under management (`aum`), and ripcord status (`ripcord`). The ripcord is set to true (`1`) by the asset issuer when the consumer should ignore the value being sent (for cases such as maintenance, upstream data source outages, etc). The feed data will remain stale until the ripcord returns false (`0`). +[Chainlink SmartData streams](/data-streams/smartdata-streams) use the [SmartData (v9)](/data-streams/reference/report-schema-v9) report schema to provide real-time, tamper-proof access to data such as Net Asset Value (`navPerShare`) of tokenized assets, funds, or portfolios, as well as Proof of Reserve data. Each report includes NAV per share (`navPerShare`), NAV date (`navDate`), assets under management (`aum`), and ripcord status (`ripcord`). The ripcord is set to true (`1`) by the asset issuer when the consumer should ignore the value being sent (for cases such as maintenance, upstream data source outages, etc). The feed data will remain stale until the ripcord returns false (`0`). NAV is a fundamental financial metric that represents the value of an investment vehicle such as a mutual fund or ETF and is calculated as the total assets minus the total liabilities. -Data Streams ensures that any NAV update, whenever it occurs, is captured and made available immediately and at low latency, allowing for seamless integration with onchain applications alongside other real-time data streams. Although the NAV value may not change frequently, Data Streams provides the most recent NAV as soon as it is published by the source. +Data Streams ensures that any SmartData update, whenever it occurs, is captured and made available immediately and at low latency, allowing for seamless integration with onchain applications alongside other real-time data streams. Although the values may not change frequently, Data Streams provides the most recent data as soon as it is published by the source. ## Tokenized Asset -[Chainlink Tokenized Asset streams](/data-streams/backed-streams) use the [Tokenized Asset (v10)](/data-streams/reference/report-schema-v10) report schema to provide financial market data for tokenized equities such as [xStock](https://xstocks.com/us) assets. These streams combine data from US equity streams with data from the tokenization service to enable users to handle corporate actions affecting the underlying equities. Each report includes the staleness measure (`lastUpdateTimestamp`), consensus mid price (`price`), market status (`marketStatus`), current multiplier (`currentMultiplier`, the number of underlying shares each xStock is redeemable for), new multiplier (`newMultiplier`, the future number of shares after a scheduled corporate action), activation date/time of the corporate action (`activationDateTime`) and the tokenized price if available on primary or secondary markets (`tokenizedPrice`). +[Chainlink Tokenized Asset streams](/data-streams/tokenized-asset-streams) use the [Tokenized Asset (v10)](/data-streams/reference/report-schema-v10) report schema to provide financial market data for tokenized equities. These streams combine data from US equity streams with data from tokenization services to enable users to handle corporate actions affecting the underlying equities. Each report includes the staleness measure (`lastUpdateTimestamp`), consensus mid price (`price`), market status (`marketStatus`), current multiplier (`currentMultiplier`, the number of underlying shares each tokenized asset is redeemable for), new multiplier (`newMultiplier`, the future number of shares after a scheduled corporate action), activation date/time of the corporate action (`activationDateTime`) and the tokenized price if available on primary or secondary markets (`tokenizedPrice`). The underlying US equities trade on traditional exchanges during [market hours](/data-streams/market-hours). These market hours depend per asset class and can be subject to unexpected halts, pauses and other behaviors affecting traditional markets. For this reason, this class of Data Streams contains a market hours flag and a staleness measure to equip our users to handle these events correctly. It is critical that users implement correct safeguards on their end to pause markets, add more conservative risk caps, or implement other measures appropriate for their application. -[Tokenized Asset (v10)](/data-streams/reference/report-schema-v10) is designed specifically for tokenized equities such as xStocks and contains data from the Chainlink US equities streams, combined with data provided by the tokenizer to properly handle corporate actions. With this enhanced data users are able to handle expected and unexpected market events such as pauses, halts and market off hours. The tokenization provider layers in data around the `currentMultiplier`, the `newMultiplier` and the `activationDateTime` of the new multiplier to handle corporate actions. +[Tokenized Asset (v10)](/data-streams/reference/report-schema-v10) is designed specifically for tokenized equities and contains data from the Chainlink US equities streams, combined with data provided by the tokenizer to properly handle corporate actions. With this enhanced data users are able to handle expected and unexpected market events such as pauses, halts and market off hours. The tokenization provider layers in data around the `currentMultiplier`, the `newMultiplier` and the `activationDateTime` of the new multiplier to handle corporate actions. --- @@ -5151,7 +5134,7 @@ Source: https://docs.chain.link/data-streams/reference/report-schema-v10 <DataStreams section="dsNotes" /> -Chainlink Backed xStock Data Streams adhere to the report schema outlined below. +Chainlink Tokenized Asset Data Streams adhere to the report schema outlined below. ### Schema Fields @@ -5173,67 +5156,104 @@ Chainlink Backed xStock Data Streams adhere to the report schema outlined below. <Aside type="danger" title="Weekend Usage Disclaimer"> - **Users should not use these streams during weekends** due to limited exchange activity. + **The `price` field does not update during weekends** because the underlying real-world equity market is closed. + + However, the `tokenizedPrice` field continues to update as it reflects trading activity on centralized exchanges (CEXs). Weekend liquidity tends to be thin, so users should implement guardrails against unexpected volatility. - If usage is necessary, increase fees to mitigate risks. Developers are solely responsible for monitoring and mitigating market integrity risks, as outlined in the [Developer Responsibilities](/data-streams/developer-responsibilities) documentation. + Developers are solely responsible for monitoring and mitigating market integrity risks, as outlined in the [Developer Responsibilities](/data-streams/developer-responsibilities) documentation. </Aside> **Notes:** -- Future Backed xStock streams may use different report schemas. +- Future Tokenized Asset streams may use different report schemas. - `price` updates in real time during market open, but may become stale during market closed periods. - `currentMultiplier` reflects all past corporate actions and is updated only when a new action is activated. - `activationDateTime` and `newMultiplier` provide advance notice of upcoming corporate actions, allowing protocols to prepare. -- See more detailed guidance for handling stock splits in the [Best Practices](/data-streams/concepts/best-practices#handling-stock-splits-for-tokenized-assets) documentation. +- See more detailed guidance for handling stock splits in the [Handling Stock Splits](/data-streams/tokenized-asset-streams/handling-stock-splits) documentation. --- # Report Schema: RWA Advanced (v11) Source: https://docs.chain.link/data-streams/reference/report-schema-v11 +import { Aside } from "@components" + +{/* Fix for the table cutting off/overflowing */} + <DataStreams section="dsNotes" /> Chainlink Data Streams that use the RWA Advanced (v11) schema adhere to the structure outlined below. ## Schema Fields -| Field | Type | Description | -| ----------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `feedId` | `bytes32` | Unique identifier for the Data Streams feed | -| `validFromTimestamp` | `uint32` | Earliest timestamp when the price is valid (seconds) | -| `observationsTimestamp` | `uint32` | Latest timestamp when the price is valid (seconds) | -| `nativeFee` | `uint192` | Cost to verify report onchain (native token) | -| `linkFee` | `uint192` | Cost to verify report onchain (LINK) | -| `expiresAt` | `uint32` | Expiration date of the report (seconds) | -| `mid` | `int192` | Liquidity-weighted mid price | -| `lastSeenTimestampNs` | `uint64` | Staleness indicator based on mid price (nanoseconds) | -| `bid` | `int192` | Median bid price | -| `bidVolume` | `int192` | Volume at bid price | -| `ask` | `int192` | Median ask price | -| `askVolume` | `int192` | Volume at ask price | -| `lastTradedPrice` | `int192` | Last traded price | -| `marketStatus` | `uint32` | Status of the real-world equity market. <br /> Possible values: <br /> `0` (Unknown), <br /> `1` (Pre-market extended hours), <br /> `2` (Regular hours), <br /> `3` (Post-market hours), <br /> `4` (Overnight), <br /> `5` (Weekend) <br /> [More details](#market-status-values) | +| Field | Type | Description | +| ----------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `feedId` | `bytes32` | Unique identifier for the Data Streams feed | +| `validFromTimestamp` | `uint32` | Earliest timestamp when the price is valid (seconds) | +| `observationsTimestamp` | `uint32` | Latest timestamp when the price is valid (seconds) | +| `nativeFee` | `uint192` | Cost to verify report onchain (native token) | +| `linkFee` | `uint192` | Cost to verify report onchain (LINK) | +| `expiresAt` | `uint32` | Expiration date of the report (seconds) | +| `mid` | `int192` | DON Consensus mid-price | +| `lastSeenTimestampNs` | `uint64` | Reflects the timestamp of the last update for the **mid price only** (nanoseconds). See [Notes](#notes) below. | +| `bid` | `int192` | Median bid price | +| `bidVolume` | `int192` | Volume at bid price. See [bid/ask volume note](#bidask-volume-note) below. | +| `ask` | `int192` | Median ask price | +| `askVolume` | `int192` | Volume at ask price. See [bid/ask volume note](#bidask-volume-note) below. | +| `lastTradedPrice` | `int192` | Last traded price | +| `marketStatus` | `uint32` | Status of the real-world asset market. Values depend on the stream's supported hours. See [Market Status Values](#market-status-values) for details. | ### Market Status Values -The `marketStatus` field reflects the current state of the equity market: +The `marketStatus` field indicates the current state of the market. The possible values vary depending on the stream's supported trading hours: + +#### Standard RWA Streams + +For streams with standard market hours coverage. Unless a feed explicitly states extended hours support, it is assumed to follow this format: + +| Value | Status | Description | +| ----- | ----------- | ---------------------------------- | +| `0` | **Unknown** | Market status cannot be determined | +| `1` | **Closed** | Market is closed | +| `2` | **Open** | Market is open | + +#### 24/5 US Equities Streams -| Value | Status | Hours (ET) | Description | -| ----- | ----------------- | ------------------------------------- | ---------------------------------------------- | -| `0` | **Unknown** | — | Market status cannot be determined | -| `1` | **Pre-market** | 4:00am–9:30am Mon–Fri | Extended hours before regular trading session | -| `2` | **Regular hours** | 9:30am–4:00pm Mon–Fri | Primary trading session with highest liquidity | -| `3` | **Post-market** | 4:00pm–8:00pm Mon–Fri | Extended hours after regular trading session | -| `4` | **Overnight** | 8:00pm–4:00am Sun evening–Fri morning | Overnight session with limited liquidity | -| `5` | **Weekend** | 8:00pm Fri–8:00pm Sun | Weekend period when primary markets are closed | +For streams with 24/5 extended hours coverage (e.g., US Equities): -Users should implement appropriate safeguards based on market status, such as pausing trading, adjusting risk parameters, or implementing staleness checks during non-regular hours. +| Value | Status | Normal Hours (ET) | Description | +| ----- | ----------------- | ------------------------------------- | ---------------------------------------------------------- | +| `0` | **Unknown** | — | Market status cannot be determined | +| `1` | **Pre-market** | 4:00am–9:30am Mon–Fri | Extended hours before regular trading session | +| `2` | **Regular hours** | 9:30am–4:00pm Mon–Fri | Primary trading session with highest liquidity | +| `3` | **Post-market** | 4:00pm–8:00pm Mon–Fri | Extended hours after regular trading session | +| `4` | **Overnight** | 8:00pm–4:00am Sun evening–Fri morning | Overnight session with limited liquidity | +| `5` | **Closed** | — | Market closed (weekends, holidays, or unexpected closures) | + +Users should implement appropriate safeguards based on market status, such as pausing trading, adjusting risk parameters, or implementing staleness checks during non-regular hours or closed periods. + +<Aside type="note" title="Handling Unknown and Closed Status"> + Consumers should implement logic to handle market status `0` (Unknown) and market status `5` (Closed), as these + periods imply no active feed and require a decision on fallback behavior (e.g., using a tokenized price, pausing the + market, etc.). +</Aside> ### Notes +#### Last Seen Timestamp + +- `lastSeenTimestampNs` helps applications detect stale data for the mid price, especially important during market transitions and holidays. +- **IMPORTANT**: The `lastSeenTimestampNs` field reflects the timestamp of the last update for the `mid` price only. Do not assume this timestamp applies to `bid`, `ask`, `bidVolume`, `askVolume`, or `lastTradedPrice`. Different fields may have been updated at different times. + +#### Bid/Ask Volume + +For U.S. equities, there is no single consolidated order book. Instead, multiple venues each maintain their own order books. Because data providers source from different markets, the `bidVolume` and `askVolume` reported at each update come from one specific order book at a time, not an aggregate across all venues. + +As a result, these volume fields should not be treated as a proxy for total market liquidity at the top of book. They are informational and not especially representative in fragmented markets like U.S. equities. + +#### Additional Notes + - Future streams using this format may adopt different report schemas as needed. -- `lastSeenTimestampNs` helps applications detect stale data, especially important during market transitions and holidays. -- Market status cannot detect public holidays. See [Market Hours](/data-streams/market-hours) for major holiday periods. - Data availability and sourcing vary by session. Liquidity is typically highest during regular hours and lower during extended and overnight sessions. --- @@ -5373,17 +5393,17 @@ RWA streams adhere to the report schema outlined below. - `marketStatus`: - Users are responsible for handling market status changes in their applications. - - For further guidance, refer to the [Market Hours Best Practices](/data-streams/concepts/best-practices#market-hours) documentation. + - For further guidance, refer to the [Handling Market Events](/data-streams/rwa-streams/handling-market-events) documentation. - Future RWA streams may use different report schemas. --- -# Report Schema: NAV (v9) +# Report Schema: SmartData (v9) Source: https://docs.chain.link/data-streams/reference/report-schema-v9 <DataStreams section="dsNotes" /> -Chainlink NAV Data Streams streams adhere to the report schema outlined below. +Chainlink SmartData streams adhere to the report schema outlined below. ### Schema Fields @@ -5402,7 +5422,7 @@ Chainlink NAV Data Streams streams adhere to the report schema outlined below. **Notes:** -- Future NAV streams may use different report schemas. +- Future SmartData streams may use different report schemas. ##### `ripcord` Status @@ -5411,39 +5431,632 @@ Chainlink NAV Data Streams streams adhere to the report schema outlined below. --- -# Real World Asset (RWA) Data Streams -Source: https://docs.chain.link/data-streams/rwa-streams +# 24/5 US Equities User Guide +Source: https://docs.chain.link/data-streams/rwa-streams/24-5-us-equities-user-guide -<FeedPage dataFeedType="streamsRwa" initialNetwork="arbitrum" allowNetworkTableExpansion={true} defaultNetworkTableExpanded={false} /> +Chainlink 24/5 U.S. Equities Streams provide real-time equity pricing data across all major U.S. single-name equities and ETFs spanning regular, pre-market, post-market, and overnight trading sessions. The [advanced RWA schema](/data-streams/reference/report-schema-v11) includes fields such as market status flags, best bid and ask prices, bid and ask volumes, staleness measures, and last traded prices to facilitate more advanced execution and risk management. ---- +The data referenced in this document covers 24/5 trading hours in US equities on a range of traditional venues. While there is currently no trading activity in traditional markets over the weekend on any venue, protocols can extend their pricing coverage to 24/7 in multiple ways, such as leveraging the pricing of [tokenized stocks](#stream-switching-example-logic) on secondary markets such as CEXes and DEXes. -# Streams Trade Implementation -Source: https://docs.chain.link/data-streams/streams-trade +Developers are responsible for choosing the appropriate feed and ensuring that the operation and performance of their choice matches expectations. For more information, please visit the Chainlink [documentation](/data-streams/developer-responsibilities). -The Streams Trade implementation combines Chainlink Data Streams with [Chainlink Automation](/chainlink-automation) to enable automated trade execution. This implementation allows decentralized applications to automate trade execution, mitigate frontrunning, and limit bias or adverse incentives in executing non-user-triggered orders. +## Schema -Read more about the [Streams Trade Architecture](/data-streams/architecture#streams-trade-architecture) and an [example trading flow](/data-streams/architecture#example-trading-flow-using-streams-trade). +The data is delivered using the [RWA Advanced (v11) schema](/data-streams/reference/report-schema-v11). -## Getting Started +This advanced RWA schema is built to support 24/5 streams, including DON Consensus `mid` price (with its corresponding timestamp `lastSeenTimestampNs` for staleness tracking), order book depth (`bid`, `ask`, `bidVolume`, `askVolume`), execution data (`lastTradedPrice`), and granular market phases (`marketStatus` values for Pre-market, Regular hours, Post-market, Overnight, and Closed). -To implement Streams Trade in your application: +<Aside type="caution" title="Important: Timestamp Scope"> + The `lastSeenTimestampNs` field reflects the timestamp of the last update for the `mid` price only. This timestamp + does **not** apply to other fields in the report such as `bid`, `ask`, `bidVolume`, `askVolume`, or `lastTradedPrice`. + Different fields may have been updated at different times. +</Aside> -1. First, ensure Streams Trade is available on your desired network by checking the [Supported Networks](/data-streams/supported-networks#streams-trade-implementation-onchain-lookup) page. -2. Review the [Architecture Documentation](/data-streams/architecture#streams-trade-architecture) to understand the system components. -3. See an [Example Trading Flow](/data-streams/architecture#example-trading-flow-using-streams-trade) to understand how trades are executed. -4. Follow our [Getting Started Guide](/data-streams/getting-started) to set up your first integration. +<Aside type="note" title="Bid/Ask Volume Interpretation"> + For U.S. equities, there is no single consolidated order book—multiple venues each maintain their own. The `bidVolume` + and `askVolume` reported come from one specific order book at a time, not an aggregate across all venues. These values + should not be treated as a proxy for total market liquidity and are primarily informational. +</Aside> -## Common Use Cases +## Feeds -Streams Trade is particularly well-suited for: +Each instrument is exposed through three distinct data streams feeds, each corresponding to a specific trading phase: **Regular Hours**, **Extended Hours**, and **Overnight Hours**. -- **Perpetual Futures Protocols**: Enable high-performance onchain perpetual futures that can compete with centralized exchanges -- **Automated Market Making**: Implement sophisticated market making strategies with real-time price updates -- **Options Protocols**: Enable precise and timely settlement of options contracts -- **Prediction Markets**: Allow quick responses to real-time events with accurate settlement data +You can view all available 24/5 US Equities streams in the [stream table viewer](/data-streams/stream-ids) or see the [complete list below](#available-streams). ---- +For example, **TSLA** is available via the following streams: + +- `TSLA/USD-Streams-ExtendedHours` +- `TSLA/USD-Streams-OvernightHours` +- `TSLA/USD-Streams-RegularHours` + +To construct a **continuous price feed**, users must **dynamically switch** between these individual streams based on the value of `marketStatus`. The mapping logic is as follows: + +| Market Status | Stream | +| ----------------- | --------------------------------- | +| `1` (Pre-market) | `TSLA/USD-Streams-ExtendedHours` | +| `2` (Regular) | `TSLA/USD-Streams-RegularHours` | +| `3` (Post-market) | `TSLA/USD-Streams-ExtendedHours` | +| `4` (Overnight) | `TSLA/USD-Streams-OvernightHours` | + +<Aside type="note" title="Note"> + Market status `0` (Unknown) and `5` (Closed) require custom handling. See the [Building a Continuous Price + Feed](#building-a-continuous-price-feed) section below. +</Aside> + +## Building a Continuous Price Feed + +Building a continuous price feed by dynamically switching streams requires robust exception handling to manage edge cases effectively. Because different protocols have unique risk profiles and design requirements, Data Streams allows you to implement custom logic tailored to your specific needs. + +There is no one-size-fits-all solution to integrating 24/5 streams. The sections below outline edge cases you will encounter when building a continuous price feed along with recommended mitigation strategies. For information on structural risks and protocol-specific considerations, see the [Risks](#risks) section. + +If you wish to jump ahead to view an example of switching logic, jump to [Stream Switching Example Logic](#stream-switching-example-logic). + +### Edge Cases and Mitigation + +#### Price Jumps at Session Transition Boundaries + +When transitioning between Regular ↔ Extended ↔ Overnight sessions, noticeable price dislocations can occur. + +These differences are expected and normal due to unique liquidity conditions, venues, participants, and pricing sources per session. These are not bad data; they are true market microstructure effects. + +Typical jumps are **1–2%**, but **larger spikes (10–20%+)** are possible during low-liquidity environments or impactful news cycles. + +##### Mitigation + +**Phase-specific streams are provided intentionally** to give users control over when and how transitions occur. Optional safeguards: + +- Pause or lock market activity during transition windows +- Delay feed switching until price convergence or stability threshold is met +- Apply price smoothing (EMA/VWAP/TWAP) across transition windows +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +#### Market Status Unknown/Unavailable (`marketStatus = 0`) + +The system may return `marketStatus = 0` (Unknown). **If your implementation relies on automated feed switching based on market status, you must account for this scenario.** + +Market status is sourced from several independent providers configured as primary/fallback. While resilient, multiple providers can fail simultaneously. + +##### Mitigation + +Consumers must treat `marketStatus = 0` (Unknown) as a valid state and define deterministic behaviors when it is returned. Potential actions include: + +- Pause or lock market activity +- Allow restricted trading within a bounded range (e.g., last-valid price ± threshold) +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +#### Closed (`marketStatus = 5`) + +Market status `5` indicates the market is closed, which includes weekends, public holidays, and unexpected market closures. During these periods, all three feeds will carry stale values. This reflects true underlying market inactivity rather than an outage or failure. + +##### Mitigation + +Consumers must treat `marketStatus = 5` (Closed) as a valid state and define deterministic behaviors when it is returned. Potential actions include: + +- Pause or lock market activity +- Allow restricted trading within a bounded range (e.g., last-valid price ± threshold) +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +#### Stale Data Detection + +Markets may stop updating due to exchange outages, circuit breakers, trading halts, or corporate actions. The `marketStatus` field will continue reflecting the status that it normally would. Use the `lastSeenTimestampNs` field (which reflects the timestamp of the last update for the `mid` price only) to detect staleness by comparing it against the current time. When this timestamp stops advancing, it indicates the underlying venue has stopped providing updates. + +Phase-specific feeds can introduce unique behavior due to venue-specific operational characteristics and market microstructure. The following are some examples of scenarios that may occur during session transitions or under specific market conditions: + +##### Regular Hours Session: Delayed Quote Availability at Market Open + +During the first 10–20 seconds after regular hours open (9:30am ET), bid/ask quotes may not yet be available from the regular hours venue. In those cases, the reported price may still reflect the previous regular hours close rather than live market data. + +Users should factor this transition period into their switching logic and consider alternative strategies during the first \~20 seconds of regular hours, such as: + +- Pause or lock market activity +- Continue using the pre-market (Extended Hours) stream until fresh regular hours quotes are available +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +##### Overnight Session: Stale Bid/Ask at Session Start + +During the early overnight session -- before the overnight venue begins publishing data -- the feed may display the last bid/ask prices and volumes from the previous regular session. This occurs because no new quotes are available yet from the overnight venue. + +Once the overnight venue starts publishing its own quotes, the data will update to reflect current overnight market conditions. This behavior is normal market microstructure, not a data quality issue. It reflects the actual state of the market during the transition period when overnight liquidity has not yet begun. + +Users relying on bid/ask data during early overnight hours should be aware of this carryover behavior and implement appropriate safeguards, such as checking `lastSeenTimestampNs` for staleness or widening risk parameters during overnight session transitions. + +##### Mitigation + +Consumers must have fallback logic in place when the data is stale. Potential actions include: + +- Pause or lock market activity +- Use last-valid price as reference +- Allow bounded-range trading based on last-valid price +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +### Stream Switching Example Logic + +The following examples demonstrate how to implement a continuous price feed by dynamically switching between phase-specific streams. These examples use tokenized asset prices as the fallback strategy for edge cases (stale data, Unknown market status, and Closed). Developers may choose alternative mitigation strategies based on their protocol's risk requirements. + +Developers interested in using tokenized assets can find the list of supported assets and schema in the [Tokenized Assets documentation](/data-streams/tokenized-asset-streams). Using tokenized assets carries its own risks, including liquidity limitations and price deviations from spot markets. Evaluate these factors carefully before integrating tokenized prices into your protocol. + +<Aside type="note" title="Note"> + Tokenized Assets are often Total Return Trackers (TRT). If used, the price should be normalized back to a non-TRT + price: `Spot_RWA_Price = Tokenized_RWA_Price / TRT_Multiplier` +</Aside> + +#### Decision Flow + +To build a continuous price feed, follow this general decision flow. This is a simplified outline that leverages tokenized asset prices as fallback; your implementation must account for all risks outlined above and in the [Risks](#risks) section below. + +1. **Fetch and decode** the Regular Hours stream report to get `marketStatus` and `lastSeenTimestampNs` + +2. **Check staleness first:** + - **If data is stale** (timestamp older than your threshold) → **[Use Tokenized Asset stream](/data-streams/tokenized-asset-streams)** or apply custom risk mitigation + - **If data is fresh** → Continue to step 3 + +3. **Route based on market status:** + - **`marketStatus = 0`** (Unknown) → **Use Tokenized Asset stream** or apply custom risk mitigation + - **`marketStatus = 1`** (Pre-market) → **Use Extended Hours stream** + - **`marketStatus = 2`** (Regular) → **Use Regular Hours stream** + - **`marketStatus = 3`** (Post-market) → **Use Extended Hours stream** + - **`marketStatus = 4`** (Overnight) → **Use Overnight Hours stream** + - **`marketStatus = 5`** (Closed) → **Use Tokenized Asset stream** or apply custom risk mitigation + +4. **Apply additional safeguards** as needed for your protocol (e.g., price jump checks, circuit breakers, holiday calendars, bounded trading ranges) + +5. **Return the `mid` price** from the selected stream + +<Aside type="caution" title="Important"> + This is a simplified decision flow. Your implementation must account for all risks outlined in the [Risks](#risks) + section below, including price jumps at transition boundaries, corporate actions, public holidays, and + protocol-specific edge cases. Each protocol has unique risk requirements—design your switching logic accordingly. +</Aside> + +#### Example Implementation Logic + +This example demonstrates switching logic with tokenized asset prices as fallback. View examples in different SDK languages. + +Please note that these code snippets are illustrative and may require adaptation to fit your specific environment, SDK versions, and error handling practices. Refer to the guide to [fetch](/data-streams/tutorials/go-sdk-fetch) and [stream](/data-streams/tutorials/go-sdk-stream) decoded reports in your chosen SDK. + + +<Aside type="caution" title="Disclaimer"> + This guide represents an example of using a Chainlink product or service and is provided to help you understand how to + interact with Chainlink's systems and services so that you can integrate them into your own. This template is provided + "AS IS" and "AS AVAILABLE" without warranties of any kind, has not been audited, and may be missing key checks or + error handling to make the usage of the product more clear. Do not use the code in this example in a production + environment without completing your own audits and application of best practices. Neither Chainlink Labs, the + Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs that are generated due to + errors in code. +</Aside> + +## Risks + +While 24/5 streams provide extended market coverage, they introduce specific risks related to liquidity, volatility, and data sourcing. Users must understand these factors and implement appropriate safeguards. + +In the following sections, we outline key risks and recommended mitigation strategies. + +### Single Provider for Extended & Overnight Data + +Extended and overnight session price feeds are currently sourced from a single data provider, making these sessions less reliable than the regular hours price feed which is multi-sourced. + +If the provider experiences downtime, technical failures, or connectivity disruption, the feed may flatline or report highly inaccurate figures, preventing users from reacting to real price movements. Such issues may lead to mispricing, failed liquidations, and potential bad debt accumulation. + +##### Mitigation + +The feed includes a staleness indicator, allowing consumers to detect when data stops updating. Users are strongly recommended to implement fallback logic within their protocol risk framework, which may include: + +- Pause or lock market activity +- Restrict to narrow price bands +- Temporarily switch to the tokenized price feed (understanding that it also carries liquidity limitations) + +### Structural Illiquidity and Volatility in Extended & Overnight Hours + +Pre-market and post-market sessions are typically thinly traded, with fragmented liquidity and higher spreads, leading to stale ticks, price gaps, and elevated volatility. These conditions are inherent to the market, not to the feed, and will be visible in the published data. + +##### Mitigation + +Users should evaluate whether the full 24/5 price coverage is appropriate for their use case. Consider the following: + +- Configure risk thresholds, circuit breakers, or mode switching aligned with your risk appetite +- Validate these configurations during integration and simulation, not post-deployment + +### Corporate Actions + +Traditional equities are subject to corporate actions which can dramatically change the price of an asset overnight, especially in the case of stock splits and reverse stock splits. These actions are usually announced outside regular trading hours and can cause substantial price movements when markets reopen. + +Additionally, the overnight session data provider may disable trading for individual symbols during pending corporate actions such as dividends, splits, or mergers. When this occurs, there will be no overnight session data available for that specific symbol, and this closure will not be reflected in the `marketStatus` field. The overnight feed may continue to display stale data from the previous session, or the data may flatline, making it critical to monitor `lastSeenTimestampNs` for staleness detection. + +##### Mitigation + +Consumers should: + +- Actively monitor corporate action announcements +- Adjust pricing logic, risk parameters, and open positions accordingly +- Consider pausing markets during corporate action windows to prevent unfair liquidations +- Implement staleness checks on `lastSeenTimestampNs` to detect when overnight session data stops updating due to symbol-specific trading halts + +### Trading Halts Are Not Explicitly Flagged + +Trading halts can occur for various reasons including regulatory actions, pending news announcements, volatility circuit breakers, or operational issues. When the underlying market is halted, this will not be reflected in the `marketStatus` field. + +Automated switching logic that relies only on `marketStatus` or staleness signals can incorrectly interpret halt inactivity as an outage or unexpected feed degradation, leading to unnecessary fallbacks, paused markets, or erroneous risk decisions. + +##### Mitigation + +Consumers must: + +- Monitor exchange halt notifications and adjust protocol behavior accordingly +- Implement appropriate safeguards when trading halts are detected to prevent unfair liquidations or trades at stale prices + +For detailed market hours and trading schedules, see the [Market Hours](/data-streams/market-hours) documentation. + +## Available Streams + +The table below shows all available 24/5 US Equities streams. Use the **Time segment** filter to view streams for specific trading sessions. + +--- + +# Handling Market Events (v11) +Source: https://docs.chain.link/data-streams/rwa-streams/handling-market-events-v11 + +<MarketEventsTabs /> + +<Aside type="note" title="Market Status Values"> + The `marketStatus` field values vary depending on the stream's supported hours. Refer to the [RWA Advanced (v11) + schema documentation](/data-streams/reference/report-schema-v11#market-status-values) to understand which values apply + to your specific stream. This guide uses generic "Open" and "Closed" terminology that applies across all v11 streams. +</Aside> + +Apply these best practices when integrating or operating markets that use tokenized real-world assets during standard market hours. Developers and operators are responsible for assessing market integrity, implementing mitigations, and managing application-level risks — see the [Developer Responsibilities](/data-streams/developer-responsibilities) guidance for details. + +## Market Hours + +Markets for Real-World Assets (RWA) operate during specific hours and are subject to various market conditions that can create risks for applications. The following sections outline common market issues and how to mitigate them. + +<Aside type="note" title="Market Hours Overview"> + For detailed market hours and trading schedules, see the <a href="/data-streams/market-hours">Market Hours</a> page. +</Aside> + +### Market gaps + +Market gaps occur when there are interruptions in trading or price discovery, leading to periods where the last available price may not reflect current market conditions. These gaps can create risks, particularly around market opens, closures, and unexpected disruptions. + +#### Market close + +The following guidance applies to streams during non-trading hours. Check your stream's specific `marketStatus` values in the [schema documentation](/data-streams/reference/report-schema-v11#market-status-values). + +Around market close, large price jumps may occur due to after-hours news. This can create a large pricing gap between the close of the last session and the open of the new session. Such a price jump can cause issues for protocols by triggering sudden liquidations. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| <ul><li>`midPrice`: Closing price is repeated until market open.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Keep markets closed while `marketStatus` indicates closed to prevent users trading at unfair prices.<br /><br /> Leverage available should be set in line with the asset average volatility to avoid bad debt if a user's collateral is insufficient to cover the losses. | + +#### Price formation at open/close + +Certain assets (e.g., FX open on Sunday afternoon) experience gradual price discovery due to fragmented liquidity and delayed trading activity. + +Integrating protocols should avoid opening their market with the last close price. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a bid/ask becomes available or a transaction occurs.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Wait until `lastUpdateTimestamp` is current before opening the market so traders don't execute on stale quotes. | + +#### Sudden failures + +Unexpected system outages, order execution failures, or data feed disruptions can occur in traditional data brokers and trading systems. + +The price will be flat during that period, meaning if an integrating protocol lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus` indicates open but `lastUpdateTimestamp` is stale. | + +#### Trading halts + +Stocks can be halted due to extreme volatility (e.g., limit up/down rules) or regulatory actions. + +The price will be flat during that period, meaning if an integrating protocol lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus` indicates open but `lastUpdateTimestamp` is stale. | + +*** + +## Volatility & low liquidity + +During periods of high volatility or low liquidity, price movements can become unpredictable and exaggerated. These conditions can increase the risk of sudden liquidations and bad debt accumulation, requiring careful risk management strategies. + +### Algorithmic & HFT activity + +Rapid-fire trading by algos can create unpredictable price movements. + +High volatility can lead to liquidation and potential bad debt accumulation. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Low liquidity at open/close + +Reduced market depth at trading session transitions can lead to higher volatility and spreads. + +High volatility can lead to liquidation and potential bad debt accumulation. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +*** + +## Corporate actions + +Corporate actions are events initiated by publicly traded companies that can significantly impact stock prices and trading behavior. These actions are usually announced outside regular trading hours and can cause substantial price movements when markets reopen. Users should monitor these events closely as they can lead to sudden price adjustments that may trigger unexpected liquidations or require position modifications. + +### Bankruptcy & delisting + +Bankruptcy can lead to delisting or complete loss of equity value. + +Delisting will zero out prices for the asset. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------ | +| <ul><li>`midPrice`: Closing price is repeated until a new price is available.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Closing timestamp of the last session.</li></ul> | Monitor delisting news during market closed periods and close markets permanently once confirmed. | + +### Spin-offs + +When a company spins off a business unit into a separate publicly traded entity, the parent company's stock may adjust accordingly, while the spun-off company's shares begin trading independently. + +Positions may need to be manually adjusted if the integrating protocol doesn't support tracking the new entity. + +| Data Stream behavior | User guidance | +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the first post-spin trade.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements during market closed periods.<br /><br />Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br /><br />If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | + +### Stock splits & reverse splits + +<Aside type="note" title="Tokenized Stocks Guidance"> + Tokenized stocks such as [Backed xStock](/data-streams/reference/report-schema-v10) handle stock splits differently + using activation dates and staged multipliers to maintain price continuity. [Learn more about advanced stock split + handling](/data-streams/tokenized-asset-streams/handling-stock-splits). +</Aside> + +A stock split increases the number of shares while reducing the price per share (e.g., 2-for-1 split), often making shares more accessible to investors. A reverse split does the opposite, consolidating shares to increase the price per share. + +A 2-for-1 split would reduce the price by 50% from the previous trading session, any leveraged user could get liquidated. + +| Data Stream behavior | User guidance | +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the split-adjusted price prints.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements during market closed periods.<br /><br />Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br /><br />If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | + +### Mergers & acquisitions (M\&A) + +If a company is being acquired, its stock price may rise to reflect the acquisition premium. The acquiring company's stock might fluctuate based on investor sentiment regarding the deal's financial and strategic impact. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Share buybacks & stock issuance + +Reduced share supply from a buyback can drive stock prices higher, while an increase in share supply can lead to price dilution. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Dividends + +A company's stock price typically adjusts to reflect dividend payments. For example, when a company declares a 10% dividend, its stock price often drops by a similar amount on the ex-dividend date, as new buyers are no longer entitled to that dividend. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the ex-date trade prints.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +--- + +# Handling Market Events +Source: https://docs.chain.link/data-streams/rwa-streams/handling-market-events + +<MarketEventsTabs /> + +Apply these best practices when integrating or operating markets that use tokenized real-world assets. Developers and operators are responsible for assessing market integrity, implementing mitigations, and managing application-level risks — see the [Developer Responsibilities](/data-streams/developer-responsibilities) guidance for details. + +## Market Hours + +Markets for Real-World Assets (RWA) operate during specific hours and are subject to various market conditions that can create risks for applications. The following sections outline common market issues and how to mitigate them. + +<Aside type="note" title="Market Hours Overview"> + For detailed market hours and trading schedules, see the <a href="/data-streams/market-hours">Market Hours</a> page. +</Aside> + +### Market gaps + +Market gaps occur when there are interruptions in trading or price discovery, leading to periods where the last available price may not reflect current market conditions. These gaps can create risks, particularly around market opens, closures, and unexpected disruptions. + +#### Market close + +Large price jumps between trading sessions due to after-hours news. + +A large price jump at market open could cause sudden liquidations, potentially leaving an integrating protocol with bad debt if a trader's collateral is insufficient to cover the losses. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until market open.</li><li>`marketStatus`: 1 = Market Closed.</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Keep markets closed while `marketStatus = 1` to prevent users trading at unfair prices.<br /><br /> Leverage available should be set in line with the asset average volatility to avoid bad debt if a trader's collateral is insufficient to cover the losses. | + +#### Price formation at open/close + +Certain assets (e.g., FX open on Sunday afternoon) experience gradual price discovery due to fragmented liquidity and delayed trading activity. + +Integrating protocols should avoid opening their market with the last close price. + +| Data Stream behavior | User guidance | +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a bid/ask becomes available or a transaction occurs.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Wait until `lastUpdateTimestamp` is current before opening the market so traders don't execute on stale quotes. | + +#### Sudden failures + +Unexpected system outages, order execution failures, or data feed disruptions can occur in traditional data brokers and trading systems. + +The price will be flat during that period, meaning if an integrating protocol lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. + +| Data Stream behavior | User guidance | +| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus = 2` but `lastUpdateTimestamp` is stale. | + +#### Trading halts + +Stocks can be halted due to extreme volatility (e.g., limit up/down rules) or regulatory actions. + +The price will be flat during that period, meaning if an integrating protocol lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. + +| Data Stream behavior | User guidance | +| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus = 2` but `lastUpdateTimestamp` is stale. | + +*** + +## Volatility & low liquidity + +During periods of high volatility or low liquidity, price movements can become unpredictable and exaggerated. These conditions can increase the risk of sudden liquidations and bad debt accumulation, requiring careful risk management strategies. + +### Algorithmic & HFT activity + +Rapid-fire trading by algos can create unpredictable price movements. + +High volatility can lead to liquidation and potential bad debt accumulation. + +| Data Stream behavior | User guidance | +| :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Low liquidity at open/close + +Reduced market depth at trading session transitions can lead to higher volatility and spreads. + +High volatility can lead to liquidation and potential bad debt accumulation. + +| Data Stream behavior | User guidance | +| :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +*** + +## Corporate actions + +Corporate actions are events initiated by publicly traded companies that can significantly impact stock prices and trading behavior. These actions are usually announced outside regular trading hours and can cause substantial price movements when markets reopen. Users should monitor these events closely as they can lead to sudden price adjustments that may trigger unexpected liquidations or require position modifications. + +### Bankruptcy & delisting + +Bankruptcy can lead to delisting or complete loss of equity value. + +Delisting will zero out prices for the asset. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price is available.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Closing timestamp of the last session.</li></ul> | Monitor delisting news during `marketStatus` = `1` and close markets permanently once confirmed. | + +### Spin-offs + +When a company spins off a business unit into a separate publicly traded entity, the parent company's stock may adjust accordingly, while the spun-off company's shares begin trading independently. + +Positions may need to be manually adjusted if the integrating protocol doesn't support tracking the new entity. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the first post-spin trade.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements while `marketStatus = 1`.<br /><br />Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br /><br />If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | + +### Stock splits & reverse splits + +<Aside type="note" title="Tokenized Stocks Guidance"> + Tokenized stocks such as [Backed xStock](/data-streams/reference/report-schema-v10) handle stock splits differently + using activation dates and staged multipliers to maintain price continuity. [Learn more about advanced stock split + handling](/data-streams/tokenized-asset-streams/handling-stock-splits). +</Aside> + +A stock split increases the number of shares while reducing the price per share (e.g., 2-for-1 split), often making shares more accessible to investors. A reverse split does the opposite, consolidating shares to increase the price per share. + +A 2-for-1 split would reduce the price by 50% from the previous trading session, any leveraged user could get liquidated. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the split-adjusted price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements while `marketStatus = 1`.<br /><br />Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br /><br />If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | + +### Mergers & acquisitions (M\&A) + +If a company is being acquired, its stock price may rise to reflect the acquisition premium. The acquiring company's stock might fluctuate based on investor sentiment regarding the deal's financial and strategic impact. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Share buybacks & stock issuance + +Reduced share supply from a buyback can drive stock prices higher, while an increase in share supply can lead to price dilution. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Dividends + +A company's stock price typically adjusts to reflect dividend payments. For example, when a company declares a 10% dividend, its stock price often drops by a similar amount on the ex-dividend date, as new buyers are no longer entitled to that dividend. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the ex-date trade prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +--- + +# Real World Asset (RWA) Data Streams +Source: https://docs.chain.link/data-streams/rwa-streams + +<FeedPage dataFeedType="streamsRwa" initialNetwork="arbitrum" allowNetworkTableExpansion={true} defaultNetworkTableExpanded={false} /> + +--- + +# SmartData Streams +Source: https://docs.chain.link/data-streams/smartdata-streams + +<FeedPage dataFeedType="streamsNav" initialNetwork="arbitrum" allowNetworkTableExpansion={true} defaultNetworkTableExpanded={false} /> + +--- + +# Streams Trade Implementation +Source: https://docs.chain.link/data-streams/streams-trade + +The Streams Trade implementation combines Chainlink Data Streams with [Chainlink Automation](/chainlink-automation) to enable automated trade execution. This implementation allows decentralized applications to automate trade execution, mitigate frontrunning, and limit bias or adverse incentives in executing non-user-triggered orders. + +Read more about the [Streams Trade Architecture](/data-streams/architecture#streams-trade-architecture) and an [example trading flow](/data-streams/architecture#example-trading-flow-using-streams-trade). + +## Getting Started + +To implement Streams Trade in your application: + +1. First, ensure Streams Trade is available on your desired network by checking the [Supported Networks](/data-streams/supported-networks#streams-trade-implementation-onchain-lookup) page. +2. Review the [Architecture Documentation](/data-streams/architecture#streams-trade-architecture) to understand the system components. +3. See an [Example Trading Flow](/data-streams/architecture#example-trading-flow-using-streams-trade) to understand how trades are executed. +4. Follow our [Getting Started Guide](/data-streams/getting-started) to set up your first integration. + +## Common Use Cases + +Streams Trade is particularly well-suited for: + +- **Perpetual Futures Protocols**: Enable high-performance onchain perpetual futures that can compete with centralized exchanges +- **Automated Market Making**: Implement sophisticated market making strategies with real-time price updates +- **Options Protocols**: Enable precise and timely settlement of options contracts +- **Prediction Markets**: Allow quick responses to real-time events with accurate settlement data + +--- # Interfaces Source: https://docs.chain.link/data-streams/streams-trade/interfaces @@ -5461,6 +6074,226 @@ Data Streams require several interfaces in order to retrieve and verify reports. In the current code example for using Data Streams with Automation, these interfaces are specified in the example itself. Imports for these interfaces will be available in the future. +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ILogAutomation, Log} from "@chainlink/contracts/src/v0.8/automation/interfaces/ILogAutomation.sol"; +import { + StreamsLookupCompatibleInterface +} from "@chainlink/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol"; +import {Common} from "@chainlink/contracts/src/v0.8/llo-feeds/libraries/Common.sol"; + +import {IRewardManager} from "@chainlink/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IRewardManager.sol"; +import {IVerifierFeeManager} from "@chainlink/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierFeeManager.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE FOR DEMONSTRATION PURPOSES. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +// Custom interfaces for IVerifierProxy and IFeeManager +interface IVerifierProxy { + /** + * @notice Verifies that the data encoded has been signed. + * correctly by routing to the correct verifier, and bills the user if applicable. + * @param payload The encoded data to be verified, including the signed + * report. + * @param parameterPayload Fee metadata for billing. For the current implementation this is just the abi-encoded fee + * token ERC-20 address. + * @return verifierResponse The encoded report from the verifier. + */ + function verify( + bytes calldata payload, + bytes calldata parameterPayload + ) external payable returns (bytes memory verifierResponse); + + function s_feeManager() external view returns (IVerifierFeeManager); +} + +interface IFeeManager { + /** + * @notice Calculates the fee and reward associated with verifying a report, including discounts for subscribers. + * This function assesses the fee and reward for report verification, applying a discount for recognized subscriber + * addresses. + * @param subscriber The address attempting to verify the report. A discount is applied if this address + * is recognized as a subscriber. + * @param unverifiedReport The report data awaiting verification. The content of this report is used to + * determine the base fee and reward, before considering subscriber discounts. + * @param quoteAddress The payment token address used for quoting fees and rewards. + * @return fee The fee assessed for verifying the report, with subscriber discounts applied where applicable. + * @return reward The reward allocated to the caller for successfully verifying the report. + * @return totalDiscount The total discount amount deducted from the fee for subscribers + */ + function getFeeAndReward( + address subscriber, + bytes memory unverifiedReport, + address quoteAddress + ) external returns (Common.Asset memory, Common.Asset memory, uint256); + + function i_linkAddress() external view returns (address); + + function i_nativeAddress() external view returns (address); + + function i_rewardManager() external view returns (address); +} + +contract StreamsUpkeep is ILogAutomation, StreamsLookupCompatibleInterface { + error InvalidReportVersion(uint16 version); // Thrown when an unsupported report version is provided to verifyReport. + + /** + * @dev Represents a data report from a Data Streams stream for v3 schema (used for crypto and DEX State Price + * streams). + * The `price`, `bid`, and `ask` values are carried to either 8 or 18 decimal places, depending on the stream. + * `bid`, and `ask` values are not available for DEX State Price streams. + * For more information, see https://docs.chain.link/data-streams/crypto-streams and + * https://docs.chain.link/data-streams/reference/report-schema + */ + struct ReportV3 { + bytes32 feedId; // The stream ID the report has data for. + uint32 validFromTimestamp; // Earliest timestamp for which price is applicable. + uint32 observationsTimestamp; // Latest timestamp for which price is applicable. + uint192 nativeFee; // Base cost to validate a transaction using the report, denominated in the chain’s native + // token (e.g., WETH/ETH). + uint192 linkFee; // Base cost to validate a transaction using the report, denominated in LINK. + uint32 expiresAt; // Latest timestamp where the report can be verified onchain. + int192 price; // DON consensus median price (8 or 18 decimals). + int192 bid; // Simulated price impact of a buy order up to the X% depth of liquidity utilisation (8 or 18 decimals). + // Note: not available for DEX State Price streams. + int192 ask; // Simulated price impact of a sell order up to the X% depth of liquidity utilisation (8 or 18 + // decimals). Note: not available for DEX State Price streams. + } + + /** + * @dev Represents a data report from a Data Streams stream for v4 schema (RWA streams). + * The `price` value is carried to either 8 or 18 decimal places, depending on the stream. + * The `marketStatus` indicates whether the market is currently open. Possible values: `0` (`Unknown`), `1` + * (`Closed`), `2` (`Open`). + * For more information, see https://docs.chain.link/data-streams/rwa-streams and + * https://docs.chain.link/data-streams/reference/report-schema-v4 + */ + struct ReportV4 { + bytes32 feedId; // The stream ID the report has data for. + uint32 validFromTimestamp; // Earliest timestamp for which price is applicable. + uint32 observationsTimestamp; // Latest timestamp for which price is applicable. + uint192 nativeFee; // Base cost to validate a transaction using the report, denominated in the chain’s native + // token (e.g., WETH/ETH). + uint192 linkFee; // Base cost to validate a transaction using the report, denominated in LINK. + uint32 expiresAt; // Latest timestamp where the report can be verified onchain. + int192 price; // DON consensus median benchmark price (8 or 18 decimals). + uint32 marketStatus; // The DON's consensus on whether the market is currently open. + } + + struct Quote { + address quoteAddress; + } + + IVerifierProxy public verifier; + + address public FEE_ADDRESS; + string public constant DATASTREAMS_FEEDLABEL = "feedIDs"; + string public constant DATASTREAMS_QUERYLABEL = "timestamp"; + int192 public lastDecodedPrice; + + // This example reads the ID for the ETH/USD report. + // Find a complete list of IDs at https://docs.chain.link/data-streams/crypto-streams. + string[] public feedIds = ["0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782"]; + + constructor( + address _verifier + ) { + verifier = IVerifierProxy(_verifier); + } + + // This function uses revert to convey call information. + // See https://eips.ethereum.org/EIPS/eip-3668#rationale for details. + function checkLog( + Log calldata log, + bytes memory + ) external returns (bool upkeepNeeded, bytes memory performData) { + revert StreamsLookup(DATASTREAMS_FEEDLABEL, feedIds, DATASTREAMS_QUERYLABEL, log.timestamp, ""); + } + + /** + * @notice this is a new, optional function in streams lookup. It is meant to surface streams lookup errors. + * @return upkeepNeeded boolean to indicate whether the keeper should call performUpkeep or not. + * @return performData bytes that the keeper should call performUpkeep with, if + * upkeep is needed. If you would like to encode data to decode later, try `abi.encode`. + */ + function checkErrorHandler( + uint256, /*errCode*/ + bytes memory /*extraData*/ + ) external pure returns (bool upkeepNeeded, bytes memory performData) { + return (true, "0"); + // Hardcoded to always perform upkeep. + // Read the StreamsLookup error handler guide for more information. + // https://docs.chain.link/chainlink-automation/guides/streams-lookup-error-handler + } + + // The Data Streams report bytes is passed here. + // extraData is context data from stream lookup process. + // Your contract may include logic to further process this data. + // This method is intended only to be simulated offchain by Automation. + // The data returned will then be passed by Automation into performUpkeep + function checkCallback( + bytes[] calldata values, + bytes calldata extraData + ) external pure returns (bool, bytes memory) { + return (true, abi.encode(values, extraData)); + } + + // function will be performed onchain + function performUpkeep( + bytes calldata performData + ) external { + // Decode the performData bytes passed in by CL Automation. + // This contains the data returned by your implementation in checkCallback(). + (bytes[] memory signedReports, bytes memory extraData) = abi.decode(performData, (bytes[], bytes)); + + bytes memory unverifiedReport = signedReports[0]; + + (, /* bytes32[3] reportContextData */ bytes memory reportData) = abi.decode(unverifiedReport, (bytes32[3], bytes)); + + // Extract report version from reportData + uint16 reportVersion = (uint16(uint8(reportData[0])) << 8) | uint16(uint8(reportData[1])); + + // Validate report version + if (reportVersion != 3 && reportVersion != 4) { + revert InvalidReportVersion(uint8(reportVersion)); + } + + // Report verification fees + IFeeManager feeManager = IFeeManager(address(verifier.s_feeManager())); + IRewardManager rewardManager = IRewardManager(address(feeManager.i_rewardManager())); + + address feeTokenAddress = feeManager.i_linkAddress(); + (Common.Asset memory fee,,) = feeManager.getFeeAndReward(address(this), reportData, feeTokenAddress); + + // Approve rewardManager to spend this contract's balance in fees + IERC20(feeTokenAddress).approve(address(rewardManager), fee.amount); + + // Verify the report + bytes memory verifiedReportData = verifier.verify(unverifiedReport, abi.encode(feeTokenAddress)); + + // Decode verified report data into the appropriate Report struct based on reportVersion + if (reportVersion == 3) { + // v3 report schema + ReportV3 memory verifiedReport = abi.decode(verifiedReportData, (ReportV3)); + + // Store the price from the report + lastDecodedPrice = verifiedReport.price; + } else if (reportVersion == 4) { + // v4 report schema + ReportV4 memory verifiedReport = abi.decode(verifiedReportData, (ReportV4)); + + // Store the price from the report + lastDecodedPrice = verifiedReport.price; + } + } +} +``` + --- # Supported Networks @@ -5474,7 +6307,7 @@ The table below lists all networks supported by Data Streams, each with verifier ## Streams Trade implementation (Onchain Lookup) -[Streams Trade](streams-trade), the alternative implementation, allows smart contracts to access Data Streams onchain using the [`StreamsLookup`](/data-streams/getting-started) capability integrated with [Chainlink Automation](/chainlink-automation). +[Streams Trade](/data-streams/streams-trade), the alternative implementation, allows smart contracts to access Data Streams onchain using the [`StreamsLookup`](/data-streams/getting-started) capability integrated with [Chainlink Automation](/chainlink-automation). Streams Trade is currently available on the following networks: @@ -5488,6 +6321,118 @@ Streams Trade is currently available on the following networks: --- +# Handling Stock Splits +Source: https://docs.chain.link/data-streams/tokenized-asset-streams/handling-stock-splits + +Corporate actions, such as stock splits and reverse splits, require precise handling for tokenized assets to ensure price continuity and avoid disruptions. These events alter per‑share pricing while leaving the underlying economic exposure unchanged. They can produce abrupt per‑share price moves and must be handled carefully to avoid incorrect onchain price computations and unexpected liquidations. + +In the [v10 report schema](/data-streams/reference/report-schema-v10), continuity is preserved by staging a multiplier change with a scheduled `activationDateTime` so the Theoretical Price (`price` \* `currentMultiplier`) remains continuous. Split ratios are typically known in advance, but activation may occur while markets are closed, so some external price sources may not reflect the split until trading resumes. + +<Aside type="note" title="Note"> + This guidance is designed for multiplier handling in the [v10 report + schema](/data-streams/reference/report-schema-v10) and what integrators should expect around activation windows and + protocol behavior. Similar principles may apply to future schemas that host tokenized stocks, but applicability and + exact behavior will depend on each schema's design and are not guaranteed. +</Aside> + +## Guiding principle + +Follow these principles when handling multiplier changes during corporate actions: + +1. The protocol considers the Theoretical Price as `price` \* `currentMultiplier`. +2. Ahead of the event, `newMultiplier` and `activationDateTime` are staged. +3. At `activationDateTime` (Unix), `currentMultiplier` becomes `newMultiplier`. + - The underlying `price` from traditional markets should start reflecting the split the next time trading opens, so at the next `price` update, the Theoretical Price should remain continuous. + +## Example (10:1 split, AAPL) + +The following hypothetical scenario demonstrates how a 10:1 AAPL stock split is handled through the staged multiplier system, showing the progression from announcement through protocol reopening with proper price continuity maintained throughout. + +The following timeline outlines the key events and actions taken at each stage: + +- **T-2**: [Split announcement and multiplier staging](#announcement-t-2) +- **T-1**: [Protocol preparation and monitoring setup](#protocol-engagement-t-1) +- **T0**: [Multiplier activation (split effective date)](#activation-t0) +- **T+1**: [Market reopening with adjusted prices](#market-reopening-t1) +- **T+2**: [Protocol resumption after verification](#protocol-reopening-t2) + +### Announcement (T-2) + +A 10:1 AAPL stock split is announced. [The report](/data-streams/reference/report-schema-v10) updates to stage the split: + +- `newMultiplier` is set to 10x the value of `currentMultiplier`. +- `activationDateTime` is set to the Unix timestamp of the split. +- `currentMultiplier` is unaffected until activation. + +### Protocol engagement (T-1) + +At this stage, users are advised to monitor for changes in `activationDateTime` and inspect the upcoming change to prepare appropriate action, such as preparing the protocol for a pause around the `activationDateTime` in order to ensure appropriate handling of the stock split. + +### Activation (T0) + +When the provider applies the split, [the report](/data-streams/reference/report-schema-v10) updates: + +- `newMultiplier` remains the current value. +- `activationDateTime` is set to `0`. +- `currentMultiplier` is updated to the same value as `newMultiplier`. + +<Aside type="danger" title="Important"> + If activation occurs while the underlying market is closed, prices may still show the pre‑event last trade. Do not + compute the Theoretical Price during this pre-adjustment window. Monitor `marketStatus` and keep the protocol paused + until the first post‑event trade prints and the Theoretical Price is continuous. +</Aside> + +If activation occurs while the underlying market is closed, prices may still show the pre‑event last trade. Do not compute the Theoretical Price during this pre-adjustment window. Monitor `marketStatus` and keep the protocol paused until the first post‑event trade prints and the Theoretical Price is continuous. + +### Market reopening (T1) + +The stock split has taken effect. Generally, this occurs after the market closes or over the weekend, meaning `price` may not yet reflect the new economic value per share. Upon the market reopening, `price` should start reflecting the split-adjusted value. + +### Protocol reopening (T2) + +Users should pause markets before `activationDateTime` and keep them paused until: + +- The market has reopened (monitor `marketStatus`) +- `price` has updated in line with the split ratio (e.g., 10:1) +- You have confirmed that the Theoretical Price matches expectations + +After all the above checks have been confirmed, users can unpause their protocol and continue and resume normal operation. + +## Activation-time convention + +Each tokenized asset issuer sets its own activation time. For example, the xStocks default `activationDateTime` is 00:00 UTC on the effective date. Once `activationDateTime` is reached, `currentMultiplier` becomes `newMultiplier`. + +Because underlying venues may be closed at activation, some external price sources may not reflect the split immediately. If `activationDateTime` occurs while the underlying market is closed, the report’s `currentMultiplier` will become `newMultiplier`; however, `price` can remain at the pre-event level until the market reopens. During this post-activation, pre-adjustment interval (after the multiplier has changed but before the underlying `price` updates), the Theoretical Price can be incorrect. Use `marketStatus` to pause until `price` reflects the event. + +## Integrator risk & handling + +Computing `price` \* `currentMultiplier` when the price has not adjusted (e.g., market closed) can produce large errors. It is critical to ensure that the Theoretical Price is again reflective of actual market conditions before allowing live trading. + +Treat any multiplier change (splits, dividends, etc) and `activationDateTime` as a maintenance window; pause/guard the protocol, then verify post-activation conditions before resuming. + +<Aside type="caution" title="Integrator Responsibility"> + It is the integrator's responsibility to perform proper handling and risk management. Failure to follow these best + practices may result in significant financial losses. Ensure that all multiplier changes, activation windows, and + post-activation conditions are verified before resuming operations. +</Aside> + +For broader guidance around market hours and event handling, refer to the [Market Hours](/data-streams/market-hours) guidance. + +--- + +# Tokenized Asset Data Streams +Source: https://docs.chain.link/data-streams/tokenized-asset-streams + +<Aside type="danger" title="Weekend Usage Disclaimer"> + **The `price` field does not update during weekends** because the underlying real-world equity market is closed. + + However, the `tokenizedPrice` field continues to update as it reflects trading activity on centralized exchanges (CEXs). Weekend liquidity tends to be thin, so users should implement guardrails against unexpected volatility. + + Developers are solely responsible for monitoring and mitigating market integrity risks, as outlined in the [Developer Responsibilities](/data-streams/developer-responsibilities) documentation. +</Aside> + +--- + # Verify report data onchain (EVM) Source: https://docs.chain.link/data-streams/tutorials/evm-onchain-report-verification @@ -5515,6 +6460,228 @@ Deploy a `ClientReportsVerifier` contract on *Arbitrum Sepolia*. This contract i 1. [Open the ClientReportsVerifier.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/DataStreams/ClientReportsVerifier.sol) contract in Remix. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; + + import {Common} from "@chainlink/contracts/src/v0.8/llo-feeds/libraries/Common.sol"; + import {IVerifierFeeManager} from "@chainlink/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierFeeManager.sol"; + import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + + using SafeERC20 for IERC20; + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE FOR DEMONSTRATION PURPOSES. + * DO NOT USE THIS CODE IN PRODUCTION. + * + * This contract can verify Chainlink Data Streams reports onchain and pay + * the verification fee in LINK (when required). + * + * - If `VerifierProxy.s_feeManager()` returns a non-zero address, the network + * expects you to interact with that FeeManager for every verification call: + * quote fees, approve the RewardManager, then call `verify()`. + * + * - If `s_feeManager()` returns the zero address, no FeeManager contract has + * been deployed on that chain. In that case there is nothing to quote or pay + * onchain, so the contract skips the fee logic entirely. + * + * The `if (address(feeManager) != address(0))` check below chooses the + * correct path automatically, making the same bytecode usable on any chain. + */ + + // ──────────────────────────────────────────────────────────────────────────── + // Interfaces + // ──────────────────────────────────────────────────────────────────────────── + + interface IVerifierProxy { + /** + * @notice Route a report to the correct verifier and (optionally) bill fees. + * @param payload Full report payload (header + signed report). + * @param parameterPayload ABI-encoded fee metadata. + */ + function verify( + bytes calldata payload, + bytes calldata parameterPayload + ) external payable returns (bytes memory verifierResponse); + + function verifyBulk( + bytes[] calldata payloads, + bytes calldata parameterPayload + ) external payable returns (bytes[] memory verifiedReports); + + function s_feeManager() external view returns (IVerifierFeeManager); + } + + interface IFeeManager { + /** + * @return fee, reward, totalDiscount + */ + function getFeeAndReward( + address subscriber, + bytes memory unverifiedReport, + address quoteAddress + ) external returns (Common.Asset memory, Common.Asset memory, uint256); + + function i_linkAddress() external view returns (address); + + function i_nativeAddress() external view returns (address); + + function i_rewardManager() external view returns (address); + } + + // ──────────────────────────────────────────────────────────────────────────── + // Contract + // ──────────────────────────────────────────────────────────────────────────── + + /** + * @dev This contract implements functionality to verify Data Streams reports from + * the Data Streams API, with payment in LINK tokens. + */ + contract ClientReportsVerifier { + // ----------------- Errors ----------------- + error NothingToWithdraw(); + error NotOwner(address caller); + error InvalidReportVersion(uint16 version); + + // ----------------- Report schemas ----------------- + // More info: https://docs.chain.link/data-streams/reference/report-schema-v3 + /** + * @dev Data Streams report schema v3 (crypto streams). + * Prices, bids and asks use 8 or 18 decimals depending on the stream. + */ + struct ReportV3 { + bytes32 feedId; + uint32 validFromTimestamp; + uint32 observationsTimestamp; + uint192 nativeFee; + uint192 linkFee; + uint32 expiresAt; + int192 price; + int192 bid; + int192 ask; + } + + /** + * @dev Data Streams report schema v8 (RWA streams). + */ + struct ReportV8 { + bytes32 feedId; + uint32 validFromTimestamp; + uint32 observationsTimestamp; + uint192 nativeFee; + uint192 linkFee; + uint32 expiresAt; + uint64 lastUpdateTimestamp; + int192 midPrice; + uint32 marketStatus; + } + + // ----------------- Storage ----------------- + IVerifierProxy public immutable i_verifierProxy; + address private immutable i_owner; + + int192 public lastDecodedPrice; + + // ----------------- Events ----------------- + event DecodedPrice(int192 price); + + // ----------------- Constructor / modifier ----------------- + /** + * @param _verifierProxy Address of the VerifierProxy on the target network. + * Addresses: https://docs.chain.link/data-streams/crypto-streams + */ + constructor( + address _verifierProxy + ) { + i_owner = msg.sender; + i_verifierProxy = IVerifierProxy(_verifierProxy); + } + + modifier onlyOwner() { + if (msg.sender != i_owner) revert NotOwner(msg.sender); + _; + } + + // ----------------- Public API ----------------- + + /** + * @notice Verify a Data Streams report (schema v3 or v8). + * + * @dev Steps: + * 1. Decode the unverified report to get `reportData`. + * 2. Read the first two bytes → schema version (`0x0003` or `0x0008`). + * - Revert if the version is unsupported. + * 3. Fee handling: + * - Query `s_feeManager()` on the proxy. + * – Non-zero → quote the fee, approve the RewardManager, + * ABI-encode the fee token address for `verify()`. + * – Zero → no FeeManager; skip quoting/approval and pass `""`. + * 4. Call `VerifierProxy.verify()`. + * 5. Decode the verified report into the correct struct and emit the price. + * + * @param unverifiedReport Full payload returned by Streams Direct. + * @custom:reverts InvalidReportVersion when schema ≠ v3/v8. + */ + function verifyReport( + bytes memory unverifiedReport + ) external { + // ─── 1. & 2. Extract reportData and schema version ── + (, bytes memory reportData) = abi.decode(unverifiedReport, (bytes32[3], bytes)); + + uint16 reportVersion = (uint16(uint8(reportData[0])) << 8) | uint16(uint8(reportData[1])); + if (reportVersion != 3 && reportVersion != 8) { + revert InvalidReportVersion(reportVersion); + } + + // ─── 3. Fee handling ── + IFeeManager feeManager = IFeeManager(address(i_verifierProxy.s_feeManager())); + + bytes memory parameterPayload; + if (address(feeManager) != address(0)) { + // FeeManager exists — always quote & approve + address feeToken = feeManager.i_linkAddress(); + + (Common.Asset memory fee,,) = feeManager.getFeeAndReward(address(this), reportData, feeToken); + + IERC20(feeToken).approve(feeManager.i_rewardManager(), fee.amount); + parameterPayload = abi.encode(feeToken); + } else { + // No FeeManager deployed on this chain + parameterPayload = bytes(""); + } + + // ─── 4. Verify through the proxy ── + bytes memory verified = i_verifierProxy.verify(unverifiedReport, parameterPayload); + + // ─── 5. Decode & store price ── + if (reportVersion == 3) { + int192 price = abi.decode(verified, (ReportV3)).price; + lastDecodedPrice = price; + emit DecodedPrice(price); + } else { + int192 price = abi.decode(verified, (ReportV8)).midPrice; + lastDecodedPrice = price; + emit DecodedPrice(price); + } + } + + /** + * @notice Withdraw all balance of an ERC-20 token held by this contract. + * @param _beneficiary Address that receives the tokens. + * @param _token ERC-20 token address. + */ + function withdrawToken( + address _beneficiary, + address _token + ) external onlyOwner { + uint256 amount = IERC20(_token).balanceOf(address(this)); + if (amount == 0) revert NothingToWithdraw(); + IERC20(_token).safeTransfer(_beneficiary, amount); + } + } + ``` + 2. Select the `ClientReportsVerifier.sol` contract in the **Solidity Compiler** tab. 3. Compile the contract. @@ -5558,6 +6725,228 @@ For this tutorial on *Arbitrum Sepolia*, fees are required, so you need to fund The example code you deployed has all the interfaces and functions required to verify Data Streams reports onchain. +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Common} from "@chainlink/contracts/src/v0.8/llo-feeds/libraries/Common.sol"; +import {IVerifierFeeManager} from "@chainlink/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierFeeManager.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +using SafeERC20 for IERC20; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE FOR DEMONSTRATION PURPOSES. + * DO NOT USE THIS CODE IN PRODUCTION. + * + * This contract can verify Chainlink Data Streams reports onchain and pay + * the verification fee in LINK (when required). + * + * - If `VerifierProxy.s_feeManager()` returns a non-zero address, the network + * expects you to interact with that FeeManager for every verification call: + * quote fees, approve the RewardManager, then call `verify()`. + * + * - If `s_feeManager()` returns the zero address, no FeeManager contract has + * been deployed on that chain. In that case there is nothing to quote or pay + * onchain, so the contract skips the fee logic entirely. + * + * The `if (address(feeManager) != address(0))` check below chooses the + * correct path automatically, making the same bytecode usable on any chain. + */ + +// ──────────────────────────────────────────────────────────────────────────── +// Interfaces +// ──────────────────────────────────────────────────────────────────────────── + +interface IVerifierProxy { + /** + * @notice Route a report to the correct verifier and (optionally) bill fees. + * @param payload Full report payload (header + signed report). + * @param parameterPayload ABI-encoded fee metadata. + */ + function verify( + bytes calldata payload, + bytes calldata parameterPayload + ) external payable returns (bytes memory verifierResponse); + + function verifyBulk( + bytes[] calldata payloads, + bytes calldata parameterPayload + ) external payable returns (bytes[] memory verifiedReports); + + function s_feeManager() external view returns (IVerifierFeeManager); +} + +interface IFeeManager { + /** + * @return fee, reward, totalDiscount + */ + function getFeeAndReward( + address subscriber, + bytes memory unverifiedReport, + address quoteAddress + ) external returns (Common.Asset memory, Common.Asset memory, uint256); + + function i_linkAddress() external view returns (address); + + function i_nativeAddress() external view returns (address); + + function i_rewardManager() external view returns (address); +} + +// ──────────────────────────────────────────────────────────────────────────── +// Contract +// ──────────────────────────────────────────────────────────────────────────── + +/** + * @dev This contract implements functionality to verify Data Streams reports from + * the Data Streams API, with payment in LINK tokens. + */ +contract ClientReportsVerifier { + // ----------------- Errors ----------------- + error NothingToWithdraw(); + error NotOwner(address caller); + error InvalidReportVersion(uint16 version); + + // ----------------- Report schemas ----------------- + // More info: https://docs.chain.link/data-streams/reference/report-schema-v3 + /** + * @dev Data Streams report schema v3 (crypto streams). + * Prices, bids and asks use 8 or 18 decimals depending on the stream. + */ + struct ReportV3 { + bytes32 feedId; + uint32 validFromTimestamp; + uint32 observationsTimestamp; + uint192 nativeFee; + uint192 linkFee; + uint32 expiresAt; + int192 price; + int192 bid; + int192 ask; + } + + /** + * @dev Data Streams report schema v8 (RWA streams). + */ + struct ReportV8 { + bytes32 feedId; + uint32 validFromTimestamp; + uint32 observationsTimestamp; + uint192 nativeFee; + uint192 linkFee; + uint32 expiresAt; + uint64 lastUpdateTimestamp; + int192 midPrice; + uint32 marketStatus; + } + + // ----------------- Storage ----------------- + IVerifierProxy public immutable i_verifierProxy; + address private immutable i_owner; + + int192 public lastDecodedPrice; + + // ----------------- Events ----------------- + event DecodedPrice(int192 price); + + // ----------------- Constructor / modifier ----------------- + /** + * @param _verifierProxy Address of the VerifierProxy on the target network. + * Addresses: https://docs.chain.link/data-streams/crypto-streams + */ + constructor( + address _verifierProxy + ) { + i_owner = msg.sender; + i_verifierProxy = IVerifierProxy(_verifierProxy); + } + + modifier onlyOwner() { + if (msg.sender != i_owner) revert NotOwner(msg.sender); + _; + } + + // ----------------- Public API ----------------- + + /** + * @notice Verify a Data Streams report (schema v3 or v8). + * + * @dev Steps: + * 1. Decode the unverified report to get `reportData`. + * 2. Read the first two bytes → schema version (`0x0003` or `0x0008`). + * - Revert if the version is unsupported. + * 3. Fee handling: + * - Query `s_feeManager()` on the proxy. + * – Non-zero → quote the fee, approve the RewardManager, + * ABI-encode the fee token address for `verify()`. + * – Zero → no FeeManager; skip quoting/approval and pass `""`. + * 4. Call `VerifierProxy.verify()`. + * 5. Decode the verified report into the correct struct and emit the price. + * + * @param unverifiedReport Full payload returned by Streams Direct. + * @custom:reverts InvalidReportVersion when schema ≠ v3/v8. + */ + function verifyReport( + bytes memory unverifiedReport + ) external { + // ─── 1. & 2. Extract reportData and schema version ── + (, bytes memory reportData) = abi.decode(unverifiedReport, (bytes32[3], bytes)); + + uint16 reportVersion = (uint16(uint8(reportData[0])) << 8) | uint16(uint8(reportData[1])); + if (reportVersion != 3 && reportVersion != 8) { + revert InvalidReportVersion(reportVersion); + } + + // ─── 3. Fee handling ── + IFeeManager feeManager = IFeeManager(address(i_verifierProxy.s_feeManager())); + + bytes memory parameterPayload; + if (address(feeManager) != address(0)) { + // FeeManager exists — always quote & approve + address feeToken = feeManager.i_linkAddress(); + + (Common.Asset memory fee,,) = feeManager.getFeeAndReward(address(this), reportData, feeToken); + + IERC20(feeToken).approve(feeManager.i_rewardManager(), fee.amount); + parameterPayload = abi.encode(feeToken); + } else { + // No FeeManager deployed on this chain + parameterPayload = bytes(""); + } + + // ─── 4. Verify through the proxy ── + bytes memory verified = i_verifierProxy.verify(unverifiedReport, parameterPayload); + + // ─── 5. Decode & store price ── + if (reportVersion == 3) { + int192 price = abi.decode(verified, (ReportV3)).price; + lastDecodedPrice = price; + emit DecodedPrice(price); + } else { + int192 price = abi.decode(verified, (ReportV8)).midPrice; + lastDecodedPrice = price; + emit DecodedPrice(price); + } + } + + /** + * @notice Withdraw all balance of an ERC-20 token held by this contract. + * @param _beneficiary Address that receives the tokens. + * @param _token ERC-20 token address. + */ + function withdrawToken( + address _beneficiary, + address _token + ) external onlyOwner { + uint256 amount = IERC20(_token).balanceOf(address(this)); + if (amount == 0) revert NothingToWithdraw(); + IERC20(_token).safeTransfer(_beneficiary, amount); + } +} +``` + ### Initializing the contract When deploying the contract, you define the verifier proxy address for the stream you want to read from. You can find this address on the [Stream Addresses](/data-streams/crypto-streams) page. The verifier proxy address provides functions that are required for this example: @@ -5576,7 +6965,7 @@ The `verifyReport` function is the core function that handles onchain report ver - Schema version `0x0003` corresponds to the [Crypto Advanced (v3)](/data-streams/reference/report-schema-v3). - Schema version `0x0008` corresponds to the [RWA Standard (v8)](/data-streams/reference/report-schema-v8). - Schema version `0x0007` corresponds to the [Redemption Rates (v7)](/data-streams/reference/report-schema-v7). - - Schema version `0x0009` corresponds to the [NAV (v9)](/data-streams/reference/report-schema-v9). + - Schema version `0x0009` corresponds to the [SmartData (v9)](/data-streams/reference/report-schema-v9). - Schema version `0x000A` corresponds to the [Tokenized Asset (v10)](/data-streams/reference/report-schema-v10). - Schema version `0x000B` corresponds to the [RWA Advanced (v11)](/data-streams/reference/report-schema-v11). - If the report version is unsupported, the function reverts with an InvalidReportVersion error. @@ -5802,7 +7191,7 @@ You'll start with the set up of your Go project, installing the SDK and pasting See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. -5. Read from a [testnet crypto stream](/data-streams/crypto-streams?page=1\&testnetPage=1#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: +5. Read from a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: ```bash go run single-stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 @@ -5980,7 +7369,7 @@ You'll start with the set up of your Go project, installing the SDK and pasting export API_SECRET="<YOUR_API_SECRET>" ``` -4. Read from two [testnet crypto streams](/data-streams/crypto-streams?page=1\&testnetPage=1#testnet-crypto-streams). For this example, you will read from the ETH/USD and LINK/USD Data Streams crypto streams. Run your application: +4. Read from two [testnet crypto streams](/data-streams/crypto-streams#testnet-crypto-streams). For this example, you will read from the ETH/USD and LINK/USD Data Streams crypto streams. Run your application: ```bash go run multiple-streams.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265 @@ -6420,7 +7809,7 @@ First, you'll set up a basic Go project, installing the SDK and pasting example See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. -5. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams?page=1\&testnetPage=1#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: +5. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: Execute your application: @@ -6811,11 +8200,11 @@ You'll start with the set up of your Rust project, installing the SDK and pastin ).build()?; ``` - This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint [for subscribing to a streamed data report](rust-sdk-stream). In this example, both are set to the testnet URLs for Data Streams. + This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint [for subscribing to a streamed data report](/data-streams/tutorials/rust-sdk-stream). In this example, both are set to the testnet URLs for Data Streams. See the [Rust SDK Reference](/data-streams/reference/data-streams-api/rust-sdk#configuration-reference) page for more configuration options. -3. Read from a [testnet crypto stream](/data-streams/crypto-streams?page=1\&testnetPage=1#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: +3. Read from a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: ```bash cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 @@ -7178,11 +8567,11 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r ).build()?; ``` - This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint [for subscribing to a streamed data report](rust-sdk-stream). In this example, both are set to the testnet URLs for Data Streams. + This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint for subscribing to a streamed data report. In this example, both are set to the testnet URLs for Data Streams. See the [Rust SDK Reference](/data-streams/reference/data-streams-api/rust-sdk#configuration-reference) page for more configuration options. -3. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams?page=1\&testnetPage=1#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: +3. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: ```bash cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 @@ -8480,7 +9869,7 @@ You'll start with the set up of your TypeScript project, installing the SDK and The TypeScript SDK automatically detects the report version based on the provided feed ID. </Aside> -3. Read from a [testnet crypto stream](/data-streams/crypto-streams?page=1\&testnetPage=1#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: +3. Read from a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: ```bash npx tsx singleStream.ts 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 @@ -9013,7 +10402,7 @@ First, you'll set up a basic TypeScript project, installing the SDK and pasting accordingly. </Aside> -3. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams?page=1\&testnetPage=1#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: +3. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: ```bash npx tsx stream.ts 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 diff --git a/src/content/data-streams/market-hours.mdx b/src/content/data-streams/market-hours.mdx index 333387e2757..c9337770919 100644 --- a/src/content/data-streams/market-hours.mdx +++ b/src/content/data-streams/market-hours.mdx @@ -71,6 +71,23 @@ RWA markets operate during specific hours, with breaks for holidays and sometime | **Precious Metals (Spot)**<br/>(XAU, XAG) | **18:00 Sun** | **17:00 Fri** | 17:00–18:00 Mon-Thu | Jan 1, Good Fri, Dec 25 | | **Commodities** <br/> (WTI Synthetic Spot) | **18:00 Sun** | **17:00 Fri** | 17:00–18:00 Mon-Thu | [NYMEX holiday calendar](https://www.cmegroup.com/tools-information/holiday-calendar/) | +### US Equities 24/5 Trading Sessions + +For feeds using the [RWA Advanced (v11) schema](/data-streams/reference/report-schema-v11), US Equities are available across three distinct trading sessions, providing 24/5 coverage: + +| Session | Hours (ET) | `marketStatus` Value | Description | +| ------------------- | ------------------------------------- | ------------------------------------ | ---------------------------------------------- | +| **Regular Hours** | 9:30am–4:00pm Mon–Fri | `2` (Regular hours) | Primary trading session with highest liquidity | +| **Extended Hours** | 4:00am–9:30am & 4:00pm–8:00pm Mon–Fri | `1` (Pre-market) & `3` (Post-market) | Pre-market and post-market sessions | +| **Overnight Hours** | 8:00pm–4:00am Sun evening–Fri morning | `4` (Overnight) | Overnight session with limited liquidity | + +**Additional `marketStatus` values:** + +- `0` (Unknown) — Market status cannot be determined +- `5` (Weekend) — Weekend period: 8:00pm Fri–8:00pm Sun + +See the [24/5 US Equities User Guide](/data-streams/rwa-streams/24-5-us-equities-user-guide) for detailed information on building continuous price feeds and managing session transitions. + \* Times shown as **HH:MM ET**. \*\* Half-day trading may apply on the eve of certain U.S. holidays (e.g., Jul 3, Nov 28). Consult the linked exchange calendars for exact cut-off times. diff --git a/src/content/data-streams/reference/candlestick-api/index.mdx b/src/content/data-streams/reference/candlestick-api/index.mdx index 0149066cd4a..64478531221 100644 --- a/src/content/data-streams/reference/candlestick-api/index.mdx +++ b/src/content/data-streams/reference/candlestick-api/index.mdx @@ -82,9 +82,9 @@ curl -X POST \ **`/api/v1/symbol_info`** -| Type | Description | Parameter(s) | -| :------- | :------------------------------------------------------- | :----------------------------------------------------------------------------------------------- | -| HTTP GET | Gets a list of all supported symbols on the environment. | <ul><li>`group` (optional): Filter symbols by group. Currently only supports "crypto".</li></ul> | +| Type | Description | Parameter(s) | +| :------- | :------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------- | +| HTTP GET | Gets a list of all supported symbols on the environment. | <ul><li>`group` (optional): Filter symbols by group. See [`/groups`](#get-list-of-supported-groups) for available groups.</li></ul> | ##### Sample request @@ -121,26 +121,85 @@ curl -X GET \ | `401` | `Unauthorized - Authorization header is required \|\| Invalid authorization header format \|\| token signature is invalid: signature is invalid \|\| ...` | The authorization header was missing or invalid. | | `500` | `Error - Something went wrong` | An unexpected server error occurred. | +### Get list of supported groups + +##### Endpoint + +**`/api/v1/groups`** + +| Type | Description | Parameter(s) | +| :------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------- | +| HTTP GET | Gets a list of all supported symbol types on the environment. Any group name returned can be used as a filter in the `/symbol_info` endpoint. | None | + +##### Sample request + +```bash +curl -X GET \ + -H "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \ + https://priceapi.testnet-dataengine.chain.link/api/v1/groups +``` + +##### Response + +- **Status**: `200` + + ```json + { + "s": "ok", + "d": { + "groups": [{ "id": "crypto" }, { "id": "equities" }, { "id": "forex" }, { "id": "equity" }] + } + } + ``` + + | Field | Type | Description | + | :------- | :------- | :--------------------------------- | + | `s` | `string` | The status of the request. | + | `d` | `object` | The data returned by the API call. | + | `groups` | `array` | Array of supported groups. | + +##### Error Responses + +| Status Code | Error Message | Description | +| :---------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------- | +| `401` | `Unauthorized - Authorization header is required \|\| Invalid authorization header format \|\| token signature is invalid: signature is invalid \|\| ...` | The authorization header was missing or invalid. | +| `500` | `Error - Something went wrong` | An unexpected server error occurred. | + ### Get candlestick data (column format) ##### Endpoint **`/api/v1/history`** -| Type | Description | Parameter(s) | -| :------- | :-------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| HTTP GET | Gets candlestick data in column format. | <ul><li>`symbol`: The symbol to query.</li><li>`resolution`: Resolution of the data (required but not used, use "1m").</li><li>`from`: Unix timestamp of the leftmost required bar (inclusive).</li><li>`to`: Unix timestamp of the rightmost required bar (inclusive).</li></ul> | +| Type | Description | Parameter(s) | +| :------- | :-------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| HTTP GET | Gets candlestick data in column format. | <ul><li>`symbol`: The symbol to query.</li><li>`resolution`: Resolution of the data. E.g., "1m". Must match [supported resolutions](#supported-resolutions).</li><li>`from`: Unix timestamp of the leftmost required bar (inclusive).</li><li>`to`: Unix timestamp of the rightmost required bar (inclusive).</li></ul> | + +#### Supported resolutions + +The resolution you provide must be within the supported boundaries for the given time window size: + +| Time window size | Supported resolutions | +| :------------------------ | :------------------------------- | +| 1 min - 24 hours | 1 minute - 24 hours (1m - 24h) | +| 1 - 5 days | 5 minutes - 5 days (5m - 5d) | +| 5 - 30 days | 30 minutes - 30 days (30m - 30d) | +| 30 - 90 days | 1 hour - 90 days (1h - 90d) | +| 90 - 180 days | 2 hours - 180 days (2h - 6M) | +| 180 - 365 days | 24 hours - 365 days (24h - 1y) | +| 365 - 1825 days (1-5 yrs) | 1 week - 5 years (1w - 5y) | +| Over 1825 days (> 5 yrs) | Over 1 month | -**Note**: The resolution of the data is currently based on the size of the time window: +Resolutions can be provided in the following units: -| Max time window size | Resolution of candles | -| :------------------- | :-------------------- | -| \<= 24 hours | 1 minute | -| \<= 5 days | 5 minutes | -| \<= 30 days | 30 minutes | -| \<= 90 days | 1 hour | -| \<= 6 months | 2 hours | -| > 6 months | 1 day | +| Name | Unit | Example | +| :------ | :--- | :------ | +| minutes | m | 5m | +| hours | h | 3h | +| days | d | 1d | +| weeks | w | 2w | +| months | M | 6M | +| years | y | 2y | ##### Sample request @@ -193,9 +252,9 @@ curl -X GET \ **`/api/v1/history/rows`** -| Type | Description | Parameter(s) | -| :------- | :----------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| HTTP GET | Gets candlestick data in row format. | <ul><li>`symbol`: The symbol to query.</li><li>`resolution`: Resolution of the data (required but not used, use "1m").</li><li>`from`: Unix timestamp of the leftmost required bar (inclusive).</li><li>`to`: Unix timestamp of the rightmost required bar (inclusive).</li></ul> | +| Type | Description | Parameter(s) | +| :------- | :----------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| HTTP GET | Gets candlestick data in row format. | <ul><li>`symbol`: The symbol to query.</li><li>`resolution`: Resolution of the data. E.g., "1m". Must match [supported resolutions](#supported-resolutions).</li><li>`from`: Unix timestamp of the leftmost required bar (inclusive).</li><li>`to`: Unix timestamp of the rightmost required bar (inclusive).</li></ul> | ##### Sample request diff --git a/src/content/data-streams/reference/report-schema-overview.mdx b/src/content/data-streams/reference/report-schema-overview.mdx index 1ad3b81d699..5fa73315609 100644 --- a/src/content/data-streams/reference/report-schema-overview.mdx +++ b/src/content/data-streams/reference/report-schema-overview.mdx @@ -83,24 +83,24 @@ Each stream category uses one or more report schemas to deliver data. Several ca </tr> <tr> <td> - <a href="/data-streams/nav-streams">NAV</a> + <a href="/data-streams/smartdata-streams">SmartData</a> </td> <td> - <a href="/data-streams/reference/report-schema-v9">NAV (v9)</a> + <a href="/data-streams/reference/report-schema-v9">SmartData (v9)</a> </td> - <td>Net Asset Value (NAV)</td> + <td>Net Asset Value (NAV), Proof of Reserve (POR)</td> <td> <code>aum</code>, <code>navPerShare</code>, <code>navDate</code>, <code>ripcord</code> </td> </tr> <tr> <td> - <a href="/data-streams/backed-streams">Tokenized Asset</a> + <a href="/data-streams/tokenized-asset-streams">Tokenized Asset</a> </td> <td> <a href="/data-streams/reference/report-schema-v10">Tokenized Asset (v10)</a> </td> - <td>Backed xStock</td> + <td>Tokenized equities</td> <td> <code>price</code>, <code>tokenizedPrice</code>, <code>marketStatus</code>, <code>currentMultiplier</code>,{" "} <code>newMultiplier</code> @@ -155,18 +155,18 @@ The [RWA Advanced (v11)](/data-streams/reference/report-schema-v11) report schem These advanced fields enable protocols to implement more sophisticated risk management and settlement logic. Where applicable, streams using this schema can provide coverage across extended trading sessions including pre-market, post-market, and overnight hours — though extended hours availability varies by stream. See individual [RWA stream details](/data-streams/rwa-streams?schema=v11) for specific coverage and the [RWA Advanced (v11) reference](/data-streams/reference/report-schema-v11) for complete field specifications. -## Net Asset Value (NAV) +## SmartData -[Chainlink NAV streams](/data-streams/nav-streams) use the [NAV (v9)](/data-streams/reference/report-schema-v9) report schema to provide real-time, tamper-proof access to the Net Asset Value (`navPerShare`) of tokenized assets, funds, or portfolios. Each report includes NAV per share (`navPerShare`), NAV date (`navDate`), assets under management (`aum`), and ripcord status (`ripcord`). The ripcord is set to true (`1`) by the asset issuer when the consumer should ignore the value being sent (for cases such as maintenance, upstream data source outages, etc). The feed data will remain stale until the ripcord returns false (`0`). +[Chainlink SmartData streams](/data-streams/smartdata-streams) use the [SmartData (v9)](/data-streams/reference/report-schema-v9) report schema to provide real-time, tamper-proof access to data such as Net Asset Value (`navPerShare`) of tokenized assets, funds, or portfolios, as well as Proof of Reserve data. Each report includes NAV per share (`navPerShare`), NAV date (`navDate`), assets under management (`aum`), and ripcord status (`ripcord`). The ripcord is set to true (`1`) by the asset issuer when the consumer should ignore the value being sent (for cases such as maintenance, upstream data source outages, etc). The feed data will remain stale until the ripcord returns false (`0`). NAV is a fundamental financial metric that represents the value of an investment vehicle such as a mutual fund or ETF and is calculated as the total assets minus the total liabilities. -Data Streams ensures that any NAV update, whenever it occurs, is captured and made available immediately and at low latency, allowing for seamless integration with onchain applications alongside other real-time data streams. Although the NAV value may not change frequently, Data Streams provides the most recent NAV as soon as it is published by the source. +Data Streams ensures that any SmartData update, whenever it occurs, is captured and made available immediately and at low latency, allowing for seamless integration with onchain applications alongside other real-time data streams. Although the values may not change frequently, Data Streams provides the most recent data as soon as it is published by the source. ## Tokenized Asset -[Chainlink Tokenized Asset streams](/data-streams/backed-streams) use the [Tokenized Asset (v10)](/data-streams/reference/report-schema-v10) report schema to provide financial market data for tokenized equities such as [xStock](https://xstocks.com/us) assets. These streams combine data from US equity streams with data from the tokenization service to enable users to handle corporate actions affecting the underlying equities. Each report includes the staleness measure (`lastUpdateTimestamp`), consensus mid price (`price`), market status (`marketStatus`), current multiplier (`currentMultiplier`, the number of underlying shares each xStock is redeemable for), new multiplier (`newMultiplier`, the future number of shares after a scheduled corporate action), activation date/time of the corporate action (`activationDateTime`) and the tokenized price if available on primary or secondary markets (`tokenizedPrice`). +[Chainlink Tokenized Asset streams](/data-streams/tokenized-asset-streams) use the [Tokenized Asset (v10)](/data-streams/reference/report-schema-v10) report schema to provide financial market data for tokenized equities. These streams combine data from US equity streams with data from tokenization services to enable users to handle corporate actions affecting the underlying equities. Each report includes the staleness measure (`lastUpdateTimestamp`), consensus mid price (`price`), market status (`marketStatus`), current multiplier (`currentMultiplier`, the number of underlying shares each tokenized asset is redeemable for), new multiplier (`newMultiplier`, the future number of shares after a scheduled corporate action), activation date/time of the corporate action (`activationDateTime`) and the tokenized price if available on primary or secondary markets (`tokenizedPrice`). The underlying US equities trade on traditional exchanges during [market hours](/data-streams/market-hours). These market hours depend per asset class and can be subject to unexpected halts, pauses and other behaviors affecting traditional markets. For this reason, this class of Data Streams contains a market hours flag and a staleness measure to equip our users to handle these events correctly. It is critical that users implement correct safeguards on their end to pause markets, add more conservative risk caps, or implement other measures appropriate for their application. -[Tokenized Asset (v10)](/data-streams/reference/report-schema-v10) is designed specifically for tokenized equities such as xStocks and contains data from the Chainlink US equities streams, combined with data provided by the tokenizer to properly handle corporate actions. With this enhanced data users are able to handle expected and unexpected market events such as pauses, halts and market off hours. The tokenization provider layers in data around the `currentMultiplier`, the `newMultiplier` and the `activationDateTime` of the new multiplier to handle corporate actions. +[Tokenized Asset (v10)](/data-streams/reference/report-schema-v10) is designed specifically for tokenized equities and contains data from the Chainlink US equities streams, combined with data provided by the tokenizer to properly handle corporate actions. With this enhanced data users are able to handle expected and unexpected market events such as pauses, halts and market off hours. The tokenization provider layers in data around the `currentMultiplier`, the `newMultiplier` and the `activationDateTime` of the new multiplier to handle corporate actions. diff --git a/src/content/data-streams/reference/report-schema-v10.mdx b/src/content/data-streams/reference/report-schema-v10.mdx index 08f8498104a..7dfc49a4b17 100644 --- a/src/content/data-streams/reference/report-schema-v10.mdx +++ b/src/content/data-streams/reference/report-schema-v10.mdx @@ -5,7 +5,7 @@ title: "Report Schema: Tokenized Asset (v10)" metadata: title: "Tokenized Asset (v10) | Chainlink Data Streams" description: "Learn about Chainlink Data Streams Tokenized Asset (v10) schema, including fields, encoding, and examples for integrating tokenized asset data in your applications." - keywords: ["Report Schema", "Tokenized Assets", "Backed xStock", "v10 Schema", "Data Format", "Report Structure"] + keywords: ["Report Schema", "Tokenized Assets", "Tokenized Equities", "v10 Schema", "Data Format", "Report Structure"] --- import DataStreams from "@features/data-streams/common/DataStreams.astro" @@ -16,7 +16,7 @@ import Aside from "@components/Aside.astro" <ReportSchemaTabs /> -Chainlink Backed xStock Data Streams adhere to the report schema outlined below. +Chainlink Tokenized Asset Data Streams adhere to the report schema outlined below. ### Schema Fields @@ -38,15 +38,17 @@ Chainlink Backed xStock Data Streams adhere to the report schema outlined below. {/* prettier-ignore */} <Aside type="danger" title="Weekend Usage Disclaimer"> - **Users should not use these streams during weekends** due to limited exchange activity. + **The `price` field does not update during weekends** because the underlying real-world equity market is closed. - If usage is necessary, increase fees to mitigate risks. Developers are solely responsible for monitoring and mitigating market integrity risks, as outlined in the [Developer Responsibilities](/data-streams/developer-responsibilities) documentation. + However, the `tokenizedPrice` field continues to update as it reflects trading activity on centralized exchanges (CEXs). Weekend liquidity tends to be thin, so users should implement guardrails against unexpected volatility. + + Developers are solely responsible for monitoring and mitigating market integrity risks, as outlined in the [Developer Responsibilities](/data-streams/developer-responsibilities) documentation. </Aside> **Notes:** -- Future Backed xStock streams may use different report schemas. +- Future Tokenized Asset streams may use different report schemas. - `price` updates in real time during market open, but may become stale during market closed periods. - `currentMultiplier` reflects all past corporate actions and is updated only when a new action is activated. - `activationDateTime` and `newMultiplier` provide advance notice of upcoming corporate actions, allowing protocols to prepare. -- See more detailed guidance for handling stock splits in the [Best Practices](/data-streams/concepts/best-practices#handling-stock-splits-for-tokenized-assets) documentation. +- See more detailed guidance for handling stock splits in the [Handling Stock Splits](/data-streams/tokenized-asset-streams/handling-stock-splits) documentation. diff --git a/src/content/data-streams/reference/report-schema-v11.mdx b/src/content/data-streams/reference/report-schema-v11.mdx index 25278ef3faf..a388c135d32 100644 --- a/src/content/data-streams/reference/report-schema-v11.mdx +++ b/src/content/data-streams/reference/report-schema-v11.mdx @@ -22,6 +22,16 @@ metadata: import DataStreams from "@features/data-streams/common/DataStreams.astro" import ReportSchemaTabs from "@features/data-streams/common/ReportSchemaTabs.astro" +import { Aside } from "@components" + +{/* Fix for the table cutting off/overflowing */} + +<style>{` + article table code { + white-space: nowrap; + } +`}</style> + <DataStreams section="dsNotes" /> <ReportSchemaTabs /> @@ -30,41 +40,72 @@ Chainlink Data Streams that use the RWA Advanced (v11) schema adhere to the stru ## Schema Fields -| Field | Type | Description | -| ----------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `feedId` | `bytes32` | Unique identifier for the Data Streams feed | -| `validFromTimestamp` | `uint32` | Earliest timestamp when the price is valid (seconds) | -| `observationsTimestamp` | `uint32` | Latest timestamp when the price is valid (seconds) | -| `nativeFee` | `uint192` | Cost to verify report onchain (native token) | -| `linkFee` | `uint192` | Cost to verify report onchain (LINK) | -| `expiresAt` | `uint32` | Expiration date of the report (seconds) | -| `mid` | `int192` | Liquidity-weighted mid price | -| `lastSeenTimestampNs` | `uint64` | Staleness indicator based on mid price (nanoseconds) | -| `bid` | `int192` | Median bid price | -| `bidVolume` | `int192` | Volume at bid price | -| `ask` | `int192` | Median ask price | -| `askVolume` | `int192` | Volume at ask price | -| `lastTradedPrice` | `int192` | Last traded price | -| `marketStatus` | `uint32` | Status of the real-world equity market. <br/> Possible values: <br/> `0` (Unknown), <br/> `1` (Pre-market extended hours), <br/> `2` (Regular hours), <br/> `3` (Post-market hours), <br/> `4` (Overnight), <br/> `5` (Weekend) <br/> [More details](#market-status-values) | +| Field | Type | Description | +| ----------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `feedId` | `bytes32` | Unique identifier for the Data Streams feed | +| `validFromTimestamp` | `uint32` | Earliest timestamp when the price is valid (seconds) | +| `observationsTimestamp` | `uint32` | Latest timestamp when the price is valid (seconds) | +| `nativeFee` | `uint192` | Cost to verify report onchain (native token) | +| `linkFee` | `uint192` | Cost to verify report onchain (LINK) | +| `expiresAt` | `uint32` | Expiration date of the report (seconds) | +| `mid` | `int192` | DON Consensus mid-price | +| `lastSeenTimestampNs` | `uint64` | Reflects the timestamp of the last update for the **mid price only** (nanoseconds). See [Notes](#notes) below. | +| `bid` | `int192` | Median bid price | +| `bidVolume` | `int192` | Volume at bid price. See [bid/ask volume note](#bidask-volume-note) below. | +| `ask` | `int192` | Median ask price | +| `askVolume` | `int192` | Volume at ask price. See [bid/ask volume note](#bidask-volume-note) below. | +| `lastTradedPrice` | `int192` | Last traded price | +| `marketStatus` | `uint32` | Status of the real-world asset market. Values depend on the stream's supported hours. See [Market Status Values](#market-status-values) for details. | ### Market Status Values -The `marketStatus` field reflects the current state of the equity market: +The `marketStatus` field indicates the current state of the market. The possible values vary depending on the stream's supported trading hours: + +#### Standard RWA Streams + +For streams with standard market hours coverage. Unless a feed explicitly states extended hours support, it is assumed to follow this format: + +| Value | Status | Description | +| ----- | ----------- | ---------------------------------- | +| `0` | **Unknown** | Market status cannot be determined | +| `1` | **Closed** | Market is closed | +| `2` | **Open** | Market is open | + +#### 24/5 US Equities Streams + +For streams with 24/5 extended hours coverage (e.g., US Equities): -| Value | Status | Hours (ET) | Description | -| ----- | ----------------- | ------------------------------------- | ---------------------------------------------- | -| `0` | **Unknown** | — | Market status cannot be determined | -| `1` | **Pre-market** | 4:00am–9:30am Mon–Fri | Extended hours before regular trading session | -| `2` | **Regular hours** | 9:30am–4:00pm Mon–Fri | Primary trading session with highest liquidity | -| `3` | **Post-market** | 4:00pm–8:00pm Mon–Fri | Extended hours after regular trading session | -| `4` | **Overnight** | 8:00pm–4:00am Sun evening–Fri morning | Overnight session with limited liquidity | -| `5` | **Weekend** | 8:00pm Fri–8:00pm Sun | Weekend period when primary markets are closed | +| Value | Status | Normal Hours (ET) | Description | +| ----- | ----------------- | ------------------------------------- | ---------------------------------------------------------- | +| `0` | **Unknown** | — | Market status cannot be determined | +| `1` | **Pre-market** | 4:00am–9:30am Mon–Fri | Extended hours before regular trading session | +| `2` | **Regular hours** | 9:30am–4:00pm Mon–Fri | Primary trading session with highest liquidity | +| `3` | **Post-market** | 4:00pm–8:00pm Mon–Fri | Extended hours after regular trading session | +| `4` | **Overnight** | 8:00pm–4:00am Sun evening–Fri morning | Overnight session with limited liquidity | +| `5` | **Closed** | — | Market closed (weekends, holidays, or unexpected closures) | -Users should implement appropriate safeguards based on market status, such as pausing trading, adjusting risk parameters, or implementing staleness checks during non-regular hours. +Users should implement appropriate safeguards based on market status, such as pausing trading, adjusting risk parameters, or implementing staleness checks during non-regular hours or closed periods. + +<Aside type="note" title="Handling Unknown and Closed Status"> + Consumers should implement logic to handle market status `0` (Unknown) and market status `5` (Closed), as these + periods imply no active feed and require a decision on fallback behavior (e.g., using a tokenized price, pausing the + market, etc.). +</Aside> ### Notes +#### Last Seen Timestamp + +- `lastSeenTimestampNs` helps applications detect stale data for the mid price, especially important during market transitions and holidays. +- **IMPORTANT**: The `lastSeenTimestampNs` field reflects the timestamp of the last update for the `mid` price only. Do not assume this timestamp applies to `bid`, `ask`, `bidVolume`, `askVolume`, or `lastTradedPrice`. Different fields may have been updated at different times. + +#### Bid/Ask Volume + +For U.S. equities, there is no single consolidated order book. Instead, multiple venues each maintain their own order books. Because data providers source from different markets, the `bidVolume` and `askVolume` reported at each update come from one specific order book at a time, not an aggregate across all venues. + +As a result, these volume fields should not be treated as a proxy for total market liquidity at the top of book. They are informational and not especially representative in fragmented markets like U.S. equities. + +#### Additional Notes + - Future streams using this format may adopt different report schemas as needed. -- `lastSeenTimestampNs` helps applications detect stale data, especially important during market transitions and holidays. -- Market status cannot detect public holidays. See [Market Hours](/data-streams/market-hours) for major holiday periods. - Data availability and sourcing vary by session. Liquidity is typically highest during regular hours and lower during extended and overnight sessions. diff --git a/src/content/data-streams/reference/report-schema-v8.mdx b/src/content/data-streams/reference/report-schema-v8.mdx index 061a3ec2fe8..aee16c91a8c 100644 --- a/src/content/data-streams/reference/report-schema-v8.mdx +++ b/src/content/data-streams/reference/report-schema-v8.mdx @@ -35,5 +35,5 @@ RWA streams adhere to the report schema outlined below. - `marketStatus`: - Users are responsible for handling market status changes in their applications. - - For further guidance, refer to the [Market Hours Best Practices](/data-streams/concepts/best-practices#market-hours) documentation. + - For further guidance, refer to the [Handling Market Events](/data-streams/rwa-streams/handling-market-events) documentation. - Future RWA streams may use different report schemas. diff --git a/src/content/data-streams/reference/report-schema-v9.mdx b/src/content/data-streams/reference/report-schema-v9.mdx index 6474bacd7ef..26f6756affc 100644 --- a/src/content/data-streams/reference/report-schema-v9.mdx +++ b/src/content/data-streams/reference/report-schema-v9.mdx @@ -1,11 +1,22 @@ --- section: dataStreams date: Last Modified -title: "Report Schema: NAV (v9)" +title: "Report Schema: SmartData (v9)" metadata: - title: "NAV (v9) | Chainlink Data Streams" - description: "Learn about Chainlink Data Streams NAV (v9) schema, including fields, encoding, and examples for integrating NAV data in your applications." - keywords: ["Report Schema", "NAV", "Net Asset Value", "v9 Schema", "Data Format", "Report Structure"] + title: "SmartData (v9) | Chainlink Data Streams" + description: "Learn about Chainlink Data Streams SmartData (v9) schema, including fields, encoding, and examples for integrating NAV and POR data in your applications." + keywords: + [ + "Report Schema", + "SmartData", + "NAV", + "POR", + "Net Asset Value", + "Proof of Reserve", + "v9 Schema", + "Data Format", + "Report Structure", + ] --- import DataStreams from "@features/data-streams/common/DataStreams.astro" @@ -15,7 +26,7 @@ import ReportSchemaTabs from "@features/data-streams/common/ReportSchemaTabs.ast <ReportSchemaTabs /> -Chainlink NAV Data Streams streams adhere to the report schema outlined below. +Chainlink SmartData streams adhere to the report schema outlined below. ### Schema Fields @@ -34,7 +45,7 @@ Chainlink NAV Data Streams streams adhere to the report schema outlined below. **Notes:** -- Future NAV streams may use different report schemas. +- Future SmartData streams may use different report schemas. ##### `ripcord` Status diff --git a/src/content/data-streams/rwa-streams/24-5-us-equities-user-guide.mdx b/src/content/data-streams/rwa-streams/24-5-us-equities-user-guide.mdx new file mode 100644 index 00000000000..c20768fee36 --- /dev/null +++ b/src/content/data-streams/rwa-streams/24-5-us-equities-user-guide.mdx @@ -0,0 +1,402 @@ +--- +section: dataStreams +date: "Last Modified" +title: "24/5 US Equities User Guide" +metadata: + title: "24/5 US Equities User Guide | Chainlink Data Streams" + description: "User guide for Chainlink 24/5 U.S. Equities Streams, covering schema, feeds, continuous price feed composition, and risk management." +whatsnext: + { + "Find the schema of data to expect from Data Streams reports: RWA Advanced (v11)": "/data-streams/reference/report-schema-v11", + "Learn about Data Streams market hours and schedules": "/data-streams/market-hours", + } +--- + +import { Aside, ClickToZoom } from "@components" +import { Tabs } from "@components/Tabs" +import { FeedList } from "@features/feeds" + +Chainlink 24/5 U.S. Equities Streams provide real-time equity pricing data across all major U.S. single-name equities and ETFs spanning regular, pre-market, post-market, and overnight trading sessions. The [advanced RWA schema](/data-streams/reference/report-schema-v11) includes fields such as market status flags, best bid and ask prices, bid and ask volumes, staleness measures, and last traded prices to facilitate more advanced execution and risk management. + +<ClickToZoom src="/images/data-streams/24-5-availability.png" caption="24/5 Streams Availability Diagram" /> + +The data referenced in this document covers 24/5 trading hours in US equities on a range of traditional venues. While there is currently no trading activity in traditional markets over the weekend on any venue, protocols can extend their pricing coverage to 24/7 in multiple ways, such as leveraging the pricing of [tokenized stocks](#stream-switching-example-logic) on secondary markets such as CEXes and DEXes. + +Developers are responsible for choosing the appropriate feed and ensuring that the operation and performance of their choice matches expectations. For more information, please visit the Chainlink [documentation](/data-streams/developer-responsibilities). + +## Schema + +The data is delivered using the [RWA Advanced (v11) schema](/data-streams/reference/report-schema-v11). + +This advanced RWA schema is built to support 24/5 streams, including DON Consensus `mid` price (with its corresponding timestamp `lastSeenTimestampNs` for staleness tracking), order book depth (`bid`, `ask`, `bidVolume`, `askVolume`), execution data (`lastTradedPrice`), and granular market phases (`marketStatus` values for Pre-market, Regular hours, Post-market, Overnight, and Closed). + +<Aside type="caution" title="Important: Timestamp Scope"> + The `lastSeenTimestampNs` field reflects the timestamp of the last update for the `mid` price only. This timestamp + does **not** apply to other fields in the report such as `bid`, `ask`, `bidVolume`, `askVolume`, or `lastTradedPrice`. + Different fields may have been updated at different times. +</Aside> + +<Aside type="note" title="Bid/Ask Volume Interpretation"> + For U.S. equities, there is no single consolidated order book—multiple venues each maintain their own. The `bidVolume` + and `askVolume` reported come from one specific order book at a time, not an aggregate across all venues. These values + should not be treated as a proxy for total market liquidity and are primarily informational. +</Aside> + +## Feeds + +Each instrument is exposed through three distinct data streams feeds, each corresponding to a specific trading phase: **Regular Hours**, **Extended Hours**, and **Overnight Hours**. + +You can view all available 24/5 US Equities streams in the [stream table viewer](/data-streams/stream-ids) or see the [complete list below](#available-streams). + +For example, **TSLA** is available via the following streams: + +- `TSLA/USD-Streams-ExtendedHours` +- `TSLA/USD-Streams-OvernightHours` +- `TSLA/USD-Streams-RegularHours` + +To construct a **continuous price feed**, users must **dynamically switch** between these individual streams based on the value of `marketStatus`. The mapping logic is as follows: + +| Market Status | Stream | +| ----------------- | --------------------------------- | +| `1` (Pre-market) | `TSLA/USD-Streams-ExtendedHours` | +| `2` (Regular) | `TSLA/USD-Streams-RegularHours` | +| `3` (Post-market) | `TSLA/USD-Streams-ExtendedHours` | +| `4` (Overnight) | `TSLA/USD-Streams-OvernightHours` | + +<Aside type="note" title="Note"> + Market status `0` (Unknown) and `5` (Closed) require custom handling. See the [Building a Continuous Price + Feed](#building-a-continuous-price-feed) section below. +</Aside> + +## Building a Continuous Price Feed + +Building a continuous price feed by dynamically switching streams requires robust exception handling to manage edge cases effectively. Because different protocols have unique risk profiles and design requirements, Data Streams allows you to implement custom logic tailored to your specific needs. + +There is no one-size-fits-all solution to integrating 24/5 streams. The sections below outline edge cases you will encounter when building a continuous price feed along with recommended mitigation strategies. For information on structural risks and protocol-specific considerations, see the [Risks](#risks) section. + +If you wish to jump ahead to view an example of switching logic, jump to [Stream Switching Example Logic](#stream-switching-example-logic). + +### Edge Cases and Mitigation + +#### Price Jumps at Session Transition Boundaries + +When transitioning between Regular ↔ Extended ↔ Overnight sessions, noticeable price dislocations can occur. + +These differences are expected and normal due to unique liquidity conditions, venues, participants, and pricing sources per session. These are not bad data; they are true market microstructure effects. + +Typical jumps are **1–2%**, but **larger spikes (10–20%+)** are possible during low-liquidity environments or impactful news cycles. + +<ClickToZoom + src="/images/data-streams/24-5-price-jumps-example.png" + caption="Example chart showing price jumps at session transition boundaries. Green = regular trading hours, Orange = pre- and post-market sessions, Black = overnight session." +/> + +##### Mitigation + +**Phase-specific streams are provided intentionally** to give users control over when and how transitions occur. Optional safeguards: + +- Pause or lock market activity during transition windows +- Delay feed switching until price convergence or stability threshold is met +- Apply price smoothing (EMA/VWAP/TWAP) across transition windows +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +#### Market Status Unknown/Unavailable (`marketStatus = 0`) + +The system may return `marketStatus = 0` (Unknown). **If your implementation relies on automated feed switching based on market status, you must account for this scenario.** + +Market status is sourced from several independent providers configured as primary/fallback. While resilient, multiple providers can fail simultaneously. + +##### Mitigation + +Consumers must treat `marketStatus = 0` (Unknown) as a valid state and define deterministic behaviors when it is returned. Potential actions include: + +- Pause or lock market activity +- Allow restricted trading within a bounded range (e.g., last-valid price ± threshold) +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +#### Closed (`marketStatus = 5`) + +Market status `5` indicates the market is closed, which includes weekends, public holidays, and unexpected market closures. During these periods, all three feeds will carry stale values. This reflects true underlying market inactivity rather than an outage or failure. + +##### Mitigation + +Consumers must treat `marketStatus = 5` (Closed) as a valid state and define deterministic behaviors when it is returned. Potential actions include: + +- Pause or lock market activity +- Allow restricted trading within a bounded range (e.g., last-valid price ± threshold) +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +#### Stale Data Detection + +Markets may stop updating due to exchange outages, circuit breakers, trading halts, or corporate actions. The `marketStatus` field will continue reflecting the status that it normally would. Use the `lastSeenTimestampNs` field (which reflects the timestamp of the last update for the `mid` price only) to detect staleness by comparing it against the current time. When this timestamp stops advancing, it indicates the underlying venue has stopped providing updates. + +Phase-specific feeds can introduce unique behavior due to venue-specific operational characteristics and market microstructure. The following are some examples of scenarios that may occur during session transitions or under specific market conditions: + +##### Regular Hours Session: Delayed Quote Availability at Market Open + +During the first 10–20 seconds after regular hours open (9:30am ET), bid/ask quotes may not yet be available from the regular hours venue. In those cases, the reported price may still reflect the previous regular hours close rather than live market data. + +Users should factor this transition period into their switching logic and consider alternative strategies during the first ~20 seconds of regular hours, such as: + +- Pause or lock market activity +- Continue using the pre-market (Extended Hours) stream until fresh regular hours quotes are available +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +##### Overnight Session: Stale Bid/Ask at Session Start + +During the early overnight session -- before the overnight venue begins publishing data -- the feed may display the last bid/ask prices and volumes from the previous regular session. This occurs because no new quotes are available yet from the overnight venue. + +Once the overnight venue starts publishing its own quotes, the data will update to reflect current overnight market conditions. This behavior is normal market microstructure, not a data quality issue. It reflects the actual state of the market during the transition period when overnight liquidity has not yet begun. + +Users relying on bid/ask data during early overnight hours should be aware of this carryover behavior and implement appropriate safeguards, such as checking `lastSeenTimestampNs` for staleness or widening risk parameters during overnight session transitions. + +##### Mitigation + +Consumers must have fallback logic in place when the data is stale. Potential actions include: + +- Pause or lock market activity +- Use last-valid price as reference +- Allow bounded-range trading based on last-valid price +- Temporarily reference [tokenized asset](#stream-switching-example-logic) price (where available) + +### Stream Switching Example Logic + +The following examples demonstrate how to implement a continuous price feed by dynamically switching between phase-specific streams. These examples use tokenized asset prices as the fallback strategy for edge cases (stale data, Unknown market status, and Closed). Developers may choose alternative mitigation strategies based on their protocol's risk requirements. + +Developers interested in using tokenized assets can find the list of supported assets and schema in the [Tokenized Assets documentation](/data-streams/tokenized-asset-streams). Using tokenized assets carries its own risks, including liquidity limitations and price deviations from spot markets. Evaluate these factors carefully before integrating tokenized prices into your protocol. + +<Aside type="note" title="Note"> + Tokenized Assets are often Total Return Trackers (TRT). If used, the price should be normalized back to a non-TRT + price: `Spot_RWA_Price = Tokenized_RWA_Price / TRT_Multiplier` +</Aside> + +#### Decision Flow + +To build a continuous price feed, follow this general decision flow. This is a simplified outline that leverages tokenized asset prices as fallback; your implementation must account for all risks outlined above and in the [Risks](#risks) section below. + +1. **Fetch and decode** the Regular Hours stream report to get `marketStatus` and `lastSeenTimestampNs` + +2. **Check staleness first:** + - **If data is stale** (timestamp older than your threshold) → **[Use Tokenized Asset stream](/data-streams/tokenized-asset-streams)** or apply custom risk mitigation + - **If data is fresh** → Continue to step 3 + +3. **Route based on market status:** + - **`marketStatus = 0`** (Unknown) → **Use Tokenized Asset stream** or apply custom risk mitigation + - **`marketStatus = 1`** (Pre-market) → **Use Extended Hours stream** + - **`marketStatus = 2`** (Regular) → **Use Regular Hours stream** + - **`marketStatus = 3`** (Post-market) → **Use Extended Hours stream** + - **`marketStatus = 4`** (Overnight) → **Use Overnight Hours stream** + - **`marketStatus = 5`** (Closed) → **Use Tokenized Asset stream** or apply custom risk mitigation + +4. **Apply additional safeguards** as needed for your protocol (e.g., price jump checks, circuit breakers, holiday calendars, bounded trading ranges) + +5. **Return the `mid` price** from the selected stream + +<Aside type="caution" title="Important"> + This is a simplified decision flow. Your implementation must account for all risks outlined in the [Risks](#risks) + section below, including price jumps at transition boundaries, corporate actions, public holidays, and + protocol-specific edge cases. Each protocol has unique risk requirements—design your switching logic accordingly. +</Aside> + +#### Example Implementation Logic + +This example demonstrates switching logic with tokenized asset prices as fallback. View examples in different SDK languages. + +Please note that these code snippets are illustrative and may require adaptation to fit your specific environment, SDK versions, and error handling practices. Refer to the guide to [fetch](/data-streams/tutorials/go-sdk-fetch) and [stream](/data-streams/tutorials/go-sdk-stream) decoded reports in your chosen SDK. + +<br /> + +{/* prettier-ignore */} +<Tabs client:visible> + <Fragment slot="tab.1">TypeScript</Fragment> + <Fragment slot="tab.2">Go</Fragment> + <Fragment slot="tab.3">Rust</Fragment> + <Fragment slot="panel.1"> + ```typescript + import { createClient, decodeReport } from "@chainlink/data-streams-sdk" + + const client = createClient({ apiKey, userSecret, endpoint }) + + async function getPrice() { + const regularReport = await client.getLatestReport(REGULAR_HOURS) + const decoded = decodeReport(regularReport.fullReport, regularReport.feedID) + + // Check staleness (5 minute threshold) + const isStale = (Date.now() - decoded.lastSeenTimestampNs / 1000000) > 300000 + + // Determine which stream to use + if (isStale || decoded.marketStatus === 0 || decoded.marketStatus === 5) { + // Stale, Unknown, or Closed -> use tokenized asset + const tokenReport = await client.getLatestReport(TOKENIZED_TSLA) + return decodeReport(tokenReport.fullReport, tokenReport.feedID).mid + } else if (decoded.marketStatus === 1 || decoded.marketStatus === 3) { + const report = await client.getLatestReport(EXTENDED_HOURS) + return decodeReport(report.fullReport, report.feedID).mid + } else if (decoded.marketStatus === 2) { + return decoded.mid + } else if (decoded.marketStatus === 4) { + const report = await client.getLatestReport(OVERNIGHT_HOURS) + return decodeReport(report.fullReport, report.feedID).mid + } + } + ``` + + </Fragment> + <Fragment slot="panel.2"> + ```go + import "github.com/smartcontractkit/data-streams-sdk/go/feed" + + func getPrice() (*big.Int, error) { + report, err := client.GetLatestReport(REGULAR_HOURS) + if err != nil { + return nil, err + } + + decoded, err := feed.Decode(report.FullReport) + if err != nil { + return nil, err + } + + // Check staleness (5 minute threshold) + isStale := time.Since(decoded.LastSeenTimestamp) > 5*time.Minute + + // Determine which stream to use + if isStale || decoded.MarketStatus == 0 || decoded.MarketStatus == 5 { + // Stale, Unknown, or Closed -> use tokenized asset + tokenReport, _ := client.GetLatestReport(TOKENIZED_TSLA) + tokenDecoded, _ := feed.Decode(tokenReport.FullReport) + return tokenDecoded.Mid, nil + } else if decoded.MarketStatus == 1 || decoded.MarketStatus == 3 { + extReport, _ := client.GetLatestReport(EXTENDED_HOURS) + extDecoded, _ := feed.Decode(extReport.FullReport) + return extDecoded.Mid, nil + } else if decoded.MarketStatus == 2 { + return decoded.Mid, nil + } else if decoded.MarketStatus == 4 { + ovnReport, _ := client.GetLatestReport(OVERNIGHT_HOURS) + ovnDecoded, _ := feed.Decode(ovnReport.FullReport) + return ovnDecoded.Mid, nil + } + } + ``` + + </Fragment> + <Fragment slot="panel.3"> + ```rust + use data_streams_sdk::{client::Client, feed}; + + async fn get_price() -> Result<i128, Box<dyn std::error::Error>> { + let report = client.get_latest_report(REGULAR_HOURS).await?; + let decoded = feed::decode(&report.full_report)?; + + // Check staleness (5 minute threshold) + let is_stale = (SystemTime::now().duration_since(UNIX_EPOCH)?.as_nanos() + - decoded.last_seen_timestamp_ns as u128) > 300_000_000_000; + + // Determine which stream to use + if is_stale || decoded.market_status == 0 || decoded.market_status == 5 { + // Stale, Unknown, or Closed -> use tokenized asset + let token_report = client.get_latest_report(TOKENIZED_TSLA).await?; + let token_decoded = feed::decode(&token_report.full_report)?; + Ok(token_decoded.mid) + } else if decoded.market_status == 1 || decoded.market_status == 3 { + let ext_report = client.get_latest_report(EXTENDED_HOURS).await?; + let ext_decoded = feed::decode(&ext_report.full_report)?; + Ok(ext_decoded.mid) + } else if decoded.market_status == 2 { + Ok(decoded.mid) + } else if decoded.market_status == 4 { + let ovn_report = client.get_latest_report(OVERNIGHT_HOURS).await?; + let ovn_decoded = feed::decode(&ovn_report.full_report)?; + Ok(ovn_decoded.mid) + } else { + Err("Unknown market status".into()) + } + } + ``` + + </Fragment> +</Tabs> + +<Aside type="caution" title="Disclaimer"> + This guide represents an example of using a Chainlink product or service and is provided to help you understand how to + interact with Chainlink's systems and services so that you can integrate them into your own. This template is provided + "AS IS" and "AS AVAILABLE" without warranties of any kind, has not been audited, and may be missing key checks or + error handling to make the usage of the product more clear. Do not use the code in this example in a production + environment without completing your own audits and application of best practices. Neither Chainlink Labs, the + Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs that are generated due to + errors in code. +</Aside> + +## Risks + +While 24/5 streams provide extended market coverage, they introduce specific risks related to liquidity, volatility, and data sourcing. Users must understand these factors and implement appropriate safeguards. + +In the following sections, we outline key risks and recommended mitigation strategies. + +### Single Provider for Extended & Overnight Data + +Extended and overnight session price feeds are currently sourced from a single data provider, making these sessions less reliable than the regular hours price feed which is multi-sourced. + +If the provider experiences downtime, technical failures, or connectivity disruption, the feed may flatline or report highly inaccurate figures, preventing users from reacting to real price movements. Such issues may lead to mispricing, failed liquidations, and potential bad debt accumulation. + +##### Mitigation + +The feed includes a staleness indicator, allowing consumers to detect when data stops updating. Users are strongly recommended to implement fallback logic within their protocol risk framework, which may include: + +- Pause or lock market activity +- Restrict to narrow price bands +- Temporarily switch to the tokenized price feed (understanding that it also carries liquidity limitations) + +### Structural Illiquidity and Volatility in Extended & Overnight Hours + +Pre-market and post-market sessions are typically thinly traded, with fragmented liquidity and higher spreads, leading to stale ticks, price gaps, and elevated volatility. These conditions are inherent to the market, not to the feed, and will be visible in the published data. + +##### Mitigation + +Users should evaluate whether the full 24/5 price coverage is appropriate for their use case. Consider the following: + +- Configure risk thresholds, circuit breakers, or mode switching aligned with your risk appetite +- Validate these configurations during integration and simulation, not post-deployment + +### Corporate Actions + +Traditional equities are subject to corporate actions which can dramatically change the price of an asset overnight, especially in the case of stock splits and reverse stock splits. These actions are usually announced outside regular trading hours and can cause substantial price movements when markets reopen. + +Additionally, the overnight session data provider may disable trading for individual symbols during pending corporate actions such as dividends, splits, or mergers. When this occurs, there will be no overnight session data available for that specific symbol, and this closure will not be reflected in the `marketStatus` field. The overnight feed may continue to display stale data from the previous session, or the data may flatline, making it critical to monitor `lastSeenTimestampNs` for staleness detection. + +##### Mitigation + +Consumers should: + +- Actively monitor corporate action announcements +- Adjust pricing logic, risk parameters, and open positions accordingly +- Consider pausing markets during corporate action windows to prevent unfair liquidations +- Implement staleness checks on `lastSeenTimestampNs` to detect when overnight session data stops updating due to symbol-specific trading halts + +### Trading Halts Are Not Explicitly Flagged + +Trading halts can occur for various reasons including regulatory actions, pending news announcements, volatility circuit breakers, or operational issues. When the underlying market is halted, this will not be reflected in the `marketStatus` field. + +Automated switching logic that relies only on `marketStatus` or staleness signals can incorrectly interpret halt inactivity as an outage or unexpected feed degradation, leading to unnecessary fallbacks, paused markets, or erroneous risk decisions. + +##### Mitigation + +Consumers must: + +- Monitor exchange halt notifications and adjust protocol behavior accordingly +- Implement appropriate safeguards when trading halts are detected to prevent unfair liquidations or trades at stale prices + +For detailed market hours and trading schedules, see the [Market Hours](/data-streams/market-hours) documentation. + +## Available Streams + +The table below shows all available 24/5 US Equities streams. Use the **Time segment** filter to view streams for specific trading sessions. + +<FeedList + client:idle + initialNetwork="arbitrum" + dataFeedType="streamsRwa" + force24x5Only={true} + allowNetworkTableExpansion={true} +/> diff --git a/src/content/data-streams/rwa-streams/handling-market-events-v11.mdx b/src/content/data-streams/rwa-streams/handling-market-events-v11.mdx new file mode 100644 index 00000000000..edc893b6f83 --- /dev/null +++ b/src/content/data-streams/rwa-streams/handling-market-events-v11.mdx @@ -0,0 +1,176 @@ +--- +section: dataStreams +date: "Last Modified" +title: "Handling Market Events (v11)" +metadata: + title: "Handling Market Events (v11) | Chainlink Data Streams" + description: "Learn how to handle market hours, volatility, and corporate actions when using Chainlink Data Streams with the v11 schema." +whatsnext: + { + "Learn about Data Streams market hours and schedules": "/data-streams/market-hours", + "Find the schema of data to expect from Data Streams reports: RWA Advanced (v11)": "/data-streams/reference/report-schema-v11", + } +--- + +import { Aside } from "@components" +import MarketEventsTabs from "@features/data-streams/common/MarketEventsTabs.astro" + +<MarketEventsTabs /> + +<Aside type="note" title="Market Status Values"> + The `marketStatus` field values vary depending on the stream's supported hours. Refer to the [RWA Advanced (v11) + schema documentation](/data-streams/reference/report-schema-v11#market-status-values) to understand which values apply + to your specific stream. This guide uses generic "Open" and "Closed" terminology that applies across all v11 streams. +</Aside> + +Apply these best practices when integrating or operating markets that use tokenized real-world assets during standard market hours. Developers and operators are responsible for assessing market integrity, implementing mitigations, and managing application-level risks — see the [Developer Responsibilities](/data-streams/developer-responsibilities) guidance for details. + +## Market Hours + +Markets for Real-World Assets (RWA) operate during specific hours and are subject to various market conditions that can create risks for applications. The following sections outline common market issues and how to mitigate them. + +<Aside type="note" title="Market Hours Overview"> + For detailed market hours and trading schedules, see the <a href="/data-streams/market-hours">Market Hours</a> page. +</Aside> + +### Market gaps + +Market gaps occur when there are interruptions in trading or price discovery, leading to periods where the last available price may not reflect current market conditions. These gaps can create risks, particularly around market opens, closures, and unexpected disruptions. + +#### Market close + +The following guidance applies to streams during non-trading hours. Check your stream's specific `marketStatus` values in the [schema documentation](/data-streams/reference/report-schema-v11#market-status-values). + +Around market close, large price jumps may occur due to after-hours news. This can create a large pricing gap between the close of the last session and the open of the new session. Such a price jump can cause issues for protocols by triggering sudden liquidations. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until market open.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Keep markets closed while `marketStatus` indicates closed to prevent users trading at unfair prices.<br/><br/> Leverage available should be set in line with the asset average volatility to avoid bad debt if a user's collateral is insufficient to cover the losses. | + +#### Price formation at open/close + +Certain assets (e.g., FX open on Sunday afternoon) experience gradual price discovery due to fragmented liquidity and delayed trading activity. + +Integrating protocols should avoid opening their market with the last close price. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a bid/ask becomes available or a transaction occurs.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Wait until `lastUpdateTimestamp` is current before opening the market so traders don't execute on stale quotes. | + +#### Sudden failures + +Unexpected system outages, order execution failures, or data feed disruptions can occur in traditional data brokers and trading systems. + +The price will be flat during that period, meaning if an integrating protocol lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus` indicates open but `lastUpdateTimestamp` is stale. | + +#### Trading halts + +Stocks can be halted due to extreme volatility (e.g., limit up/down rules) or regulatory actions. + +The price will be flat during that period, meaning if an integrating protocol lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus` indicates open but `lastUpdateTimestamp` is stale. | + +--- + +## Volatility & low liquidity + +During periods of high volatility or low liquidity, price movements can become unpredictable and exaggerated. These conditions can increase the risk of sudden liquidations and bad debt accumulation, requiring careful risk management strategies. + +### Algorithmic & HFT activity + +Rapid-fire trading by algos can create unpredictable price movements. + +High volatility can lead to liquidation and potential bad debt accumulation. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Low liquidity at open/close + +Reduced market depth at trading session transitions can lead to higher volatility and spreads. + +High volatility can lead to liquidation and potential bad debt accumulation. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: Market Open status value.</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +--- + +## Corporate actions + +Corporate actions are events initiated by publicly traded companies that can significantly impact stock prices and trading behavior. These actions are usually announced outside regular trading hours and can cause substantial price movements when markets reopen. Users should monitor these events closely as they can lead to sudden price adjustments that may trigger unexpected liquidations or require position modifications. + +### Bankruptcy & delisting + +Bankruptcy can lead to delisting or complete loss of equity value. + +Delisting will zero out prices for the asset. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------ | +| <ul><li>`midPrice`: Closing price is repeated until a new price is available.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Closing timestamp of the last session.</li></ul> | Monitor delisting news during market closed periods and close markets permanently once confirmed. | + +### Spin-offs + +When a company spins off a business unit into a separate publicly traded entity, the parent company's stock may adjust accordingly, while the spun-off company's shares begin trading independently. + +Positions may need to be manually adjusted if the integrating protocol doesn't support tracking the new entity. + +| Data Stream behavior | User guidance | +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the first post-spin trade.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements during market closed periods.<br/><br/>Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br/><br/>If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | + +### Stock splits & reverse splits + +<Aside type="note" title="Tokenized Stocks Guidance"> + Tokenized stocks such as [Backed xStock](/data-streams/reference/report-schema-v10) handle stock splits differently + using activation dates and staged multipliers to maintain price continuity. [Learn more about advanced stock split + handling](/data-streams/tokenized-asset-streams/handling-stock-splits). +</Aside> + +A stock split increases the number of shares while reducing the price per share (e.g., 2-for-1 split), often making shares more accessible to investors. A reverse split does the opposite, consolidating shares to increase the price per share. + +A 2-for-1 split would reduce the price by 50% from the previous trading session, any leveraged user could get liquidated. + +| Data Stream behavior | User guidance | +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the split-adjusted price prints.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements during market closed periods.<br/><br/>Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br/><br/>If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | + +### Mergers & acquisitions (M&A) + +If a company is being acquired, its stock price may rise to reflect the acquisition premium. The acquiring company's stock might fluctuate based on investor sentiment regarding the deal's financial and strategic impact. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Share buybacks & stock issuance + +Reduced share supply from a buyback can drive stock prices higher, while an increase in share supply can lead to price dilution. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Dividends + +A company's stock price typically adjusts to reflect dividend payments. For example, when a company declares a 10% dividend, its stock price often drops by a similar amount on the ex-dividend date, as new buyers are no longer entitled to that dividend. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the ex-date trade prints.</li><li>`marketStatus`: Market Closed status value(s).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | diff --git a/src/content/data-streams/rwa-streams/handling-market-events.mdx b/src/content/data-streams/rwa-streams/handling-market-events.mdx new file mode 100644 index 00000000000..6359b9da1df --- /dev/null +++ b/src/content/data-streams/rwa-streams/handling-market-events.mdx @@ -0,0 +1,170 @@ +--- +section: dataStreams +date: "Last Modified" +title: "Handling Market Events" +metadata: + title: "Handling Market Events | Chainlink Data Streams" + description: "Learn how to handle market hours, volatility, and corporate actions when using Chainlink Data Streams." +whatsnext: + { + "Learn about Data Streams market hours and schedules": "/data-streams/market-hours", + "Find the schema of data to expect from Data Streams reports: RWA": "/data-streams/reference/report-schema-v8", + } +--- + +import { Aside } from "@components" +import MarketEventsTabs from "@features/data-streams/common/MarketEventsTabs.astro" + +<MarketEventsTabs /> + +Apply these best practices when integrating or operating markets that use tokenized real-world assets. Developers and operators are responsible for assessing market integrity, implementing mitigations, and managing application-level risks — see the [Developer Responsibilities](/data-streams/developer-responsibilities) guidance for details. + +## Market Hours + +Markets for Real-World Assets (RWA) operate during specific hours and are subject to various market conditions that can create risks for applications. The following sections outline common market issues and how to mitigate them. + +<Aside type="note" title="Market Hours Overview"> + For detailed market hours and trading schedules, see the <a href="/data-streams/market-hours">Market Hours</a> page. +</Aside> + +### Market gaps + +Market gaps occur when there are interruptions in trading or price discovery, leading to periods where the last available price may not reflect current market conditions. These gaps can create risks, particularly around market opens, closures, and unexpected disruptions. + +#### Market close + +Large price jumps between trading sessions due to after-hours news. + +A large price jump at market open could cause sudden liquidations, potentially leaving an integrating protocol with bad debt if a trader's collateral is insufficient to cover the losses. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until market open.</li><li>`marketStatus`: 1 = Market Closed.</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Keep markets closed while `marketStatus = 1` to prevent users trading at unfair prices.<br/><br/> Leverage available should be set in line with the asset average volatility to avoid bad debt if a trader's collateral is insufficient to cover the losses. | + +#### Price formation at open/close + +Certain assets (e.g., FX open on Sunday afternoon) experience gradual price discovery due to fragmented liquidity and delayed trading activity. + +Integrating protocols should avoid opening their market with the last close price. + +| Data Stream behavior | User guidance | +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a bid/ask becomes available or a transaction occurs.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the closing price of the last session.</li></ul> | Wait until `lastUpdateTimestamp` is current before opening the market so traders don't execute on stale quotes. | + +#### Sudden failures + +Unexpected system outages, order execution failures, or data feed disruptions can occur in traditional data brokers and trading systems. + +The price will be flat during that period, meaning if an integrating protocol lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. + +| Data Stream behavior | User guidance | +| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus = 2` but `lastUpdateTimestamp` is stale. | + +#### Trading halts + +Stocks can be halted due to extreme volatility (e.g., limit up/down rules) or regulatory actions. + +The price will be flat during that period, meaning if an integrating protocol lacks a mechanism to handle halts, it may struggle to determine fair prices thus leading to unpredictable liquidations. + +| Data Stream behavior | User guidance | +| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Last mid-price is repeated until a new price is available.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Timestamp of the last mid-price.</li></ul> | Decide whether to allow users to open/close positions when `marketStatus = 2` but `lastUpdateTimestamp` is stale. | + +--- + +## Volatility & low liquidity + +During periods of high volatility or low liquidity, price movements can become unpredictable and exaggerated. These conditions can increase the risk of sudden liquidations and bad debt accumulation, requiring careful risk management strategies. + +### Algorithmic & HFT activity + +Rapid-fire trading by algos can create unpredictable price movements. + +High volatility can lead to liquidation and potential bad debt accumulation. + +| Data Stream behavior | User guidance | +| :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Low liquidity at open/close + +Reduced market depth at trading session transitions can lead to higher volatility and spreads. + +High volatility can lead to liquidation and potential bad debt accumulation. + +| Data Stream behavior | User guidance | +| :-------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Current mid price.</li><li>`marketStatus`: `2` (Market Open).</li><li>`lastUpdateTimestamp`: Current timestamp.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +--- + +## Corporate actions + +Corporate actions are events initiated by publicly traded companies that can significantly impact stock prices and trading behavior. These actions are usually announced outside regular trading hours and can cause substantial price movements when markets reopen. Users should monitor these events closely as they can lead to sudden price adjustments that may trigger unexpected liquidations or require position modifications. + +### Bankruptcy & delisting + +Bankruptcy can lead to delisting or complete loss of equity value. + +Delisting will zero out prices for the asset. + +| Data Stream behavior | User guidance | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price is available.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Closing timestamp of the last session.</li></ul> | Monitor delisting news during `marketStatus` = `1` and close markets permanently once confirmed. | + +### Spin-offs + +When a company spins off a business unit into a separate publicly traded entity, the parent company's stock may adjust accordingly, while the spun-off company's shares begin trading independently. + +Positions may need to be manually adjusted if the integrating protocol doesn't support tracking the new entity. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the first post-spin trade.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements while `marketStatus = 1`.<br/><br/>Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br/><br/>If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | + +### Stock splits & reverse splits + +<Aside type="note" title="Tokenized Stocks Guidance"> + Tokenized stocks such as [Backed xStock](/data-streams/reference/report-schema-v10) handle stock splits differently + using activation dates and staged multipliers to maintain price continuity. [Learn more about advanced stock split + handling](/data-streams/tokenized-asset-streams/handling-stock-splits). +</Aside> + +A stock split increases the number of shares while reducing the price per share (e.g., 2-for-1 split), often making shares more accessible to investors. A reverse split does the opposite, consolidating shares to increase the price per share. + +A 2-for-1 split would reduce the price by 50% from the previous trading session, any leveraged user could get liquidated. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the split-adjusted price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor spin-off and split announcements while `marketStatus = 1`.<br/><br/>Auto-pause the market if the first post-event price moves by more than X% from the prior close, update positions, then reopen.<br/><br/>If automatic adjustment isn't possible, disable leverage during the event window to prevent unfair liquidations. | + +### Mergers & acquisitions (M&A) + +If a company is being acquired, its stock price may rise to reflect the acquisition premium. The acquiring company's stock might fluctuate based on investor sentiment regarding the deal's financial and strategic impact. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Share buybacks & stock issuance + +Reduced share supply from a buyback can drive stock prices higher, while an increase in share supply can lead to price dilution. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until a new price prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | + +### Dividends + +A company's stock price typically adjusts to reflect dividend payments. For example, when a company declares a 10% dividend, its stock price often drops by a similar amount on the ex-dividend date, as new buyers are no longer entitled to that dividend. + +Announcements can cause sharp price spikes or sustained moves. + +| Data Stream behavior | User guidance | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------- | +| <ul><li>`midPrice`: Closing price is repeated until the ex-date trade prints.</li><li>`marketStatus`: `1` (Market Closed).</li><li>`lastUpdateTimestamp`: Last close.</li></ul> | Monitor liquidation thresholds closely to prevent accumulating bad debt. | diff --git a/src/content/data-streams/nav-streams/index.mdx b/src/content/data-streams/smartdata-streams/index.mdx similarity index 63% rename from src/content/data-streams/nav-streams/index.mdx rename to src/content/data-streams/smartdata-streams/index.mdx index b7943ebed18..7c9b3cd61c9 100644 --- a/src/content/data-streams/nav-streams/index.mdx +++ b/src/content/data-streams/smartdata-streams/index.mdx @@ -1,10 +1,10 @@ --- section: dataStreams -title: "Net Asset Value (NAV) Data Streams" +title: "SmartData Streams" datafeedtype: streamsNav metadata: - title: "Net Asset Value (NAV) Data Streams" - description: "A list of available Data Streams Net Asset Value streams and their ID." + title: "SmartData Streams" + description: "A list of available SmartData streams including NAV and POR feeds and their IDs." date: Last Modified isIndex: true --- diff --git a/src/content/data-streams/supported-networks.mdx b/src/content/data-streams/supported-networks.mdx index b9db36c7471..3e5404e4f45 100644 --- a/src/content/data-streams/supported-networks.mdx +++ b/src/content/data-streams/supported-networks.mdx @@ -23,7 +23,7 @@ The table below lists all networks supported by Data Streams, each with verifier ## Streams Trade implementation (Onchain Lookup) -[Streams Trade](streams-trade), the alternative implementation, allows smart contracts to access Data Streams onchain using the [`StreamsLookup`](/data-streams/getting-started) capability integrated with [Chainlink Automation](/chainlink-automation). +[Streams Trade](/data-streams/streams-trade), the alternative implementation, allows smart contracts to access Data Streams onchain using the [`StreamsLookup`](/data-streams/getting-started) capability integrated with [Chainlink Automation](/chainlink-automation). Streams Trade is currently available on the following networks: diff --git a/src/content/data-streams/tokenized-asset-streams/handling-stock-splits.mdx b/src/content/data-streams/tokenized-asset-streams/handling-stock-splits.mdx new file mode 100644 index 00000000000..9b099f83bc2 --- /dev/null +++ b/src/content/data-streams/tokenized-asset-streams/handling-stock-splits.mdx @@ -0,0 +1,108 @@ +--- +section: dataStreams +date: "Last Modified" +title: "Handling Stock Splits" +metadata: + title: "Handling Stock Splits for Tokenized Assets | Chainlink Data Streams" + description: "Learn how to handle stock splits and reverse splits for tokenized assets using Chainlink Data Streams v10 schema." +whatsnext: + { + "Find the schema of data to expect from Data Streams reports: Tokenized Asset (v10)": "/data-streams/reference/report-schema-v10", + } +--- + +import { Aside } from "@components" + +Corporate actions, such as stock splits and reverse splits, require precise handling for tokenized assets to ensure price continuity and avoid disruptions. These events alter per‑share pricing while leaving the underlying economic exposure unchanged. They can produce abrupt per‑share price moves and must be handled carefully to avoid incorrect onchain price computations and unexpected liquidations. + +In the [v10 report schema](/data-streams/reference/report-schema-v10), continuity is preserved by staging a multiplier change with a scheduled `activationDateTime` so the Theoretical Price (`price` \* `currentMultiplier`) remains continuous. Split ratios are typically known in advance, but activation may occur while markets are closed, so some external price sources may not reflect the split until trading resumes. + +<Aside type="note" title="Note"> + This guidance is designed for multiplier handling in the [v10 report + schema](/data-streams/reference/report-schema-v10) and what integrators should expect around activation windows and + protocol behavior. Similar principles may apply to future schemas that host tokenized stocks, but applicability and + exact behavior will depend on each schema's design and are not guaranteed. +</Aside> + +## Guiding principle + +Follow these principles when handling multiplier changes during corporate actions: + +1. The protocol considers the Theoretical Price as `price` \* `currentMultiplier`. +1. Ahead of the event, `newMultiplier` and `activationDateTime` are staged. +1. At `activationDateTime` (Unix), `currentMultiplier` becomes `newMultiplier`. + - The underlying `price` from traditional markets should start reflecting the split the next time trading opens, so at the next `price` update, the Theoretical Price should remain continuous. + +## Example (10:1 split, AAPL) + +The following hypothetical scenario demonstrates how a 10:1 AAPL stock split is handled through the staged multiplier system, showing the progression from announcement through protocol reopening with proper price continuity maintained throughout. + +The following timeline outlines the key events and actions taken at each stage: + +- **T-2**: [Split announcement and multiplier staging](#announcement-t-2) +- **T-1**: [Protocol preparation and monitoring setup](#protocol-engagement-t-1) +- **T0**: [Multiplier activation (split effective date)](#activation-t0) +- **T+1**: [Market reopening with adjusted prices](#market-reopening-t1) +- **T+2**: [Protocol resumption after verification](#protocol-reopening-t2) + +### Announcement (T-2) + +A 10:1 AAPL stock split is announced. [The report](/data-streams/reference/report-schema-v10) updates to stage the split: + +- `newMultiplier` is set to 10x the value of `currentMultiplier`. +- `activationDateTime` is set to the Unix timestamp of the split. +- `currentMultiplier` is unaffected until activation. + +### Protocol engagement (T-1) + +At this stage, users are advised to monitor for changes in `activationDateTime` and inspect the upcoming change to prepare appropriate action, such as preparing the protocol for a pause around the `activationDateTime` in order to ensure appropriate handling of the stock split. + +### Activation (T0) + +When the provider applies the split, [the report](/data-streams/reference/report-schema-v10) updates: + +- `newMultiplier` remains the current value. +- `activationDateTime` is set to `0`. +- `currentMultiplier` is updated to the same value as `newMultiplier`. + +<Aside type="danger" title="Important"> + If activation occurs while the underlying market is closed, prices may still show the pre‑event last trade. Do not + compute the Theoretical Price during this pre-adjustment window. Monitor `marketStatus` and keep the protocol paused + until the first post‑event trade prints and the Theoretical Price is continuous. +</Aside> + +If activation occurs while the underlying market is closed, prices may still show the pre‑event last trade. Do not compute the Theoretical Price during this pre-adjustment window. Monitor `marketStatus` and keep the protocol paused until the first post‑event trade prints and the Theoretical Price is continuous. + +### Market reopening (T1) + +The stock split has taken effect. Generally, this occurs after the market closes or over the weekend, meaning `price` may not yet reflect the new economic value per share. Upon the market reopening, `price` should start reflecting the split-adjusted value. + +### Protocol reopening (T2) + +Users should pause markets before `activationDateTime` and keep them paused until: + +- The market has reopened (monitor `marketStatus`) +- `price` has updated in line with the split ratio (e.g., 10:1) +- You have confirmed that the Theoretical Price matches expectations + +After all the above checks have been confirmed, users can unpause their protocol and continue and resume normal operation. + +## Activation-time convention + +Each tokenized asset issuer sets its own activation time. For example, the xStocks default `activationDateTime` is 00:00 UTC on the effective date. Once `activationDateTime` is reached, `currentMultiplier` becomes `newMultiplier`. + +Because underlying venues may be closed at activation, some external price sources may not reflect the split immediately. If `activationDateTime` occurs while the underlying market is closed, the report’s `currentMultiplier` will become `newMultiplier`; however, `price` can remain at the pre-event level until the market reopens. During this post-activation, pre-adjustment interval (after the multiplier has changed but before the underlying `price` updates), the Theoretical Price can be incorrect. Use `marketStatus` to pause until `price` reflects the event. + +## Integrator risk & handling + +Computing `price` \* `currentMultiplier` when the price has not adjusted (e.g., market closed) can produce large errors. It is critical to ensure that the Theoretical Price is again reflective of actual market conditions before allowing live trading. + +Treat any multiplier change (splits, dividends, etc) and `activationDateTime` as a maintenance window; pause/guard the protocol, then verify post-activation conditions before resuming. + +<Aside type="caution" title="Integrator Responsibility"> + It is the integrator's responsibility to perform proper handling and risk management. Failure to follow these best + practices may result in significant financial losses. Ensure that all multiplier changes, activation windows, and + post-activation conditions are verified before resuming operations. +</Aside> + +For broader guidance around market hours and event handling, refer to the [Market Hours](/data-streams/market-hours) guidance. diff --git a/src/content/data-streams/backed-streams/index.mdx b/src/content/data-streams/tokenized-asset-streams/index.mdx similarity index 53% rename from src/content/data-streams/backed-streams/index.mdx rename to src/content/data-streams/tokenized-asset-streams/index.mdx index c6d241037ff..54ae72c6412 100644 --- a/src/content/data-streams/backed-streams/index.mdx +++ b/src/content/data-streams/tokenized-asset-streams/index.mdx @@ -14,9 +14,11 @@ import Aside from "@components/Aside.astro" {/* prettier-ignore */} <Aside type="danger" title="Weekend Usage Disclaimer"> - **Users should not use these streams during weekends** due to limited exchange activity. + **The `price` field does not update during weekends** because the underlying real-world equity market is closed. - If usage is necessary, increase fees to mitigate risks. Developers are solely responsible for monitoring and mitigating market integrity risks, as outlined in the [Developer Responsibilities](/data-streams/developer-responsibilities) documentation. + However, the `tokenizedPrice` field continues to update as it reflects trading activity on centralized exchanges (CEXs). Weekend liquidity tends to be thin, so users should implement guardrails against unexpected volatility. + + Developers are solely responsible for monitoring and mitigating market integrity risks, as outlined in the [Developer Responsibilities](/data-streams/developer-responsibilities) documentation. </Aside> <FeedPage diff --git a/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx b/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx index a8156064cdb..7db36c88e7f 100644 --- a/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx +++ b/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx @@ -172,7 +172,7 @@ The `verifyReport` function is the core function that handles onchain report ver - Schema version `0x0003` corresponds to the [Crypto Advanced (v3)](/data-streams/reference/report-schema-v3). - Schema version `0x0008` corresponds to the [RWA Standard (v8)](/data-streams/reference/report-schema-v8). - Schema version `0x0007` corresponds to the [Redemption Rates (v7)](/data-streams/reference/report-schema-v7). - - Schema version `0x0009` corresponds to the [NAV (v9)](/data-streams/reference/report-schema-v9). + - Schema version `0x0009` corresponds to the [SmartData (v9)](/data-streams/reference/report-schema-v9). - Schema version `0x000A` corresponds to the [Tokenized Asset (v10)](/data-streams/reference/report-schema-v10). - Schema version `0x000B` corresponds to the [RWA Advanced (v11)](/data-streams/reference/report-schema-v11). - If the report version is unsupported, the function reverts with an InvalidReportVersion error. diff --git a/src/content/data-streams/tutorials/go-sdk-fetch.mdx b/src/content/data-streams/tutorials/go-sdk-fetch.mdx index 7a3163b8207..6d2d62cfdbb 100644 --- a/src/content/data-streams/tutorials/go-sdk-fetch.mdx +++ b/src/content/data-streams/tutorials/go-sdk-fetch.mdx @@ -224,7 +224,7 @@ You'll start with the set up of your Go project, installing the SDK and pasting See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. -1. Read from a [testnet crypto stream](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: +1. Read from a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: ```bash go run single-stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 @@ -404,7 +404,7 @@ You'll start with the set up of your Go project, installing the SDK and pasting export API_SECRET="<YOUR_API_SECRET>" ``` -1. Read from two [testnet crypto streams](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). For this example, you will read from the ETH/USD and LINK/USD Data Streams crypto streams. Run your application: +1. Read from two [testnet crypto streams](/data-streams/crypto-streams#testnet-crypto-streams). For this example, you will read from the ETH/USD and LINK/USD Data Streams crypto streams. Run your application: ```bash go run multiple-streams.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265 diff --git a/src/content/data-streams/tutorials/go-sdk-stream.mdx b/src/content/data-streams/tutorials/go-sdk-stream.mdx index d861dd07326..a1793c02a5e 100644 --- a/src/content/data-streams/tutorials/go-sdk-stream.mdx +++ b/src/content/data-streams/tutorials/go-sdk-stream.mdx @@ -231,7 +231,7 @@ First, you'll set up a basic Go project, installing the SDK and pasting example See the [SDK Reference](/data-streams/reference/data-streams-api/go-sdk#config-struct) page for more configuration options. -1. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: +1. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: Execute your application: diff --git a/src/content/data-streams/tutorials/rust-sdk-fetch.mdx b/src/content/data-streams/tutorials/rust-sdk-fetch.mdx index 2c5d5a6684d..3197cba6fd8 100644 --- a/src/content/data-streams/tutorials/rust-sdk-fetch.mdx +++ b/src/content/data-streams/tutorials/rust-sdk-fetch.mdx @@ -177,11 +177,11 @@ You'll start with the set up of your Rust project, installing the SDK and pastin ).build()?; ``` - This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint [for subscribing to a streamed data report](rust-sdk-stream). In this example, both are set to the testnet URLs for Data Streams. + This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint [for subscribing to a streamed data report](/data-streams/tutorials/rust-sdk-stream). In this example, both are set to the testnet URLs for Data Streams. See the [Rust SDK Reference](/data-streams/reference/data-streams-api/rust-sdk#configuration-reference) page for more configuration options. -1. Read from a [testnet crypto stream](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: +1. Read from a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: ```bash cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 diff --git a/src/content/data-streams/tutorials/rust-sdk-stream.mdx b/src/content/data-streams/tutorials/rust-sdk-stream.mdx index 47fef9f173d..3419e0b7f49 100644 --- a/src/content/data-streams/tutorials/rust-sdk-stream.mdx +++ b/src/content/data-streams/tutorials/rust-sdk-stream.mdx @@ -231,11 +231,11 @@ In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/r ).build()?; ``` - This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint [for subscribing to a streamed data report](rust-sdk-stream). In this example, both are set to the testnet URLs for Data Streams. + This configuration also specifies the `rest_url`, which is the base URL for the API, along with the WebSocket endpoint for subscribing to a streamed data report. In this example, both are set to the testnet URLs for Data Streams. See the [Rust SDK Reference](/data-streams/reference/data-streams-api/rust-sdk#configuration-reference) page for more configuration options. -1. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: +1. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: ```bash cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 diff --git a/src/content/data-streams/tutorials/ts-sdk-fetch.mdx b/src/content/data-streams/tutorials/ts-sdk-fetch.mdx index 2947743de21..fa0e31a7191 100644 --- a/src/content/data-streams/tutorials/ts-sdk-fetch.mdx +++ b/src/content/data-streams/tutorials/ts-sdk-fetch.mdx @@ -164,7 +164,7 @@ You'll start with the set up of your TypeScript project, installing the SDK and The TypeScript SDK automatically detects the report version based on the provided feed ID. </Aside> -1. Read from a [testnet crypto stream](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: +1. Read from a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, reading from the `ETH/USD` crypto stream: ```bash npx tsx singleStream.ts 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 diff --git a/src/content/data-streams/tutorials/ts-sdk-stream.mdx b/src/content/data-streams/tutorials/ts-sdk-stream.mdx index 61ef2c1b33b..0563400dc22 100644 --- a/src/content/data-streams/tutorials/ts-sdk-stream.mdx +++ b/src/content/data-streams/tutorials/ts-sdk-stream.mdx @@ -237,7 +237,7 @@ First, you'll set up a basic TypeScript project, installing the SDK and pasting accordingly. </Aside> -1. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams?page=1&testnetPage=1#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: +1. Subscribe to a [testnet crypto stream](/data-streams/crypto-streams#testnet-crypto-streams). The below example executes the application, subscribing to the `ETH/USD` crypto stream: ```bash npx tsx stream.ts 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 diff --git a/src/content/datalink/llms-full.txt b/src/content/datalink/llms-full.txt index 28ca7c36e33..e9aa0662c97 100644 --- a/src/content/datalink/llms-full.txt +++ b/src/content/datalink/llms-full.txt @@ -1177,6 +1177,227 @@ Deploy a `ClientReportsVerifier` contract on *Arbitrum Sepolia*. This contract i 1. [Open the ClientReportsVerifier.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/DataLink/ClientReportsVerifier.sol) contract in Remix. + ```sol + // SPDX-License-Identifier: MIT + pragma solidity 0.8.24; + + import {Common} from "@chainlink/contracts/src/v0.8/llo-feeds/libraries/Common.sol"; + import {IVerifierFeeManager} from "@chainlink/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierFeeManager.sol"; + import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + + using SafeERC20 for IERC20; + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE FOR DEMONSTRATION PURPOSES. + * DO NOT USE THIS CODE IN PRODUCTION. + * + * This contract can verify Chainlink DataLink reports onchain and pay + * the verification fee in LINK (when required). + * + * - If `VerifierProxy.s_feeManager()` returns a non-zero address, the network + * expects you to interact with that FeeManager for every verification call: + * quote fees, approve the RewardManager, then call `verify()`. + * + * - If `s_feeManager()` returns the zero address, no FeeManager contract has + * been deployed on that chain. In that case there is nothing to quote or pay + * onchain, so the contract skips the fee logic entirely. + * + * The `if (address(feeManager) != address(0))` check below chooses the + * correct path automatically, making the same bytecode usable on any chain. + */ + + // ──────────────────────────────────────────────────────────────────────────── + // Interfaces + // ──────────────────────────────────────────────────────────────────────────── + + interface IVerifierProxy { + /** + * @notice Route a report to the correct verifier and (optionally) bill fees. + * @param payload Full report payload (header + signed report). + * @param parameterPayload ABI-encoded fee metadata. + */ + function verify( + bytes calldata payload, + bytes calldata parameterPayload + ) external payable returns (bytes memory verifierResponse); + + function verifyBulk( + bytes[] calldata payloads, + bytes calldata parameterPayload + ) external payable returns (bytes[] memory verifiedReports); + + function s_feeManager() external view returns (IVerifierFeeManager); + } + + interface IFeeManager { + /** + * @return fee, reward, totalDiscount + */ + function getFeeAndReward( + address subscriber, + bytes memory unverifiedReport, + address quoteAddress + ) external returns (Common.Asset memory, Common.Asset memory, uint256); + + function i_linkAddress() external view returns (address); + + function i_nativeAddress() external view returns (address); + + function i_rewardManager() external view returns (address); + } + + // ──────────────────────────────────────────────────────────────────────────── + // Contract + // ──────────────────────────────────────────────────────────────────────────── + + /** + * @dev This contract implements functionality to verify DataLink reports from + * the API, with payment in LINK tokens. + */ + contract ClientReportsVerifier { + // ----------------- Errors ----------------- + error NothingToWithdraw(); + error NotOwner(address caller); + error InvalidReportVersion(uint16 version); + + // ----------------- Report schemas ----------------- + // Extract schema version from feed ID (first 2 bytes of the feed ID) + /** + * @dev DataLink report schema v3. + * Prices, bids and asks use 8 or 18 decimals depending on the feed. + */ + struct ReportV3 { + bytes32 feedId; + uint32 validFromTimestamp; + uint32 observationsTimestamp; + uint192 nativeFee; + uint192 linkFee; + uint32 expiresAt; + int192 price; + int192 bid; + int192 ask; + } + + /** + * @dev DataLink report schema v4. + */ + struct ReportV4 { + bytes32 feedId; + uint32 validFromTimestamp; + uint32 observationsTimestamp; + uint192 nativeFee; + uint192 linkFee; + uint32 expiresAt; + int192 price; + uint32 marketStatus; + } + + // ----------------- Storage ----------------- + IVerifierProxy public immutable i_verifierProxy; + address private immutable i_owner; + + int192 public lastDecodedPrice; + + // ----------------- Events ----------------- + event DecodedPrice(int192 price); + + // ----------------- Constructor / modifier ----------------- + /** + * @param _verifierProxy Address of the VerifierProxy on the target network. + * Addresses: https://docs.chain.link/datalink/pull-delivery/verifier-proxy-addresses + */ + constructor( + address _verifierProxy + ) { + i_owner = msg.sender; + i_verifierProxy = IVerifierProxy(_verifierProxy); + } + + modifier onlyOwner() { + if (msg.sender != i_owner) revert NotOwner(msg.sender); + _; + } + + // ----------------- Public API ----------------- + + /** + * @notice Verify a DataLink report (schema v3 or v4). + * + * @dev Steps: + * 1. Decode the unverified report to get `reportData`. + * 2. Read the first two bytes → schema version (`0x0003` or `0x0004`). + * - Revert if the version is unsupported. + * 3. Fee handling: + * - Query `s_feeManager()` on the proxy. + * – Non-zero → quote the fee, approve the RewardManager, + * ABI-encode the fee token address for `verify()`. + * – Zero → no FeeManager; skip quoting/approval and pass `""`. + * 4. Call `VerifierProxy.verify()`. + * 5. Decode the verified report into the correct struct and emit the price. + * + * @param unverifiedReport Full payload returned. + * @custom:reverts InvalidReportVersion when schema ≠ v3/v4. + */ + function verifyReport( + bytes memory unverifiedReport + ) external { + // ─── 1. & 2. Extract reportData and schema version ── + (, bytes memory reportData) = abi.decode(unverifiedReport, (bytes32[3], bytes)); + + uint16 reportVersion = (uint16(uint8(reportData[0])) << 8) | uint16(uint8(reportData[1])); + if (reportVersion != 3 && reportVersion != 4) { + revert InvalidReportVersion(reportVersion); + } + + // ─── 3. Fee handling ── + IFeeManager feeManager = IFeeManager(address(i_verifierProxy.s_feeManager())); + + bytes memory parameterPayload; + if (address(feeManager) != address(0)) { + // FeeManager exists — always quote & approve + address feeToken = feeManager.i_linkAddress(); + + (Common.Asset memory fee,,) = feeManager.getFeeAndReward(address(this), reportData, feeToken); + + IERC20(feeToken).approve(feeManager.i_rewardManager(), fee.amount); + parameterPayload = abi.encode(feeToken); + } else { + // No FeeManager deployed on this chain + parameterPayload = bytes(""); + } + + // ─── 4. Verify through the proxy ── + bytes memory verified = i_verifierProxy.verify(unverifiedReport, parameterPayload); + + // ─── 5. Decode & store price ── + if (reportVersion == 3) { + int192 price = abi.decode(verified, (ReportV3)).price; + lastDecodedPrice = price; + emit DecodedPrice(price); + } else { + int192 price = abi.decode(verified, (ReportV4)).price; + lastDecodedPrice = price; + emit DecodedPrice(price); + } + } + + /** + * @notice Withdraw all balance of an ERC-20 token held by this contract. + * @param _beneficiary Address that receives the tokens. + * @param _token ERC-20 token address. + */ + function withdrawToken( + address _beneficiary, + address _token + ) external onlyOwner { + uint256 amount = IERC20(_token).balanceOf(address(this)); + if (amount == 0) revert NothingToWithdraw(); + IERC20(_token).safeTransfer(_beneficiary, amount); + } + } + ``` + 2. Select the `ClientReportsVerifier.sol` contract in the **Solidity Compiler** tab. 3. Compile the contract. @@ -1222,6 +1443,227 @@ For this tutorial on *Arbitrum Sepolia*, fees are required, so you need to fund The example code you deployed has all the interfaces and functions required to verify DataLink reports onchain. +```sol +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {Common} from "@chainlink/contracts/src/v0.8/llo-feeds/libraries/Common.sol"; +import {IVerifierFeeManager} from "@chainlink/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierFeeManager.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +using SafeERC20 for IERC20; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE FOR DEMONSTRATION PURPOSES. + * DO NOT USE THIS CODE IN PRODUCTION. + * + * This contract can verify Chainlink DataLink reports onchain and pay + * the verification fee in LINK (when required). + * + * - If `VerifierProxy.s_feeManager()` returns a non-zero address, the network + * expects you to interact with that FeeManager for every verification call: + * quote fees, approve the RewardManager, then call `verify()`. + * + * - If `s_feeManager()` returns the zero address, no FeeManager contract has + * been deployed on that chain. In that case there is nothing to quote or pay + * onchain, so the contract skips the fee logic entirely. + * + * The `if (address(feeManager) != address(0))` check below chooses the + * correct path automatically, making the same bytecode usable on any chain. + */ + +// ──────────────────────────────────────────────────────────────────────────── +// Interfaces +// ──────────────────────────────────────────────────────────────────────────── + +interface IVerifierProxy { + /** + * @notice Route a report to the correct verifier and (optionally) bill fees. + * @param payload Full report payload (header + signed report). + * @param parameterPayload ABI-encoded fee metadata. + */ + function verify( + bytes calldata payload, + bytes calldata parameterPayload + ) external payable returns (bytes memory verifierResponse); + + function verifyBulk( + bytes[] calldata payloads, + bytes calldata parameterPayload + ) external payable returns (bytes[] memory verifiedReports); + + function s_feeManager() external view returns (IVerifierFeeManager); +} + +interface IFeeManager { + /** + * @return fee, reward, totalDiscount + */ + function getFeeAndReward( + address subscriber, + bytes memory unverifiedReport, + address quoteAddress + ) external returns (Common.Asset memory, Common.Asset memory, uint256); + + function i_linkAddress() external view returns (address); + + function i_nativeAddress() external view returns (address); + + function i_rewardManager() external view returns (address); +} + +// ──────────────────────────────────────────────────────────────────────────── +// Contract +// ──────────────────────────────────────────────────────────────────────────── + +/** + * @dev This contract implements functionality to verify DataLink reports from + * the API, with payment in LINK tokens. + */ +contract ClientReportsVerifier { + // ----------------- Errors ----------------- + error NothingToWithdraw(); + error NotOwner(address caller); + error InvalidReportVersion(uint16 version); + + // ----------------- Report schemas ----------------- + // Extract schema version from feed ID (first 2 bytes of the feed ID) + /** + * @dev DataLink report schema v3. + * Prices, bids and asks use 8 or 18 decimals depending on the feed. + */ + struct ReportV3 { + bytes32 feedId; + uint32 validFromTimestamp; + uint32 observationsTimestamp; + uint192 nativeFee; + uint192 linkFee; + uint32 expiresAt; + int192 price; + int192 bid; + int192 ask; + } + + /** + * @dev DataLink report schema v4. + */ + struct ReportV4 { + bytes32 feedId; + uint32 validFromTimestamp; + uint32 observationsTimestamp; + uint192 nativeFee; + uint192 linkFee; + uint32 expiresAt; + int192 price; + uint32 marketStatus; + } + + // ----------------- Storage ----------------- + IVerifierProxy public immutable i_verifierProxy; + address private immutable i_owner; + + int192 public lastDecodedPrice; + + // ----------------- Events ----------------- + event DecodedPrice(int192 price); + + // ----------------- Constructor / modifier ----------------- + /** + * @param _verifierProxy Address of the VerifierProxy on the target network. + * Addresses: https://docs.chain.link/datalink/pull-delivery/verifier-proxy-addresses + */ + constructor( + address _verifierProxy + ) { + i_owner = msg.sender; + i_verifierProxy = IVerifierProxy(_verifierProxy); + } + + modifier onlyOwner() { + if (msg.sender != i_owner) revert NotOwner(msg.sender); + _; + } + + // ----------------- Public API ----------------- + + /** + * @notice Verify a DataLink report (schema v3 or v4). + * + * @dev Steps: + * 1. Decode the unverified report to get `reportData`. + * 2. Read the first two bytes → schema version (`0x0003` or `0x0004`). + * - Revert if the version is unsupported. + * 3. Fee handling: + * - Query `s_feeManager()` on the proxy. + * – Non-zero → quote the fee, approve the RewardManager, + * ABI-encode the fee token address for `verify()`. + * – Zero → no FeeManager; skip quoting/approval and pass `""`. + * 4. Call `VerifierProxy.verify()`. + * 5. Decode the verified report into the correct struct and emit the price. + * + * @param unverifiedReport Full payload returned. + * @custom:reverts InvalidReportVersion when schema ≠ v3/v4. + */ + function verifyReport( + bytes memory unverifiedReport + ) external { + // ─── 1. & 2. Extract reportData and schema version ── + (, bytes memory reportData) = abi.decode(unverifiedReport, (bytes32[3], bytes)); + + uint16 reportVersion = (uint16(uint8(reportData[0])) << 8) | uint16(uint8(reportData[1])); + if (reportVersion != 3 && reportVersion != 4) { + revert InvalidReportVersion(reportVersion); + } + + // ─── 3. Fee handling ── + IFeeManager feeManager = IFeeManager(address(i_verifierProxy.s_feeManager())); + + bytes memory parameterPayload; + if (address(feeManager) != address(0)) { + // FeeManager exists — always quote & approve + address feeToken = feeManager.i_linkAddress(); + + (Common.Asset memory fee,,) = feeManager.getFeeAndReward(address(this), reportData, feeToken); + + IERC20(feeToken).approve(feeManager.i_rewardManager(), fee.amount); + parameterPayload = abi.encode(feeToken); + } else { + // No FeeManager deployed on this chain + parameterPayload = bytes(""); + } + + // ─── 4. Verify through the proxy ── + bytes memory verified = i_verifierProxy.verify(unverifiedReport, parameterPayload); + + // ─── 5. Decode & store price ── + if (reportVersion == 3) { + int192 price = abi.decode(verified, (ReportV3)).price; + lastDecodedPrice = price; + emit DecodedPrice(price); + } else { + int192 price = abi.decode(verified, (ReportV4)).price; + lastDecodedPrice = price; + emit DecodedPrice(price); + } + } + + /** + * @notice Withdraw all balance of an ERC-20 token held by this contract. + * @param _beneficiary Address that receives the tokens. + * @param _token ERC-20 token address. + */ + function withdrawToken( + address _beneficiary, + address _token + ) external onlyOwner { + uint256 amount = IERC20(_token).balanceOf(address(this)); + if (amount == 0) revert NothingToWithdraw(); + IERC20(_token).safeTransfer(_beneficiary, amount); + } +} +``` + ### Initializing the contract When deploying the contract, you define the verifier proxy address for the feed you want to read from. You can find this address on the [Verifier Proxy Addresses](/datalink/pull-delivery/verifier-proxy-addresses) page. The verifier proxy address provides functions that are required for this example: diff --git a/src/content/getting-started/llms-full.txt b/src/content/getting-started/llms-full.txt index efe408fcceb..19d0a8d9ba2 100644 --- a/src/content/getting-started/llms-full.txt +++ b/src/content/getting-started/llms-full.txt @@ -29,6 +29,32 @@ Some networks are not EVM-compatible and use languages other than Solidity for s The structure of a smart contract is similar to that of a class in Javascript, with a few differences. For example, the following `HelloWorld` contract is a simple smart contract that stores a single variable and includes a function to update the value of that variable. +```sol +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.7; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract HelloWorld { + string public message; + + constructor( + string memory initialMessage + ) { + message = initialMessage; + } + + function updateMessage( + string memory newMessage + ) public { + message = newMessage; + } +} +``` + ### Solidity versions The first thing that every Solidity file must have is the Solidity version definition. The `HelloWorld.sol` contract uses version `0.8.7`, which is defined in the contract as `pragma solidity 0.8.7;` @@ -102,6 +128,38 @@ Functions use visibility modifiers to define the access level. Learn more about An **interface** is another concept that is familiar to programmers of other languages. Interfaces define functions without their implementation, which leaves inheriting contracts to define the actual implementation themselves. This makes it easier to know what functions to call in a contract. Here's an example of an interface: +```sol +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.7; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +interface numberComparison { + function isSameNum( + uint256 a, + uint256 b + ) external view returns (bool); +} + +contract Test is numberComparison { + constructor() {} + + function isSameNum( + uint256 a, + uint256 b + ) external pure override returns (bool) { + if (a == b) { + return true; + } else { + return false; + } + } +} +``` + For this example, `override` is necessary in the `Test` contract function because it overrides the base function contained in the `numberComparison` interface. The contract uses `pure` instead of `view` because the `isSameNum` function in the `Test` contract does not return a storage variable. ## What does "deploying" mean? diff --git a/src/content/quickstarts/automated-portfolio-manager.mdx b/src/content/quickstarts/automated-portfolio-manager.mdx index 26a7cac21df..5425f619624 100644 --- a/src/content/quickstarts/automated-portfolio-manager.mdx +++ b/src/content/quickstarts/automated-portfolio-manager.mdx @@ -7,16 +7,19 @@ image: "QuickStarts-AutomatedPortfolioManager.webp" products: ["Feeds", "Automation", "Functions"] time: "45 minutes" datePublished: "2024-09-18" -lastModified: "2025-06-17" +lastModified: "2026-01-16" difficulty: "intermediate" --- import { Accordion, Aside, CodeSample, ClickToZoom } from "@components" -<Aside type="note" title="Note on a Forthcoming Update"> - We are currently performing maintenance on this quickstart. As part of this update, we will also be replacing a data - endpoint that is temporarily unavailable. A fully updated version will be released shortly. Thank you for your - patience! +<Aside type="caution" title="Deprecated Quickstart"> + **This quickstart is deprecated and no longer maintained.** The GVZ index API used in this tutorial is no longer + available, which means this example will not work as written. We've kept this content available for educational + reference only. **For new projects**, we strongly recommend using the [Chainlink Runtime Environment (CRE)](/cre), + which makes building applications like automated portfolio managers significantly easier. CRE provides a unified + environment for combining offchain data, onchain operations, and computation—all with built-in orchestration and + blockchain-level security. Learn more: [Getting Started with CRE](/cre/getting-started/overview) </Aside> ## Overview diff --git a/src/content/quickstarts/vrf-enabled-lootbox-pack.mdx b/src/content/quickstarts/vrf-enabled-lootbox-pack.mdx index bb059ad6251..f11d0c1dc05 100644 --- a/src/content/quickstarts/vrf-enabled-lootbox-pack.mdx +++ b/src/content/quickstarts/vrf-enabled-lootbox-pack.mdx @@ -62,7 +62,7 @@ Your _deployer account_ is the main account that you will use to deploy the loot - Ensure the deployer account owns all the assets you wish to distribute as rewards. - To deploy this contract on testnets, ensure the deployer account has testnet LINK and testnet ETH (Sepolia). Use the [LINK faucet](https://faucets.chain.link/) to retrieve 20 testnet LINK and 0.1 Sepolia ETH. - Ensure the deployer account has enough LINK to fund the [VRF subscription](/vrf/v2/subscription). If you don't already have a VRF subscription, the deployment script will create and fund one for you. - - [Estimate the minimum subscription balance](/vrf/v2/estimating-costs#estimate-minimum-subscription-balance) that VRF requires to process your randomness request. The minimum subscription balance provides a buffer against gas volatility, and only the actual cost of your request will be deducted from your account. If your subscription is underfunded, your VRF request will be [pending](/vrf/v2/subscription/ui#pending) for 24 hours. If that happens, check the [Subscription Manager](https://vrf.chain.link]) to see the additional balance needed. + - [Estimate the minimum subscription balance](/vrf/v2/estimating-costs#estimate-minimum-subscription-balance) that VRF requires to process your randomness request. The minimum subscription balance provides a buffer against gas volatility, and only the actual cost of your request will be deducted from your account. If your subscription is underfunded, your VRF request will be [pending](/vrf/v2/subscription/ui#pending) for 24 hours. If that happens, check the [Subscription Manager](https://vrf.chain.link) to see the additional balance needed. - The initial funding amount is set to 10 LINK. Optionally, you can modify the initial funding amount in [`network-config.ts`](https://github.com/smartcontractkit/quickstarts-lootbox/blob/main/network-config.ts). - [Create a second account in your MetaMask wallet](https://support.metamask.io/hc/en-us/articles/360015289452-How-to-create-an-additional-account-in-your-wallet). This account is called the _receiving account_ in this tutorial, and its address is called the _opener address_. You will use this receiving account to open a test lootbox and receive the rewards as a user. [Configure the account](https://support.metamask.io/hc/en-us/articles/360015489031-How-to-display-tokens-in-MetaMask) to display the rewards that you want to distribute from the lootbox. @@ -236,7 +236,7 @@ The [deploy script](https://github.com/smartcontractkit/quickstarts-lootbox/blob [Estimate the minimum subscription balance](/vrf/v2/estimating-costs#estimate-minimum-subscription-balance) that VRF requires to process your randomness request. The minimum subscription balance provides a buffer against gas volatility, and only the actual cost of your request will be deducted from your account. - If your subscription is underfunded, your VRF request will be [pending](/vrf/v2/subscription/ui#pending) for 24 hours. If this happens, check the [Subscription Manager](https://vrf.chain.link]) to see the additional balance needed. + If your subscription is underfunded, your VRF request will be [pending](/vrf/v2/subscription/ui#pending) for 24 hours. If this happens, check the [Subscription Manager](https://vrf.chain.link) to see the additional balance needed. </Aside> diff --git a/src/content/resources/contributing-to-chainlink.mdx b/src/content/resources/contributing-to-chainlink.mdx index 952c5214272..b7537ca3581 100644 --- a/src/content/resources/contributing-to-chainlink.mdx +++ b/src/content/resources/contributing-to-chainlink.mdx @@ -123,9 +123,3 @@ If you're interested in running an in-person meetup or watch party, [reach out t Chainlink runs hackathons multiple times per year and often sponsors other hackathons across the blockchain ecosystem. Participating in a hackathon that Chainlink is a part of is a great way to learn how to use Chainlink. It is also a great way to showcase your skills to the Chainlink team and the wider community. Hackathons are a popular place for recruiting talent into the blockchain ecosystem. To stay up to date on the hackathons that Chainlink is running or sponsoring, keep an eye out on the official Chainlink social media channels, and sign up for our [developer newsletter](/resources/developer-communications). - -## Applying for a grant - -The [Chainlink grant program](https://chain.link/community/grants) encourages development of critical developer tooling, add high-quality data, and the launch key services around the Chainlink Network. Grant categories include community, integration, bug bounty, research, and social impact grants. If you have a great idea that fits into one of these categories, you can apply for a grant. If successful, you will receive the funding and support needed to successfully build and implement your idea. - -For more information about the grant program, go to the [Chainlink Grants web page](https://chain.link/community/grants). diff --git a/src/content/resources/hackathon-resources.mdx b/src/content/resources/hackathon-resources.mdx index ee7b09830df..15db5dd352e 100644 --- a/src/content/resources/hackathon-resources.mdx +++ b/src/content/resources/hackathon-resources.mdx @@ -57,7 +57,7 @@ If you are new to Smart Contracts, read the [Getting Started Guide](/getting-sta ### BUILD projects - [Source Network](https://source.network/) -- [Thirdfi](https://www.thirdfi.org/) +- [Thirdfi](https://data.thirdfi.org/) ## Join the community diff --git a/src/content/resources/link-token-contracts.mdx b/src/content/resources/link-token-contracts.mdx index 066e6cfeb7b..0e2f91a5367 100644 --- a/src/content/resources/link-token-contracts.mdx +++ b/src/content/resources/link-token-contracts.mdx @@ -128,6 +128,18 @@ Testnet ETH and LINK are available at [faucets.chain.link/arbitrum-sepolia](http | Decimals | 18 | | Network status | [arbiscan.freshstatus.io](https://arbiscan.freshstatus.io/) | +## <img src="/assets/chains/arc.svg" style="height: 24px; width: auto; margin-right: 8px;" />Arc Network + +### Arc Network Testnet + +| Parameter | Value | +| :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `5042002` | +| Address | <Address contractUrl="https://testnet.arcscan.app/address/0x3F1f176e347235858DD6Db905DDBA09Eaf25478a" urlId="5042002_0x3F1f176e347235858DD6Db905DDBA09Eaf25478a" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Arc Network Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/astar.svg" style="height: 24px; width: auto; margin-right: 8px;" />Astar ### Astar Mainnet @@ -270,13 +282,13 @@ Testnet LINK are available at [faucets.chain.link/bitlayer-testnet](https://fauc ### Bittensor EVM Mainnet -| Parameter | Value | -| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Chain ID | `964` | -| Address | <Address contractUrl="https://taostats.io//address/0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13" urlId="964_0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13" urlClass="erc-token-address"/> | -| Name | Chainlink Token on Bittensor EVM Mainnet | -| Symbol | LINK | -| Decimals | 18 | +| Parameter | Value | +| :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `964` | +| Address | <Address contractUrl="https://taostats.io/address/0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13" urlId="964_0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Bittensor EVM Mainnet | +| Symbol | LINK | +| Decimals | 18 | ## <img src="/assets/chains/blast.svg" style="height: 24px; width: auto; margin-right: 8px;" />Blast @@ -535,6 +547,18 @@ Testnet Native and LINK is available at [faucets.chain.link/corn-testnet](https: | Symbol | LINK | | Decimals | 18 | +## <img src="/assets/chains/dogeos.svg" style="height: 24px; width: auto; margin-right: 8px;" />DogeOS + +### DogeOS Chikyu Testnet + +| Parameter | Value | +| :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `6281971` | +| Address | <Address contractUrl="https://blockscout.testnet.dogeos.com/address/0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlId="6281971_0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlClass="erc-token-address"/> | +| Name | Chainlink Token on DogeOS Chikyu Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/ethereum.svg" style="height: 24px; width: auto; margin-right: 8px;" />Ethereum ### Ethereum Mainnet @@ -580,6 +604,21 @@ Testnet ETH and LINK are available at [faucets.chain.link/holesky](https://fauce | Decimals | 18 | | Network status | [etherscan.freshstatus.io](https://etherscan.freshstatus.io/) | +### Ethereum Hoodi Testnet + +Testnet ETH is used to pay for transactions on Hoodi. + +Testnet ETH and LINK are available at [faucets.chain.link/hoodi](https://faucets.chain.link/hoodi). + +| Parameter | Value | +| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Chain ID | `560048` | +| Address | <Address contractUrl="https://hoodi.etherscan.io/token/0x76c00B055414de203B79B4955E28119BF459033e" urlId="560048_0x76c00B055414de203B79B4955E28119BF459033e" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Ethereum Hoodi Testnet | +| Symbol | LINK | +| Decimals | 18 | +| Network status | [etherscan.freshstatus.io](https://etherscan.freshstatus.io/) | + ## <img src="/assets/chains/etherlink.svg" style="height: 24px; width: auto; margin-right: 8px;" />Etherlink ### Etherlink Mainnet @@ -770,6 +809,18 @@ Testnet Native and LINK is available at [faucets.chain.link/hedera-testnet](http | Symbol | LINK | | Decimals | 18 | +## <img src="/assets/chains/henesys.svg" style="height: 24px; width: auto; margin-right: 8px;" />Henesys + +### Henesys Mainnet + +| Parameter | Value | +| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `68414` | +| Address | <Address contractUrl="https://subnets.avax.network/henesys/address/0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlId="68414_0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Nexon Henesys Mainnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/hyperliquid.svg" style="height: 24px; width: auto; margin-right: 8px;" />HyperEVM ### HyperEVM Mainnet @@ -826,6 +877,28 @@ Testnet Native and LINK is available at [faucets.chain.link/hedera-testnet](http | Symbol | LINK | | Decimals | 18 | +## <img src="/assets/chains/jovay.svg" style="height: 24px; width: auto; margin-right: 8px;" />Jovay + +### Jovay Mainnet + +| Parameter | Value | +| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `5734951` | +| Address | <Address contractUrl="https://explorer.jovay.io/l2/address/0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlId="5734951_0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Jovay Mainnet | +| Symbol | LINK | +| Decimals | 18 | + +### Jovay Sepolia Testnet + +| Parameter | Value | +| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `2019775` | +| Address | <Address contractUrl="https://sepolia-explorer.jovay.io/l2/address/0xd3e461C55676B10634a5F81b747c324B85686Dd1" urlId="2019775_0xd3e461C55676B10634a5F81b747c324B85686Dd1" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Jovay Sepolia Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/kaia.svg" style="height: 24px; width: auto; margin-right: 8px;" />Kaia ### Kaia Mainnet @@ -866,8 +939,6 @@ ETH is used to pay for transactions on the Kroma mainnet. Testnet ETH is used to pay for transactions on the Kroma testnet. -Testnet Native and LINK are available at [faucets.chain.link/kroma-testnet](https://faucets.chain.link/kroma-testnet). - | Parameter | Value | | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ETH_CHAIN_ID` | `2358` | @@ -998,15 +1069,25 @@ Testnet Native and LINK are available at [faucets.chain.link/mantle-sepolia](htt | Symbol | LINK | | Decimals | 18 | -## <img src="/assets/chains/megaeth.svg" style="height: 24px; width: auto; margin-right: 8px;" />MegaEth +## <img src="/assets/chains/megaeth.svg" style="height: 24px; width: auto; margin-right: 8px;" />MegaETH -### MegaEth Testnet +### MegaETH Mainnet + +| Parameter | Value | +| :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `4326` | +| Address | <Address contractUrl="https://megaeth.blockscout.com/address/0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae" urlId="4326_0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae" urlClass="erc-token-address"/> | +| Name | Chainlink Token on MegaETH Mainnet | +| Symbol | LINK | +| Decimals | 18 | + +### MegaETH Testnet | Parameter | Value | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Chain ID | `6342` | | Address | <Address contractUrl="https://megaexplorer.xyz/address/0x4d03398C2588D92B220578dAEde29814E41c8033" urlId="6342_0x4d03398C2588D92B220578dAEde29814E41c8033" urlClass="erc-token-address"/> | -| Name | Chainlink Token | +| Name | Chainlink Token on MegaETH Testnet | | Symbol | LINK | | Decimals | 18 | @@ -1213,6 +1294,28 @@ MOVR is used to pay transaction fees on Moonriver Mainnet. | Decimals | 18 | | Network status | [moonscan.freshstatus.io](https://moonscan.freshstatus.io/) | +## <img src="/assets/chains/morph.svg" style="height: 24px; width: auto; margin-right: 8px;" />Morph + +### Morph Mainnet + +| Parameter | Value | +| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `2818` | +| Address | <Address contractUrl="https://explorer.morphl2.io/address/0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlId="2818_0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Morph Mainnet | +| Symbol | LINK | +| Decimals | 18 | + +### Morph Hoodi Testnet + +| Parameter | Value | +| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `2910` | +| Address | <Address contractUrl="https://explorer-hoodi.morphl2.io/address/0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlId="2910_0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Morph Hoodi Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/neox.svg" style="height: 24px; width: auto; margin-right: 8px;" />Neo X ### Neo X Mainnet @@ -1235,18 +1338,6 @@ MOVR is used to pay transaction fees on Moonriver Mainnet. | Symbol | LINK | | Decimals | 18 | -## <img src="/assets/chains/henesys.svg" style="height: 24px; width: auto; margin-right: 8px;" />Henesys - -### Henesys Mainnet - -| Parameter | Value | -| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Chain ID | `68414` | -| Address | <Address contractUrl="https://subnets.avax.network/henesys/address/0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlId="68414_0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlClass="erc-token-address"/> | -| Name | Chainlink Token on Nexon Henesys Mainnet | -| Symbol | LINK | -| Decimals | 18 | - ## <img src="/assets/chains/opbnb.svg" style="height: 24px; width: auto; margin-right: 8px;" />OPBNB ### OPBNB Mainnet @@ -1648,17 +1739,29 @@ S is used to pay for transactions on Sonic mainnet. | Symbol | LINK | | Decimals | 18 | -### Sonic Blaze Testnet +### Sonic Testnet -Testnet S is used to pay for transactions on Sonic Blaze testnet. +Testnet S is used to pay for transactions on Sonic Testnet. -| Parameter | Value | -| :------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ETH_CHAIN_ID` | `57054` | -| Address | <Address contractUrl="https://testnet.sonicscan.org/address/0xd8C1eEE32341240A62eC8BC9988320bcC13c8580" urlId="57054_0xd8C1eEE32341240A62eC8BC9988320bcC13c8580" urlClass="erc-token-address"/> | -| Name | Chainlink Token on Sonice Blaze Testnet | -| Symbol | LINK | -| Decimals | 18 | +| Parameter | Value | +| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ETH_CHAIN_ID` | `14601` | +| Address | <Address contractUrl="https://explorer.testnet.soniclabs.com/address/0x19e696e75ccbB3155EEbB579BFa555Fab22293bA" urlId="14601_0x19e696e75ccbB3155EEbB579BFa555Fab22293bA" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Sonic Testnet | +| Symbol | LINK | +| Decimals | 18 | + +## <img src="/assets/chains/stable.svg" style="height: 24px; width: auto; margin-right: 8px;" />Stable + +### Stable Mainnet + +| Parameter | Value | +| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `988` | +| Address | <Address contractUrl="https://stablescan.xyz/address/0x985FB0821Eef0056ec26DD8b33dC61b9415B7F4b" urlId="988_0x985FB0821Eef0056ec26DD8b33dC61b9415B7F4b" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Stable Mainnet | +| Symbol | LINK | +| Decimals | 18 | ## <img src="/assets/chains/starknet.svg" style="height: 24px; width: auto; margin-right: 8px;" />Starknet @@ -1738,6 +1841,18 @@ Testnet S is used to pay for transactions on Sonic Blaze testnet. | Symbol | LINK | | Decimals | 18 | +## <img src="/assets/chains/tempo.svg" style="height: 24px; width: auto; margin-right: 8px;" />Tempo + +### Tempo Testnet + +| Parameter | Value | +| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Chain ID | `42429` | +| Address | <Address contractUrl="https://explore.tempo.xyz/address/0x384C8843411f725e800E625d5d1B659256D629dF" urlId="42429_0x384C8843411f725e800E625d5d1B659256D629dF" urlClass="erc-token-address"/> | +| Name | Chainlink Token on Tempo Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/treasure.svg" style="height: 24px; width: auto; margin-right: 8px;" />Treasure ### Treasure Mainnet @@ -1812,7 +1927,7 @@ Testnet Native and LINK are available at [faucets.chain.link/wemix-testnet](http | Symbol | LINK | | Decimals | 18 | -## <img src="/assets/chains/worldchain.svg" style="height: 24px; width: auto; margin-right: 8px;" />World +## <img src="/assets/chains/worldchain.svg" style="height: 24px; width: auto; margin-right: 8px;" />World Chain ### World Chain Mainnet @@ -1874,15 +1989,15 @@ Testnet ETH is used to pay for transactions on World Chain Sepolia. Testnet Nati | Symbol | LINK | | Decimals | 18 | -### X Layer Sepolia Testnet +### X Layer Testnet -| Parameter | Value | -| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Chain ID | `195` | -| Address | <Address contractUrl="https://www.oklink.com/xlayer-test/address/0x724593f6FCb0De4E6902d4C55D7C74DaA2AF0E55" urlId="195_0x724593f6FCb0De4E6902d4C55D7C74DaA2AF0E55" urlClass="erc-token-address"/> | -| Name | Chainlink Token on X Layer Sepolia Testnet | -| Symbol | LINK | -| Decimals | 18 | +| Parameter | Value | +| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `1952` | +| Address | <Address contractUrl="https://web3.okx.com/explorer/x-layer-testnet/address/0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlId="1952_0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlClass="erc-token-address"/> | +| Name | Chainlink Token on X Layer Testnet | +| Symbol | LINK | +| Decimals | 18 | ## <img src="/assets/chains/zircuit.svg" style="height: 24px; width: auto; margin-right: 8px;" />Zircuit @@ -1902,8 +2017,6 @@ ETH is used to pay for transactions on the Zircuit mainnet. Testnet ETH is used to pay for transactions on the Zircuit testnet. -Testnet Native and LINK are available at [faucets.chain.link/zircuit-sepolia](https://faucets.chain.link/zircuit-sepolia). - | Parameter | Value | | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ETH_CHAIN_ID` | `48899` | @@ -1916,7 +2029,7 @@ Testnet Native and LINK are available at [faucets.chain.link/zircuit-sepolia](ht ### ZKsync Era Mainnet -ETH is used to pay for transactions on ZKsync Era Mainnet. Use the recommended [ZKsync Bridges](https://zksync.io/explore#bridges) to transfer ETH from Ethereum to ZKsync. +ETH is used to pay for transactions on ZKsync Era Mainnet. Use the recommended [ZKsync Bridges](https://docs.zksync.io/zksync-network/zksync-era/ecosystem/bridges) to transfer ETH from Ethereum to ZKsync. | Parameter | Value | | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/src/content/resources/llms-full.txt b/src/content/resources/llms-full.txt index e039241fa49..e657d295f0c 100644 --- a/src/content/resources/llms-full.txt +++ b/src/content/resources/llms-full.txt @@ -285,12 +285,6 @@ Chainlink runs hackathons multiple times per year and often sponsors other hacka To stay up to date on the hackathons that Chainlink is running or sponsoring, keep an eye out on the official Chainlink social media channels, and sign up for our [developer newsletter](/resources/developer-communications). -## Applying for a grant - -The [Chainlink grant program](https://chain.link/community/grants) encourages development of critical developer tooling, add high-quality data, and the launch key services around the Chainlink Network. Grant categories include community, integration, bug bounty, research, and social impact grants. If you have a great idea that fits into one of these categories, you can apply for a grant. If successful, you will receive the funding and support needed to successfully build and implement your idea. - -For more information about the grant program, go to the [Chainlink Grants web page](https://chain.link/community/grants). - --- # Install Frameworks @@ -697,7 +691,7 @@ If you are new to Smart Contracts, read the [Getting Started Guide](/getting-sta ### BUILD projects - [Source Network](https://source.network/) -- [Thirdfi](https://www.thirdfi.org/) +- [Thirdfi](https://data.thirdfi.org/) ## Join the community @@ -892,6 +886,18 @@ Testnet ETH and LINK are available at [faucets.chain.link/arbitrum-sepolia](http | Decimals | 18 | | Network status | [arbiscan.freshstatus.io](https://arbiscan.freshstatus.io/) | +## <img src="/assets/chains/arc.svg" style="height: 24px; width: auto; margin-right: 8px;" />Arc Network + +### Arc Network Testnet + +| Parameter | Value | +| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `5042002` | +| Address | <Address contractUrl="https://testnet.arcscan.app/address/0x3F1f176e347235858DD6Db905DDBA09Eaf25478a" urlId="5042002_0x3F1f176e347235858DD6Db905DDBA09Eaf25478a" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Arc Network Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/astar.svg" style="height: 24px; width: auto; margin-right: 8px;" />Astar ### Astar Mainnet @@ -1034,13 +1040,13 @@ Testnet LINK are available at [faucets.chain.link/bitlayer-testnet](https://fauc ### Bittensor EVM Mainnet -| Parameter | Value | -| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Chain ID | `964` | -| Address | <Address contractUrl="https://taostats.io//address/0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13" urlId="964_0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13" urlClass="erc-token-address" /> | -| Name | Chainlink Token on Bittensor EVM Mainnet | -| Symbol | LINK | -| Decimals | 18 | +| Parameter | Value | +| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `964` | +| Address | <Address contractUrl="https://taostats.io/address/0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13" urlId="964_0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Bittensor EVM Mainnet | +| Symbol | LINK | +| Decimals | 18 | ## <img src="/assets/chains/blast.svg" style="height: 24px; width: auto; margin-right: 8px;" />Blast @@ -1299,6 +1305,18 @@ Testnet Native and LINK is available at [faucets.chain.link/corn-testnet](https: | Symbol | LINK | | Decimals | 18 | +## <img src="/assets/chains/dogeos.svg" style="height: 24px; width: auto; margin-right: 8px;" />DogeOS + +### DogeOS Chikyu Testnet + +| Parameter | Value | +| :-------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `6281971` | +| Address | <Address contractUrl="https://blockscout.testnet.dogeos.com/address/0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlId="6281971_0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlClass="erc-token-address" /> | +| Name | Chainlink Token on DogeOS Chikyu Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/ethereum.svg" style="height: 24px; width: auto; margin-right: 8px;" />Ethereum ### Ethereum Mainnet @@ -1344,6 +1362,21 @@ Testnet ETH and LINK are available at [faucets.chain.link/holesky](https://fauce | Decimals | 18 | | Network status | [etherscan.freshstatus.io](https://etherscan.freshstatus.io/) | +### Ethereum Hoodi Testnet + +Testnet ETH is used to pay for transactions on Hoodi. + +Testnet ETH and LINK are available at [faucets.chain.link/hoodi](https://faucets.chain.link/hoodi). + +| Parameter | Value | +| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `560048` | +| Address | <Address contractUrl="https://hoodi.etherscan.io/token/0x76c00B055414de203B79B4955E28119BF459033e" urlId="560048_0x76c00B055414de203B79B4955E28119BF459033e" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Ethereum Hoodi Testnet | +| Symbol | LINK | +| Decimals | 18 | +| Network status | [etherscan.freshstatus.io](https://etherscan.freshstatus.io/) | + ## <img src="/assets/chains/etherlink.svg" style="height: 24px; width: auto; margin-right: 8px;" />Etherlink ### Etherlink Mainnet @@ -1534,6 +1567,18 @@ Testnet Native and LINK is available at [faucets.chain.link/hedera-testnet](http | Symbol | LINK | | Decimals | 18 | +## <img src="/assets/chains/henesys.svg" style="height: 24px; width: auto; margin-right: 8px;" />Henesys + +### Henesys Mainnet + +| Parameter | Value | +| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Chain ID | `68414` | +| Address | <Address contractUrl="https://subnets.avax.network/henesys/address/0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlId="68414_0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Nexon Henesys Mainnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/hyperliquid.svg" style="height: 24px; width: auto; margin-right: 8px;" />HyperEVM ### HyperEVM Mainnet @@ -1590,6 +1635,28 @@ Testnet Native and LINK is available at [faucets.chain.link/hedera-testnet](http | Symbol | LINK | | Decimals | 18 | +## <img src="/assets/chains/jovay.svg" style="height: 24px; width: auto; margin-right: 8px;" />Jovay + +### Jovay Mainnet + +| Parameter | Value | +| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Chain ID | `5734951` | +| Address | <Address contractUrl="https://explorer.jovay.io/l2/address/0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlId="5734951_0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Jovay Mainnet | +| Symbol | LINK | +| Decimals | 18 | + +### Jovay Sepolia Testnet + +| Parameter | Value | +| :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `2019775` | +| Address | <Address contractUrl="https://sepolia-explorer.jovay.io/l2/address/0xd3e461C55676B10634a5F81b747c324B85686Dd1" urlId="2019775_0xd3e461C55676B10634a5F81b747c324B85686Dd1" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Jovay Sepolia Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/kaia.svg" style="height: 24px; width: auto; margin-right: 8px;" />Kaia ### Kaia Mainnet @@ -1630,8 +1697,6 @@ ETH is used to pay for transactions on the Kroma mainnet. Testnet ETH is used to pay for transactions on the Kroma testnet. -Testnet Native and LINK are available at [faucets.chain.link/kroma-testnet](https://faucets.chain.link/kroma-testnet). - | Parameter | Value | | :------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ETH_CHAIN_ID` | `2358` | @@ -1762,15 +1827,25 @@ Testnet Native and LINK are available at [faucets.chain.link/mantle-sepolia](htt | Symbol | LINK | | Decimals | 18 | -## <img src="/assets/chains/megaeth.svg" style="height: 24px; width: auto; margin-right: 8px;" />MegaEth +## <img src="/assets/chains/megaeth.svg" style="height: 24px; width: auto; margin-right: 8px;" />MegaETH + +### MegaETH Mainnet + +| Parameter | Value | +| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `4326` | +| Address | <Address contractUrl="https://megaeth.blockscout.com/address/0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae" urlId="4326_0xee85aEfb15b9489563A6a29891ebe0750AA1A7Ae" urlClass="erc-token-address" /> | +| Name | Chainlink Token on MegaETH Mainnet | +| Symbol | LINK | +| Decimals | 18 | -### MegaEth Testnet +### MegaETH Testnet | Parameter | Value | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Chain ID | `6342` | | Address | <Address contractUrl="https://megaexplorer.xyz/address/0x4d03398C2588D92B220578dAEde29814E41c8033" urlId="6342_0x4d03398C2588D92B220578dAEde29814E41c8033" urlClass="erc-token-address" /> | -| Name | Chainlink Token | +| Name | Chainlink Token on MegaETH Testnet | | Symbol | LINK | | Decimals | 18 | @@ -1977,6 +2052,28 @@ MOVR is used to pay transaction fees on Moonriver Mainnet. | Decimals | 18 | | Network status | [moonscan.freshstatus.io](https://moonscan.freshstatus.io/) | +## <img src="/assets/chains/morph.svg" style="height: 24px; width: auto; margin-right: 8px;" />Morph + +### Morph Mainnet + +| Parameter | Value | +| :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `2818` | +| Address | <Address contractUrl="https://explorer.morphl2.io/address/0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlId="2818_0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Morph Mainnet | +| Symbol | LINK | +| Decimals | 18 | + +### Morph Hoodi Testnet + +| Parameter | Value | +| :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `2910` | +| Address | <Address contractUrl="https://explorer-hoodi.morphl2.io/address/0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlId="2910_0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Morph Hoodi Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/neox.svg" style="height: 24px; width: auto; margin-right: 8px;" />Neo X ### Neo X Mainnet @@ -1999,18 +2096,6 @@ MOVR is used to pay transaction fees on Moonriver Mainnet. | Symbol | LINK | | Decimals | 18 | -## <img src="/assets/chains/henesys.svg" style="height: 24px; width: auto; margin-right: 8px;" />Henesys - -### Henesys Mainnet - -| Parameter | Value | -| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Chain ID | `68414` | -| Address | <Address contractUrl="https://subnets.avax.network/henesys/address/0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlId="68414_0x76a443768A5e3B8d1AED0105FC250877841Deb40" urlClass="erc-token-address" /> | -| Name | Chainlink Token on Nexon Henesys Mainnet | -| Symbol | LINK | -| Decimals | 18 | - ## <img src="/assets/chains/opbnb.svg" style="height: 24px; width: auto; margin-right: 8px;" />OPBNB ### OPBNB Mainnet @@ -2413,17 +2498,29 @@ S is used to pay for transactions on Sonic mainnet. | Symbol | LINK | | Decimals | 18 | -### Sonic Blaze Testnet +### Sonic Testnet -Testnet S is used to pay for transactions on Sonic Blaze testnet. +Testnet S is used to pay for transactions on Sonic Testnet. -| Parameter | Value | -| :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ETH_CHAIN_ID` | `57054` | -| Address | <Address contractUrl="https://testnet.sonicscan.org/address/0xd8C1eEE32341240A62eC8BC9988320bcC13c8580" urlId="57054_0xd8C1eEE32341240A62eC8BC9988320bcC13c8580" urlClass="erc-token-address" /> | -| Name | Chainlink Token on Sonice Blaze Testnet | -| Symbol | LINK | -| Decimals | 18 | +| Parameter | Value | +| :------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ETH_CHAIN_ID` | `14601` | +| Address | <Address contractUrl="https://explorer.testnet.soniclabs.com/address/0x19e696e75ccbB3155EEbB579BFa555Fab22293bA" urlId="14601_0x19e696e75ccbB3155EEbB579BFa555Fab22293bA" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Sonic Testnet | +| Symbol | LINK | +| Decimals | 18 | + +## <img src="/assets/chains/stable.svg" style="height: 24px; width: auto; margin-right: 8px;" />Stable + +### Stable Mainnet + +| Parameter | Value | +| :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `988` | +| Address | <Address contractUrl="https://stablescan.xyz/address/0x985FB0821Eef0056ec26DD8b33dC61b9415B7F4b" urlId="988_0x985FB0821Eef0056ec26DD8b33dC61b9415B7F4b" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Stable Mainnet | +| Symbol | LINK | +| Decimals | 18 | ## <img src="/assets/chains/starknet.svg" style="height: 24px; width: auto; margin-right: 8px;" />Starknet @@ -2503,6 +2600,18 @@ Testnet S is used to pay for transactions on Sonic Blaze testnet. | Symbol | LINK | | Decimals | 18 | +## <img src="/assets/chains/tempo.svg" style="height: 24px; width: auto; margin-right: 8px;" />Tempo + +### Tempo Testnet + +| Parameter | Value | +| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `42429` | +| Address | <Address contractUrl="https://explore.tempo.xyz/address/0x384C8843411f725e800E625d5d1B659256D629dF" urlId="42429_0x384C8843411f725e800E625d5d1B659256D629dF" urlClass="erc-token-address" /> | +| Name | Chainlink Token on Tempo Testnet | +| Symbol | LINK | +| Decimals | 18 | + ## <img src="/assets/chains/treasure.svg" style="height: 24px; width: auto; margin-right: 8px;" />Treasure ### Treasure Mainnet @@ -2577,7 +2686,7 @@ Testnet Native and LINK are available at [faucets.chain.link/wemix-testnet](http | Symbol | LINK | | Decimals | 18 | -## <img src="/assets/chains/worldchain.svg" style="height: 24px; width: auto; margin-right: 8px;" />World +## <img src="/assets/chains/worldchain.svg" style="height: 24px; width: auto; margin-right: 8px;" />World Chain ### World Chain Mainnet @@ -2639,15 +2748,15 @@ Testnet ETH is used to pay for transactions on World Chain Sepolia. Testnet Nati | Symbol | LINK | | Decimals | 18 | -### X Layer Sepolia Testnet +### X Layer Testnet -| Parameter | Value | -| :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Chain ID | `195` | -| Address | <Address contractUrl="https://www.oklink.com/xlayer-test/address/0x724593f6FCb0De4E6902d4C55D7C74DaA2AF0E55" urlId="195_0x724593f6FCb0De4E6902d4C55D7C74DaA2AF0E55" urlClass="erc-token-address" /> | -| Name | Chainlink Token on X Layer Sepolia Testnet | -| Symbol | LINK | -| Decimals | 18 | +| Parameter | Value | +| :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Chain ID | `1952` | +| Address | <Address contractUrl="https://web3.okx.com/explorer/x-layer-testnet/address/0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlId="1952_0xe5e3a4fF1773d043a387b16Ceb3c91cC49bAFD54" urlClass="erc-token-address" /> | +| Name | Chainlink Token on X Layer Testnet | +| Symbol | LINK | +| Decimals | 18 | ## <img src="/assets/chains/zircuit.svg" style="height: 24px; width: auto; margin-right: 8px;" />Zircuit @@ -2667,8 +2776,6 @@ ETH is used to pay for transactions on the Zircuit mainnet. Testnet ETH is used to pay for transactions on the Zircuit testnet. -Testnet Native and LINK are available at [faucets.chain.link/zircuit-sepolia](https://faucets.chain.link/zircuit-sepolia). - | Parameter | Value | | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ETH_CHAIN_ID` | `48899` | @@ -2681,7 +2788,7 @@ Testnet Native and LINK are available at [faucets.chain.link/zircuit-sepolia](ht ### ZKsync Era Mainnet -ETH is used to pay for transactions on ZKsync Era Mainnet. Use the recommended [ZKsync Bridges](https://zksync.io/explore#bridges) to transfer ETH from Ethereum to ZKsync. +ETH is used to pay for transactions on ZKsync Era Mainnet. Use the recommended [ZKsync Bridges](https://docs.zksync.io/zksync-network/zksync-era/ecosystem/bridges) to transfer ETH from Ethereum to ZKsync. | Parameter | Value | | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | diff --git a/src/content/vrf/llms-full.txt b/src/content/vrf/llms-full.txt index 4b026ed98b3..86ee6c1fc8e 100644 --- a/src/content/vrf/llms-full.txt +++ b/src/content/vrf/llms-full.txt @@ -373,6 +373,182 @@ contract VRFD20 is VRFConsumerBaseV2Plus { ``` +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * @notice A Chainlink VRF consumer which uses randomness to mimic the rolling + * of a 20 sided dice + */ + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract VRFD20 is VRFConsumerBaseV2Plus { + uint256 private constant ROLL_IN_PROGRESS = 42; + + // Your subscription ID. + uint256 public s_subscriptionId; + + // Sepolia coordinator. For other networks, + // see https://docs.chain.link/vrf/v2-5/supported-networks#configurations + address public vrfCoordinator = 0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/vrf/v2-5/supported-networks#configurations + bytes32 public s_keyHash = 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 40,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 40_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 1 random value in one request. + // Cannot exceed VRFCoordinatorV2_5.MAX_NUM_WORDS. + uint32 public numWords = 1; + + // map rollers to requestIds + mapping(uint256 => address) private s_rollers; + // map vrf results to rollers + mapping(address => uint256) private s_results; + + event DiceRolled(uint256 indexed requestId, address indexed roller); + event DiceLanded(uint256 indexed requestId, uint256 indexed result); + + /** + * @notice Constructor inherits VRFConsumerBaseV2Plus + * + * @dev NETWORK: Sepolia + * + * @param subscriptionId subscription ID that this consumer contract can use + */ + constructor( + uint256 subscriptionId + ) VRFConsumerBaseV2Plus(vrfCoordinator) { + s_subscriptionId = subscriptionId; + } + + /** + * @notice Requests randomness + * @dev Warning: if the VRF response is delayed, avoid calling requestRandomness repeatedly + * as that would give miners/VRF operators latitude about which VRF response arrives first. + * @dev You must review your implementation details with extreme care. + * + * @param roller address of the roller + */ + function rollDice( + address roller + ) public onlyOwner returns (uint256 requestId) { + require(s_results[roller] == 0, "Already rolled"); + // Will revert if subscription is not set and funded. + requestId = s_vrfCoordinator.requestRandomWords( + VRFV2PlusClient.RandomWordsRequest({ + keyHash: s_keyHash, + subId: s_subscriptionId, + requestConfirmations: requestConfirmations, + callbackGasLimit: callbackGasLimit, + numWords: numWords, + extraArgs: VRFV2PlusClient._argsToBytes( + // Set nativePayment to true to pay for VRF requests with Sepolia ETH instead of LINK + VRFV2PlusClient.ExtraArgsV1({nativePayment: false}) + ) + }) + ); + + s_rollers[requestId] = roller; + s_results[roller] = ROLL_IN_PROGRESS; + emit DiceRolled(requestId, roller); + } + + /** + * @notice Callback function used by VRF Coordinator to return the random number to this contract. + * + * @dev Some action on the contract state should be taken here, like storing the result. + * @dev WARNING: take care to avoid having multiple VRF requests in flight if their order of arrival would result + * in contract states with different outcomes. Otherwise miners or the VRF operator would could take advantage + * by controlling the order. + * @dev The VRF Coordinator will only send this function verified responses, and the parent VRFConsumerBaseV2 + * contract ensures that this method only receives randomness from the designated VRFCoordinator. + * + * @param requestId uint256 + * @param randomWords uint256[] The random result returned by the oracle. + */ + function fulfillRandomWords( + uint256 requestId, + uint256[] calldata randomWords + ) internal override { + uint256 d20Value = (randomWords[0] % 20) + 1; + s_results[s_rollers[requestId]] = d20Value; + emit DiceLanded(requestId, d20Value); + } + + /** + * @notice Get the house assigned to the player once the address has rolled + * @param player address + * @return house as a string + */ + function house( + address player + ) public view returns (string memory) { + require(s_results[player] != 0, "Dice not rolled"); + require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); + return _getHouseName(s_results[player]); + } + + /** + * @notice Get the house name from the id + * @param id uint256 + * @return house name string + */ + function _getHouseName( + uint256 id + ) private pure returns (string memory) { + string[20] memory houseNames = [ + "Targaryen", + "Lannister", + "Stark", + "Tyrell", + "Baratheon", + "Martell", + "Tully", + "Bolton", + "Greyjoy", + "Arryn", + "Frey", + "Mormont", + "Tarley", + "Dayne", + "Umber", + "Valeryon", + "Manderly", + "Clegane", + "Glover", + "Karstark" + ]; + return houseNames[id - 1]; + } +} +``` + You have now completed all necessary functions to generate randomness and assign the user a *Game of Thrones* house. We've added a few helper functions in there to make using the contract easier and more flexible. You can deploy and interact with the complete contract in Remix. ## How do I deploy to testnet? @@ -473,6 +649,128 @@ If using subscriptions, [create and fund a new VRF v2.5 subscription](/vrf/v2-5/ For direct funding, deploy the [`DirectFundingConsumer`](/samples/VRF/v2-5/DirectFundingConsumer.sol) example: +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that directly pays for each request. +pragma solidity ^0.8.20; + +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; +import {VRFV2PlusWrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract DirectFundingConsumer is VRFV2PlusWrapperConsumerBase, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + + struct RequestStatus { + uint256 paid; // amount paid in link + bool fulfilled; // whether the request has been successfully fulfilled + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords. + uint32 public numWords = 2; + + // Address LINK - hardcoded for Sepolia + address public linkAddress = 0x779877A7B0D9E8603169DdbD7836e478b4624789; + + // address WRAPPER - hardcoded for Sepolia + address public wrapperAddress = 0x195f15F2d49d693cE265b4fB0fdDbE15b1850Cc1; + + constructor() ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(wrapperAddress) {} + + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256) { + bytes memory extraArgs = + VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})); + uint256 requestId; + uint256 reqPrice; + if (enableNativePayment) { + (requestId, reqPrice) = requestRandomnessPayInNative(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } else { + (requestId, reqPrice) = requestRandomness(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } + s_requests[requestId] = RequestStatus({paid: reqPrice, randomWords: new uint256[](0), fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].paid > 0, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.paid, request.fulfilled, request.randomWords); + } + + /** + * Allow withdraw of Link tokens from the contract + */ + function withdrawLink() public onlyOwner { + LinkTokenInterface link = LinkTokenInterface(linkAddress); + require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); + } + + /// @notice withdrawNative withdraws the amount specified in amount to the owner + /// @param amount the amount to withdraw, in wei + function withdrawNative( + uint256 amount + ) external onlyOwner { + (bool success,) = payable(owner()).call{value: amount}(""); + // solhint-disable-next-line gas-custom-errors + require(success, "withdrawNative failed"); + } + + event Received(address, uint256); + + receive() external payable { + emit Received(msg.sender, msg.value); + } +} +``` + ### Update your code To modify your existing smart contract code to work with VRF v2.5, complete the following changes: @@ -486,6 +784,118 @@ The example `SubscriptionConsumer` contract shows the migration steps above, app Open the full example `SubscriptionConsumer` contract: +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that relies on a subscription for funding. +pragma solidity ^0.8.20; + +import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract SubscriptionConsumer is VRFConsumerBaseV2Plus { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords); + + struct RequestStatus { + bool fulfilled; // whether the request has been successfully fulfilled + bool exists; // whether a requestId exists + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // Your subscription ID. + uint256 public s_subscriptionId; + + // Past request IDs. + uint256[] public requestIds; + uint256 public lastRequestId; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/vrf/v2-5/supported-networks + bytes32 public keyHash = 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 100,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFCoordinatorV2_5.MAX_NUM_WORDS. + uint32 public numWords = 2; + + /** + * HARDCODED FOR SEPOLIA + * COORDINATOR: 0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B + */ + constructor( + uint256 subscriptionId + ) VRFConsumerBaseV2Plus(0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B) { + s_subscriptionId = subscriptionId; + } + + // Assumes the subscription is funded sufficiently. + // @param enableNativePayment: Set to `true` to enable payment in native tokens, or + // `false` to pay in LINK + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256 requestId) { + // Will revert if subscription is not set and funded. + requestId = s_vrfCoordinator.requestRandomWords( + VRFV2PlusClient.RandomWordsRequest({ + keyHash: keyHash, + subId: s_subscriptionId, + requestConfirmations: requestConfirmations, + callbackGasLimit: callbackGasLimit, + numWords: numWords, + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})) + }) + ); + s_requests[requestId] = RequestStatus({randomWords: new uint256[](0), exists: true, fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] calldata _randomWords + ) internal override { + require(s_requests[_requestId].exists, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].exists, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.fulfilled, request.randomWords); + } +} +``` + Compare the major changes between V2.5 and V2: @@ -495,6 +905,128 @@ The example `DirectFundingConsumer` contract shows the migration steps above, ap Open the full example `DirectFundingConsumer` contract: +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that directly pays for each request. +pragma solidity ^0.8.20; + +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; +import {VRFV2PlusWrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract DirectFundingConsumer is VRFV2PlusWrapperConsumerBase, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + + struct RequestStatus { + uint256 paid; // amount paid in link + bool fulfilled; // whether the request has been successfully fulfilled + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords. + uint32 public numWords = 2; + + // Address LINK - hardcoded for Sepolia + address public linkAddress = 0x779877A7B0D9E8603169DdbD7836e478b4624789; + + // address WRAPPER - hardcoded for Sepolia + address public wrapperAddress = 0x195f15F2d49d693cE265b4fB0fdDbE15b1850Cc1; + + constructor() ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(wrapperAddress) {} + + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256) { + bytes memory extraArgs = + VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})); + uint256 requestId; + uint256 reqPrice; + if (enableNativePayment) { + (requestId, reqPrice) = requestRandomnessPayInNative(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } else { + (requestId, reqPrice) = requestRandomness(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } + s_requests[requestId] = RequestStatus({paid: reqPrice, randomWords: new uint256[](0), fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].paid > 0, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.paid, request.fulfilled, request.randomWords); + } + + /** + * Allow withdraw of Link tokens from the contract + */ + function withdrawLink() public onlyOwner { + LinkTokenInterface link = LinkTokenInterface(linkAddress); + require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); + } + + /// @notice withdrawNative withdraws the amount specified in amount to the owner + /// @param amount the amount to withdraw, in wei + function withdrawNative( + uint256 amount + ) external onlyOwner { + (bool success,) = payable(owner()).call{value: amount}(""); + // solhint-disable-next-line gas-custom-errors + require(success, "withdrawNative failed"); + } + + event Received(address, uint256); + + receive() external payable { + emit Received(msg.sender, msg.value); + } +} +``` + Compare the major changes between V2.5 and V2: --- @@ -545,6 +1077,128 @@ If using subscriptions, [create and fund a new VRF v2.5 subscription](/vrf/v2-5/ For direct funding, deploy the [`DirectFundingConsumer`](/samples/VRF/v2-5/DirectFundingConsumer.sol) example: +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that directly pays for each request. +pragma solidity ^0.8.20; + +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; +import {VRFV2PlusWrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract DirectFundingConsumer is VRFV2PlusWrapperConsumerBase, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + + struct RequestStatus { + uint256 paid; // amount paid in link + bool fulfilled; // whether the request has been successfully fulfilled + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords. + uint32 public numWords = 2; + + // Address LINK - hardcoded for Sepolia + address public linkAddress = 0x779877A7B0D9E8603169DdbD7836e478b4624789; + + // address WRAPPER - hardcoded for Sepolia + address public wrapperAddress = 0x195f15F2d49d693cE265b4fB0fdDbE15b1850Cc1; + + constructor() ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(wrapperAddress) {} + + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256) { + bytes memory extraArgs = + VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})); + uint256 requestId; + uint256 reqPrice; + if (enableNativePayment) { + (requestId, reqPrice) = requestRandomnessPayInNative(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } else { + (requestId, reqPrice) = requestRandomness(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } + s_requests[requestId] = RequestStatus({paid: reqPrice, randomWords: new uint256[](0), fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].paid > 0, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.paid, request.fulfilled, request.randomWords); + } + + /** + * Allow withdraw of Link tokens from the contract + */ + function withdrawLink() public onlyOwner { + LinkTokenInterface link = LinkTokenInterface(linkAddress); + require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); + } + + /// @notice withdrawNative withdraws the amount specified in amount to the owner + /// @param amount the amount to withdraw, in wei + function withdrawNative( + uint256 amount + ) external onlyOwner { + (bool success,) = payable(owner()).call{value: amount}(""); + // solhint-disable-next-line gas-custom-errors + require(success, "withdrawNative failed"); + } + + event Received(address, uint256); + + receive() external payable { + emit Received(msg.sender, msg.value); + } +} +``` + ### Update your code To modify your existing smart contract code to work with VRF v2.5, complete the following changes: @@ -556,8 +1210,242 @@ View example code for both VRF 2.5 subscription and direct funding: Open the full example `SubscriptionConsumer` contract: +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that relies on a subscription for funding. +pragma solidity ^0.8.20; + +import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract SubscriptionConsumer is VRFConsumerBaseV2Plus { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords); + + struct RequestStatus { + bool fulfilled; // whether the request has been successfully fulfilled + bool exists; // whether a requestId exists + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // Your subscription ID. + uint256 public s_subscriptionId; + + // Past request IDs. + uint256[] public requestIds; + uint256 public lastRequestId; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/vrf/v2-5/supported-networks + bytes32 public keyHash = 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 100,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFCoordinatorV2_5.MAX_NUM_WORDS. + uint32 public numWords = 2; + + /** + * HARDCODED FOR SEPOLIA + * COORDINATOR: 0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B + */ + constructor( + uint256 subscriptionId + ) VRFConsumerBaseV2Plus(0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B) { + s_subscriptionId = subscriptionId; + } + + // Assumes the subscription is funded sufficiently. + // @param enableNativePayment: Set to `true` to enable payment in native tokens, or + // `false` to pay in LINK + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256 requestId) { + // Will revert if subscription is not set and funded. + requestId = s_vrfCoordinator.requestRandomWords( + VRFV2PlusClient.RandomWordsRequest({ + keyHash: keyHash, + subId: s_subscriptionId, + requestConfirmations: requestConfirmations, + callbackGasLimit: callbackGasLimit, + numWords: numWords, + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})) + }) + ); + s_requests[requestId] = RequestStatus({randomWords: new uint256[](0), exists: true, fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] calldata _randomWords + ) internal override { + require(s_requests[_requestId].exists, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].exists, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.fulfilled, request.randomWords); + } +} +``` + Open the full example `DirectFundingConsumer` contract: +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that directly pays for each request. +pragma solidity ^0.8.20; + +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; +import {VRFV2PlusWrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract DirectFundingConsumer is VRFV2PlusWrapperConsumerBase, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + + struct RequestStatus { + uint256 paid; // amount paid in link + bool fulfilled; // whether the request has been successfully fulfilled + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords. + uint32 public numWords = 2; + + // Address LINK - hardcoded for Sepolia + address public linkAddress = 0x779877A7B0D9E8603169DdbD7836e478b4624789; + + // address WRAPPER - hardcoded for Sepolia + address public wrapperAddress = 0x195f15F2d49d693cE265b4fB0fdDbE15b1850Cc1; + + constructor() ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(wrapperAddress) {} + + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256) { + bytes memory extraArgs = + VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})); + uint256 requestId; + uint256 reqPrice; + if (enableNativePayment) { + (requestId, reqPrice) = requestRandomnessPayInNative(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } else { + (requestId, reqPrice) = requestRandomness(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } + s_requests[requestId] = RequestStatus({paid: reqPrice, randomWords: new uint256[](0), fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].paid > 0, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.paid, request.fulfilled, request.randomWords); + } + + /** + * Allow withdraw of Link tokens from the contract + */ + function withdrawLink() public onlyOwner { + LinkTokenInterface link = LinkTokenInterface(linkAddress); + require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); + } + + /// @notice withdrawNative withdraws the amount specified in amount to the owner + /// @param amount the amount to withdraw, in wei + function withdrawNative( + uint256 amount + ) external onlyOwner { + (bool success,) = payable(owner()).call{value: amount}(""); + // solhint-disable-next-line gas-custom-errors + require(success, "withdrawNative failed"); + } + + event Received(address, uint256); + + receive() external payable { + emit Received(msg.sender, msg.value); + } +} +``` + --- # Supported Networks @@ -1383,6 +2271,118 @@ Build and deploy the contract on Sepolia. 1. Open the [SubscriptionConsumer.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/v2-5/SubscriptionConsumer.sol) in Remix. + ```sol + // SPDX-License-Identifier: MIT + // An example of a consumer contract that relies on a subscription for funding. + pragma solidity ^0.8.20; + + import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol"; + import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + + /** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + contract SubscriptionConsumer is VRFConsumerBaseV2Plus { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords); + + struct RequestStatus { + bool fulfilled; // whether the request has been successfully fulfilled + bool exists; // whether a requestId exists + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // Your subscription ID. + uint256 public s_subscriptionId; + + // Past request IDs. + uint256[] public requestIds; + uint256 public lastRequestId; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/vrf/v2-5/supported-networks + bytes32 public keyHash = 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 100,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFCoordinatorV2_5.MAX_NUM_WORDS. + uint32 public numWords = 2; + + /** + * HARDCODED FOR SEPOLIA + * COORDINATOR: 0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B + */ + constructor( + uint256 subscriptionId + ) VRFConsumerBaseV2Plus(0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B) { + s_subscriptionId = subscriptionId; + } + + // Assumes the subscription is funded sufficiently. + // @param enableNativePayment: Set to `true` to enable payment in native tokens, or + // `false` to pay in LINK + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256 requestId) { + // Will revert if subscription is not set and funded. + requestId = s_vrfCoordinator.requestRandomWords( + VRFV2PlusClient.RandomWordsRequest({ + keyHash: keyHash, + subId: s_subscriptionId, + requestConfirmations: requestConfirmations, + callbackGasLimit: callbackGasLimit, + numWords: numWords, + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})) + }) + ); + s_requests[requestId] = RequestStatus({randomWords: new uint256[](0), exists: true, fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] calldata _randomWords + ) internal override { + require(s_requests[_requestId].exists, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].exists, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.fulfilled, request.randomWords); + } + } + ``` + 2. On the **Compile** tab in Remix, compile the `SubscriptionConsumer.sol` contract. 3. Configure your deployment. On the **Deploy** tab in Remix, select the **Injected Provider** environment, select the `SubscriptionConsumer` contract from the contract list, and specify your `subscriptionId` so the constructor can set it. @@ -1435,6 +2435,118 @@ You deployed a simple contract that can request and receive random values from C In this example, your MetaMask wallet is the subscription owner and you created a consuming contract to use that subscription. The consuming contract uses static configuration parameters. +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that relies on a subscription for funding. +pragma solidity ^0.8.20; + +import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract SubscriptionConsumer is VRFConsumerBaseV2Plus { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords); + + struct RequestStatus { + bool fulfilled; // whether the request has been successfully fulfilled + bool exists; // whether a requestId exists + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // Your subscription ID. + uint256 public s_subscriptionId; + + // Past request IDs. + uint256[] public requestIds; + uint256 public lastRequestId; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/vrf/v2-5/supported-networks + bytes32 public keyHash = 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 100,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFCoordinatorV2_5.MAX_NUM_WORDS. + uint32 public numWords = 2; + + /** + * HARDCODED FOR SEPOLIA + * COORDINATOR: 0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B + */ + constructor( + uint256 subscriptionId + ) VRFConsumerBaseV2Plus(0x9DdfaCa8183c41ad55329BdeeD9F6A8d53168B1B) { + s_subscriptionId = subscriptionId; + } + + // Assumes the subscription is funded sufficiently. + // @param enableNativePayment: Set to `true` to enable payment in native tokens, or + // `false` to pay in LINK + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256 requestId) { + // Will revert if subscription is not set and funded. + requestId = s_vrfCoordinator.requestRandomWords( + VRFV2PlusClient.RandomWordsRequest({ + keyHash: keyHash, + subId: s_subscriptionId, + requestConfirmations: requestConfirmations, + callbackGasLimit: callbackGasLimit, + numWords: numWords, + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})) + }) + ); + s_requests[requestId] = RequestStatus({randomWords: new uint256[](0), exists: true, fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] calldata _randomWords + ) internal override { + require(s_requests[_requestId].exists, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].exists, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.fulfilled, request.randomWords); + } +} +``` + The parameters define how your requests will be processed. You can find the values for your network in the [Configuration](/vrf/v2-5/supported-networks) page. - `uint256 s_subscriptionId`: The subscription ID that this contract uses for funding requests. @@ -1506,8 +2618,113 @@ For local testing, use the default "Remix VM" environment. Open *VRFv2_5Consumer* and compile in Remix: +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that relies on a subscription for funding. +pragma solidity ^0.8.20; + +import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/** + * @title The RandomNumberConsumerV2_5 contract + * @notice A contract that gets random values from Chainlink VRF V2_5 + */ +contract RandomNumberConsumerV2_5 is VRFConsumerBaseV2Plus { + // Your subscription ID. + uint256 immutable s_subscriptionId; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + bytes32 immutable s_keyHash; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 100,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 constant CALLBACK_GAS_LIMIT = 100_000; + + // The default is 3, but you can set this higher. + uint16 constant REQUEST_CONFIRMATIONS = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFCoordinatorV2_5.MAX_NUM_WORDS. + uint32 constant NUM_WORDS = 2; + + uint256[] public s_randomWords; + uint256 public s_requestId; + + event ReturnedRandomness(uint256[] randomWords); + + /** + * @notice Constructor inherits VRFConsumerBaseV2Plus + * + * @param subscriptionId - the subscription ID that this contract uses for funding requests + * @param vrfCoordinator - coordinator, check https://docs.chain.link/vrf/v2-5/supported-networks + * @param keyHash - the gas lane to use, which specifies the maximum gas price to bump to + */ + constructor( + uint256 subscriptionId, + address vrfCoordinator, + bytes32 keyHash + ) VRFConsumerBaseV2Plus(vrfCoordinator) { + s_keyHash = keyHash; + s_subscriptionId = subscriptionId; + } + + /** + * @notice Requests randomness + * Assumes the subscription is funded sufficiently; "Words" refers to unit of data in Computer Science + */ + function requestRandomWords() external onlyOwner { + // Will revert if subscription is not set and funded. + s_requestId = s_vrfCoordinator.requestRandomWords( + VRFV2PlusClient.RandomWordsRequest({ + keyHash: s_keyHash, + subId: s_subscriptionId, + requestConfirmations: REQUEST_CONFIRMATIONS, + callbackGasLimit: CALLBACK_GAS_LIMIT, + numWords: NUM_WORDS, + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: false})) + }) + ); + } + + /** + * @notice Callback function used by VRF Coordinator + * + * @param - id of the request + * @param randomWords - array of random results from VRF Coordinator + */ + function fulfillRandomWords( + uint256, + /* requestId */ + uint256[] calldata randomWords + ) internal override { + s_randomWords = randomWords; + emit ReturnedRandomness(randomWords); + } +} +``` + Open *VRFCoordinatorV2_5Mock* in Remix: +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@chainlink/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2_5Mock.sol"; +``` + On the *Solidity Compiler* tab, expand the *Advanced Configurations* section and check the *Enable optimization* box before you compile the *VRFCoordinatorV2_5Mock* contract: Your Remix IDE file explorer should display *VRFCoordinatorV2_5Mock.sol* and *VRFv2_5Consumer.sol*: @@ -1630,6 +2847,128 @@ Build and deploy the contract on Sepolia. 1. Open the [`DirectFundingConsumer.sol` contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/v2-5/DirectFundingConsumer.sol) in Remix. + ```sol + // SPDX-License-Identifier: MIT + // An example of a consumer contract that directly pays for each request. + pragma solidity ^0.8.20; + + import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; + import {VRFV2PlusWrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; + import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + + /** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + contract DirectFundingConsumer is VRFV2PlusWrapperConsumerBase, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + + struct RequestStatus { + uint256 paid; // amount paid in link + bool fulfilled; // whether the request has been successfully fulfilled + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords. + uint32 public numWords = 2; + + // Address LINK - hardcoded for Sepolia + address public linkAddress = 0x779877A7B0D9E8603169DdbD7836e478b4624789; + + // address WRAPPER - hardcoded for Sepolia + address public wrapperAddress = 0x195f15F2d49d693cE265b4fB0fdDbE15b1850Cc1; + + constructor() ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(wrapperAddress) {} + + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256) { + bytes memory extraArgs = + VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})); + uint256 requestId; + uint256 reqPrice; + if (enableNativePayment) { + (requestId, reqPrice) = requestRandomnessPayInNative(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } else { + (requestId, reqPrice) = requestRandomness(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } + s_requests[requestId] = RequestStatus({paid: reqPrice, randomWords: new uint256[](0), fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].paid > 0, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.paid, request.fulfilled, request.randomWords); + } + + /** + * Allow withdraw of Link tokens from the contract + */ + function withdrawLink() public onlyOwner { + LinkTokenInterface link = LinkTokenInterface(linkAddress); + require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); + } + + /// @notice withdrawNative withdraws the amount specified in amount to the owner + /// @param amount the amount to withdraw, in wei + function withdrawNative( + uint256 amount + ) external onlyOwner { + (bool success,) = payable(owner()).call{value: amount}(""); + // solhint-disable-next-line gas-custom-errors + require(success, "withdrawNative failed"); + } + + event Received(address, uint256); + + receive() external payable { + emit Received(msg.sender, msg.value); + } + } + ``` + 2. On the **Compile** tab in Remix, compile the `DirectFundingConsumer` contract. 3. Configure your deployment. On the **Deploy** tab in Remix, select the **Injected Web3 Environment** and select the `DirectFundingConsumer` contract from the contract list. @@ -1670,6 +3009,128 @@ The deployed contract requests random values from Chainlink VRF, receives those In this example, the consuming contract uses static configuration parameters. +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that directly pays for each request. +pragma solidity ^0.8.20; + +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; +import {VRFV2PlusWrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; +import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract DirectFundingConsumer is VRFV2PlusWrapperConsumerBase, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + + struct RequestStatus { + uint256 paid; // amount paid in link + bool fulfilled; // whether the request has been successfully fulfilled + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 public callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 public requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords. + uint32 public numWords = 2; + + // Address LINK - hardcoded for Sepolia + address public linkAddress = 0x779877A7B0D9E8603169DdbD7836e478b4624789; + + // address WRAPPER - hardcoded for Sepolia + address public wrapperAddress = 0x195f15F2d49d693cE265b4fB0fdDbE15b1850Cc1; + + constructor() ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(wrapperAddress) {} + + function requestRandomWords( + bool enableNativePayment + ) external onlyOwner returns (uint256) { + bytes memory extraArgs = + VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment})); + uint256 requestId; + uint256 reqPrice; + if (enableNativePayment) { + (requestId, reqPrice) = requestRandomnessPayInNative(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } else { + (requestId, reqPrice) = requestRandomness(callbackGasLimit, requestConfirmations, numWords, extraArgs); + } + s_requests[requestId] = RequestStatus({paid: reqPrice, randomWords: new uint256[](0), fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].paid > 0, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.paid, request.fulfilled, request.randomWords); + } + + /** + * Allow withdraw of Link tokens from the contract + */ + function withdrawLink() public onlyOwner { + LinkTokenInterface link = LinkTokenInterface(linkAddress); + require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); + } + + /// @notice withdrawNative withdraws the amount specified in amount to the owner + /// @param amount the amount to withdraw, in wei + function withdrawNative( + uint256 amount + ) external onlyOwner { + (bool success,) = payable(owner()).call{value: amount}(""); + // solhint-disable-next-line gas-custom-errors + require(success, "withdrawNative failed"); + } + + event Received(address, uint256); + + receive() external payable { + emit Received(msg.sender, msg.value); + } +} +``` + The parameters define how your requests will be processed. You can find the values for your network in the [Supported networks](/vrf/v2-5/supported-networks) page. - `uint32 callbackGasLimit`: The limit for how much gas to use for the callback request to your contract's `fulfillRandomWords()` function. It must be less than the `maxGasLimit` limit on the coordinator contract minus the `wrapperGasOverhead`. See the [VRF v2.5 Direct funding limits](/vrf/v2-5/overview/direct-funding#limits) for more details. Adjust this value for larger requests depending on how your `fulfillRandomWords()` function processes and stores the received random values. If your `callbackGasLimit` is not sufficient, the callback will fail and your consuming contract is still charged for the work done to generate your requested random values. @@ -2096,6 +3557,71 @@ Note, the below values have to be configured correctly for VRF requests to work. testnet LINK](/resources/acquire-link) and [Fund your contract](/resources/fund-your-contract)**. </Aside> +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import {VRFConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBase.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ +contract RandomNumberConsumer is VRFConsumerBase { + event RequestFulfilled(bytes32 requestId, uint256 randomness); + + bytes32 internal keyHash; + uint256 internal fee; + uint256 public randomResult; + + /** + * Constructor inherits VRFConsumerBase + * + * Network: Sepolia + * Chainlink VRF Coordinator address: 0x271682DEB8C4E0901D1a1550aD2e64D568E69909 + * LINK token address: 0x779877A7B0D9E8603169DdbD7836e478b4624789 + * Key Hash: 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c + */ + constructor() + VRFConsumerBase( + 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625, // VRF Coordinator + 0x779877A7B0D9E8603169DdbD7836e478b4624789 // LINK Token + ) + { + keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; + fee = 0.1 * 10 ** 18; // 0.1 LINK (Varies by network) + } + + /** + * Requests randomness + */ + function getRandomNumber() public returns (bytes32 requestId) { + require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet"); + return requestRandomness(keyHash, fee); + } + + /** + * Callback function used by VRF Coordinator + */ + function fulfillRandomness( + bytes32 requestId, + uint256 randomness + ) internal override { + randomResult = randomness; + emit RequestFulfilled(requestId, randomness); + } + + // function withdrawLink() external {} - Implement a withdraw function to avoid locking your LINK in the contract +} +``` + <Aside type="note" title="Maximum Gas for Callback"> If your `fulfillRandomness` function uses more than 200k gas, the transaction will fail. </Aside> @@ -2346,38 +3872,158 @@ function fulfillRandomWords( } ``` -You could also map the `requestId` to an index to keep track of the order in which a request was made. +You could also map the `requestId` to an index to keep track of the order in which a request was made. + + +```solidity +mapping(uint256 => uint256) s_requestIdToRequestIndex; +mapping(uint256 => uint256[]) public s_requestIndexToRandomWords; +uint256 public requestCounter; + +function requestRandomWords() external onlyOwner { + uint256 requestId = COORDINATOR.requestRandomWords( + keyHash, + s_subscriptionId, + requestConfirmations, + callbackGasLimit, + numWords + ); + s_requestIdToRequestIndex[requestId] = requestCounter; + requestCounter += 1; +} + +function fulfillRandomWords( + uint256 requestId, + uint256[] memory randomWords + ) internal override { + uint256 requestNumber = s_requestIdToRequestIndex[requestId]; + s_requestIndexToRandomWords[requestNumber] = randomWords; +} +``` + +## Processing VRF responses through different execution paths + +If you want to process VRF responses depending on predetermined conditions, you can create an `enum`. When requesting for randomness, map each `requestId` to an enum. This way, you can handle different execution paths in `fulfillRandomWords`. See the following example: + +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that relies on a subscription for funding. +// It shows how to setup multiple execution paths for handling a response. +pragma solidity ^0.8.7; + +import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol"; +import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract VRFv2MultiplePaths is VRFConsumerBaseV2 { + VRFCoordinatorV2Interface COORDINATOR; + + // Your subscription ID. + uint64 s_subscriptionId; + + // Sepolia coordinator. For other networks, + // see https://docs.chain.link/docs/vrf/v2/supported-networks/#configurations + address vrfCoordinator = 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/docs/vrf/v2/supported-networks/#configurations + bytes32 keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; + + uint32 callbackGasLimit = 100_000; + // The default is 3, but you can set this higher. + uint16 requestConfirmations = 3; -```solidity -mapping(uint256 => uint256) s_requestIdToRequestIndex; -mapping(uint256 => uint256[]) public s_requestIndexToRandomWords; -uint256 public requestCounter; + // For this example, retrieve 1 random value in one request. + // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. + uint32 numWords = 1; -function requestRandomWords() external onlyOwner { - uint256 requestId = COORDINATOR.requestRandomWords( - keyHash, - s_subscriptionId, - requestConfirmations, - callbackGasLimit, - numWords - ); - s_requestIdToRequestIndex[requestId] = requestCounter; - requestCounter += 1; -} + enum Variable { + A, + B, + C + } -function fulfillRandomWords( + uint256 public variableA; + uint256 public variableB; + uint256 public variableC; + + mapping(uint256 => Variable) public requests; + + // events + event FulfilledA(uint256 requestId, uint256 value); + event FulfilledB(uint256 requestId, uint256 value); + event FulfilledC(uint256 requestId, uint256 value); + + constructor( + uint64 subscriptionId + ) VRFConsumerBaseV2(vrfCoordinator) { + COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); + s_subscriptionId = subscriptionId; + } + + function updateVariable( + uint256 input + ) public { + uint256 requestId = + COORDINATOR.requestRandomWords(keyHash, s_subscriptionId, requestConfirmations, callbackGasLimit, numWords); + + if (input % 2 == 0) { + requests[requestId] = Variable.A; + } else if (input % 3 == 0) { + requests[requestId] = Variable.B; + } else { + requests[requestId] = Variable.C; + } + } + + function fulfillRandomWords( uint256 requestId, uint256[] memory randomWords ) internal override { - uint256 requestNumber = s_requestIdToRequestIndex[requestId]; - s_requestIndexToRandomWords[requestNumber] = randomWords; -} -``` + Variable variable = requests[requestId]; + if (variable == Variable.A) { + fulfillA(requestId, randomWords[0]); + } else if (variable == Variable.B) { + fulfillB(requestId, randomWords[0]); + } else if (variable == Variable.C) { + fulfillC(requestId, randomWords[0]); + } + } -## Processing VRF responses through different execution paths + function fulfillA( + uint256 requestId, + uint256 randomWord + ) private { + // execution path A + variableA = randomWord; + emit FulfilledA(requestId, randomWord); + } -If you want to process VRF responses depending on predetermined conditions, you can create an `enum`. When requesting for randomness, map each `requestId` to an enum. This way, you can handle different execution paths in `fulfillRandomWords`. See the following example: + function fulfillB( + uint256 requestId, + uint256 randomWord + ) private { + // execution path B + variableB = randomWord; + emit FulfilledB(requestId, randomWord); + } + + function fulfillC( + uint256 requestId, + uint256 randomWord + ) private { + // execution path C + variableC = randomWord; + emit FulfilledC(requestId, randomWord); + } +} +``` --- @@ -2412,6 +4058,104 @@ Build and deploy the contract on Sepolia. 1. Open the [`VRFv2DirectFundingConsumer.sol` contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFv2DirectFundingConsumer.sol) in Remix. + ```sol + // SPDX-License-Identifier: MIT + // An example of a consumer contract that directly pays for each request. + pragma solidity ^0.8.7; + + import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + + import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; + import {VRFV2WrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol"; + + /** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + contract VRFv2DirectFundingConsumer is VRFV2WrapperConsumerBase, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + + struct RequestStatus { + uint256 paid; // amount paid in link + bool fulfilled; // whether the request has been successfully fulfilled + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords. + uint32 numWords = 2; + + // Address LINK - hardcoded for Sepolia + address linkAddress = 0x779877A7B0D9E8603169DdbD7836e478b4624789; + + // address WRAPPER - hardcoded for Sepolia + address wrapperAddress = 0xab18414CD93297B0d12ac29E63Ca20f515b3DB46; + + constructor() ConfirmedOwner(msg.sender) VRFV2WrapperConsumerBase(linkAddress, wrapperAddress) {} + + function requestRandomWords() external onlyOwner returns (uint256 requestId) { + requestId = requestRandomness(callbackGasLimit, requestConfirmations, numWords); + s_requests[requestId] = RequestStatus({ + paid: VRF_V2_WRAPPER.calculateRequestPrice(callbackGasLimit), randomWords: new uint256[](0), fulfilled: false + }); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].paid > 0, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.paid, request.fulfilled, request.randomWords); + } + + /** + * Allow withdraw of Link tokens from the contract + */ + function withdrawLink() public onlyOwner { + LinkTokenInterface link = LinkTokenInterface(linkAddress); + require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); + } + } + ``` + 2. On the **Compile** tab in Remix, compile the `VRFv2DirectFundingConsumer` contract. 3. Configure your deployment. On the **Deploy** tab in Remix, select the **Injected Web3 Environment** and select the `VRFv2DirectFundingConsumer` contract from the contract list. @@ -2463,6 +4207,104 @@ The deployed contract requests random values from Chainlink VRF, receives those In this example, the consuming contract uses static configuration parameters. +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that directly pays for each request. +pragma solidity ^0.8.7; + +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; +import {VRFV2WrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract VRFv2DirectFundingConsumer is VRFV2WrapperConsumerBase, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + + struct RequestStatus { + uint256 paid; // amount paid in link + bool fulfilled; // whether the request has been successfully fulfilled + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords. + uint32 numWords = 2; + + // Address LINK - hardcoded for Sepolia + address linkAddress = 0x779877A7B0D9E8603169DdbD7836e478b4624789; + + // address WRAPPER - hardcoded for Sepolia + address wrapperAddress = 0xab18414CD93297B0d12ac29E63Ca20f515b3DB46; + + constructor() ConfirmedOwner(msg.sender) VRFV2WrapperConsumerBase(linkAddress, wrapperAddress) {} + + function requestRandomWords() external onlyOwner returns (uint256 requestId) { + requestId = requestRandomness(callbackGasLimit, requestConfirmations, numWords); + s_requests[requestId] = RequestStatus({ + paid: VRF_V2_WRAPPER.calculateRequestPrice(callbackGasLimit), randomWords: new uint256[](0), fulfilled: false + }); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].paid > 0, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.paid, request.fulfilled, request.randomWords); + } + + /** + * Allow withdraw of Link tokens from the contract + */ + function withdrawLink() public onlyOwner { + LinkTokenInterface link = LinkTokenInterface(linkAddress); + require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); + } +} +``` + The parameters define how your requests will be processed. You can find the values for your network in the [Supported networks](/vrf/v2/direct-funding/supported-networks) page. - `uint32 callbackGasLimit`: The limit for how much gas to use for the callback request to your contract's `fulfillRandomWords()` function. It must be less than the `maxGasLimit` limit on the coordinator contract minus the `wrapperGasOverhead`. See the [VRF v2 Direct funding limits](/vrf/v2/direct-funding/#limits) for more details. Adjust this value for larger requests depending on how your `fulfillRandomWords()` function processes and stores the received random values. If your `callbackGasLimit` is not sufficient, the callback will fail and your consuming contract is still charged for the work done to generate your requested random values. @@ -2513,7 +4355,7 @@ This guide explains how to test Chainlink VRF v2 on a [Remix IDE](https://remix- Complete the following tasks to test your VRF v2 consumer locally: 1. Deploy the [VRFCoordinatorV2Mock](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol). This contract is a mock of the [VRFCoordinatorV2](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol) contract. -2. Deploy the [MockV3Aggregator](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/shared/mocks/MockV3Aggregator.sol) contract. +2. Deploy the [MockV3Aggregator](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/tests/MockV3Aggregator.sol) contract. 3. Deploy the [LinkToken](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/shared/token/ERC677/LinkToken.sol) contract. 4. Deploy the [VRFV2Wrapper](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/VRFV2Wrapper.sol) contract. 5. Call the VRFV2Wrapper [setConfig function](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/VRFV2Wrapper.sol#L119) to set wrapper specific parameters. @@ -2550,14 +4392,142 @@ This guide will require you to finetune the gas limit when fulfilling requests. Open *VRFCoordinatorV2Mock* and compile in Remix: +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import "@chainlink/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol"; +``` + Open *MockV3Aggregator* and compile in Remix: +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import "@chainlink/contracts/src/v0.8/shared/mocks/MockV3Aggregator.sol"; +``` + Open *LinkToken* and compile in Remix: +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@chainlink/contracts/src/v0.8/shared/token/ERC677/LinkToken.sol"; +``` + Open *VRFV2Wrapper* and compile in Remix: +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.6; + +import "@chainlink/contracts/src/v0.8/vrf/VRFV2Wrapper.sol"; +``` + Open *RandomNumberDirectFundingConsumerV2* and compile in Remix: +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that directly pays for each request. +pragma solidity ^0.8.7; + +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; +import {VRFV2WrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UNAUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract RandomNumberDirectFundingConsumerV2 is VRFV2WrapperConsumerBase, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords, uint256 paid); + event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + + error InsufficientFunds(uint256 balance, uint256 paid); + error RequestNotFound(uint256 requestId); + error LinkTransferError(address sender, address receiver, uint256 amount); + + struct RequestStatus { + uint256 paid; // amount paid in link + bool fulfilled; // whether the request has been successfully fulfilled + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // configuration: https://docs.chain.link/vrf/v2/direct-funding/supported-networks#configurations + constructor( + address _linkAddress, + address _wrapperAddress + ) ConfirmedOwner(msg.sender) VRFV2WrapperConsumerBase(_linkAddress, _wrapperAddress) {} + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + // The default is 3, but you can set this higher. + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords. + function requestRandomWords( + uint32 _callbackGasLimit, + uint16 _requestConfirmations, + uint32 _numWords + ) external onlyOwner returns (uint256 requestId) { + requestId = requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords); + uint256 paid = VRF_V2_WRAPPER.calculateRequestPrice(_callbackGasLimit); + uint256 balance = LINK.balanceOf(address(this)); + if (balance < paid) revert InsufficientFunds(balance, paid); + s_requests[requestId] = RequestStatus({paid: paid, randomWords: new uint256[](0), fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, _numWords, paid); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + RequestStatus storage request = s_requests[_requestId]; + if (request.paid == 0) revert RequestNotFound(_requestId); + request.fulfilled = true; + request.randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords, request.paid); + } + + function getNumberOfRequests() external view returns (uint256) { + return requestIds.length; + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + RequestStatus memory request = s_requests[_requestId]; + if (request.paid == 0) revert RequestNotFound(_requestId); + return (request.paid, request.fulfilled, request.randomWords); + } + + /** + * Allow withdraw of Link tokens from the contract + */ + function withdrawLink( + address _receiver + ) public onlyOwner { + bool success = LINK.transfer(_receiver, LINK.balanceOf(address(this))); + if (!success) { + revert LinkTransferError(msg.sender, _receiver, LINK.balanceOf(address(this))); + } + } +} +``` + Your RemixIDE file explorer should display the opened contracts: ### Select the correct RemixIDE environment @@ -3423,6 +5393,181 @@ contract VRFD20 is VRFConsumerBaseV2 { ``` +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol"; +import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol"; + +/** + * @notice A Chainlink VRF consumer which uses randomness to mimic the rolling + * of a 20 sided dice + */ + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract VRFD20 is VRFConsumerBaseV2 { + uint256 private constant ROLL_IN_PROGRESS = 42; + + VRFCoordinatorV2Interface COORDINATOR; + + // Your subscription ID. + uint64 s_subscriptionId; + + // Sepolia coordinator. For other networks, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + address vrfCoordinator = 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + bytes32 s_keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 40,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 callbackGasLimit = 40_000; + + // The default is 3, but you can set this higher. + uint16 requestConfirmations = 3; + + // For this example, retrieve 1 random value in one request. + // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. + uint32 numWords = 1; + address s_owner; + + // map rollers to requestIds + mapping(uint256 => address) private s_rollers; + // map vrf results to rollers + mapping(address => uint256) private s_results; + + event DiceRolled(uint256 indexed requestId, address indexed roller); + event DiceLanded(uint256 indexed requestId, uint256 indexed result); + + /** + * @notice Constructor inherits VRFConsumerBaseV2 + * + * @dev NETWORK: Sepolia + * + * @param subscriptionId subscription id that this consumer contract can use + */ + constructor( + uint64 subscriptionId + ) VRFConsumerBaseV2(vrfCoordinator) { + COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); + s_owner = msg.sender; + s_subscriptionId = subscriptionId; + } + + /** + * @notice Requests randomness + * @dev Warning: if the VRF response is delayed, avoid calling requestRandomness repeatedly + * as that would give miners/VRF operators latitude about which VRF response arrives first. + * @dev You must review your implementation details with extreme care. + * + * @param roller address of the roller + */ + function rollDice( + address roller + ) public onlyOwner returns (uint256 requestId) { + require(s_results[roller] == 0, "Already rolled"); + // Will revert if subscription is not set and funded. + requestId = + COORDINATOR.requestRandomWords(s_keyHash, s_subscriptionId, requestConfirmations, callbackGasLimit, numWords); + + s_rollers[requestId] = roller; + s_results[roller] = ROLL_IN_PROGRESS; + emit DiceRolled(requestId, roller); + } + + /** + * @notice Callback function used by VRF Coordinator to return the random number to this contract. + * + * @dev Some action on the contract state should be taken here, like storing the result. + * @dev WARNING: take care to avoid having multiple VRF requests in flight if their order of arrival would result + * in contract states with different outcomes. Otherwise miners or the VRF operator would could take advantage + * by controlling the order. + * @dev The VRF Coordinator will only send this function verified responses, and the parent VRFConsumerBaseV2 + * contract ensures that this method only receives randomness from the designated VRFCoordinator. + * + * @param requestId uint256 + * @param randomWords uint256[] The random result returned by the oracle. + */ + function fulfillRandomWords( + uint256 requestId, + uint256[] memory randomWords + ) internal override { + uint256 d20Value = (randomWords[0] % 20) + 1; + s_results[s_rollers[requestId]] = d20Value; + emit DiceLanded(requestId, d20Value); + } + + /** + * @notice Get the house assigned to the player once the address has rolled + * @param player address + * @return house as a string + */ + function house( + address player + ) public view returns (string memory) { + require(s_results[player] != 0, "Dice not rolled"); + require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); + return getHouseName(s_results[player]); + } + + /** + * @notice Get the house name from the id + * @param id uint256 + * @return house name string + */ + function getHouseName( + uint256 id + ) private pure returns (string memory) { + string[20] memory houseNames = [ + "Targaryen", + "Lannister", + "Stark", + "Tyrell", + "Baratheon", + "Martell", + "Tully", + "Bolton", + "Greyjoy", + "Arryn", + "Frey", + "Mormont", + "Tarley", + "Dayne", + "Umber", + "Valeryon", + "Manderly", + "Clegane", + "Glover", + "Karstark" + ]; + return houseNames[id - 1]; + } + + modifier onlyOwner() { + require(msg.sender == s_owner); + _; + } +} +``` + You have now completed all necessary functions to generate randomness and assign the user a *Game of Thrones* house. We've added a few helper functions in there to make using the contract easier and more flexible. You can deploy and interact with the complete contract in Remix. ## How do I deploy to testnet? @@ -3593,6 +5738,109 @@ Build and deploy the contract on Sepolia. 1. Open the [`VRFv2Consumer.sol` contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFv2Consumer.sol) in Remix. + ```sol + // SPDX-License-Identifier: MIT + // An example of a consumer contract that relies on a subscription for funding. + pragma solidity ^0.8.7; + + import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; + import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol"; + import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol"; + + /** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + + /** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + contract VRFv2Consumer is VRFConsumerBaseV2, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords); + + struct RequestStatus { + bool fulfilled; // whether the request has been successfully fulfilled + bool exists; // whether a requestId exists + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + VRFCoordinatorV2Interface COORDINATOR; + + // Your subscription ID. + uint64 s_subscriptionId; + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/docs/vrf/v2/subscription/supported-networks/#configurations + bytes32 keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 100,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. + uint32 numWords = 2; + + /** + * HARDCODED FOR SEPOLIA + * COORDINATOR: 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625 + */ + constructor( + uint64 subscriptionId + ) VRFConsumerBaseV2(0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625) ConfirmedOwner(msg.sender) { + COORDINATOR = VRFCoordinatorV2Interface(0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625); + s_subscriptionId = subscriptionId; + } + + // Assumes the subscription is funded sufficiently. + function requestRandomWords() external onlyOwner returns (uint256 requestId) { + // Will revert if subscription is not set and funded. + requestId = + COORDINATOR.requestRandomWords(keyHash, s_subscriptionId, requestConfirmations, callbackGasLimit, numWords); + s_requests[requestId] = RequestStatus({randomWords: new uint256[](0), exists: true, fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].exists, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].exists, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.fulfilled, request.randomWords); + } + } + ``` + 2. On the **Compile** tab in Remix, compile the `VRFv2Consumer.sol` contract. 3. Configure your deployment. On the **Deploy** tab in Remix, select the **Injected Provider** environment, select the `VRFv2Consumer` contract from the contract list, and specify your `subscriptionId` so the constructor can set it. @@ -3640,6 +5888,109 @@ You deployed a simple contract that can request and receive random values from C In this example, your MetaMask wallet is the subscription owner and you created a consuming contract to use that subscription. The consuming contract uses static configuration parameters. +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that relies on a subscription for funding. +pragma solidity ^0.8.7; + +import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; +import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol"; +import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract VRFv2Consumer is VRFConsumerBaseV2, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords); + + struct RequestStatus { + bool fulfilled; // whether the request has been successfully fulfilled + bool exists; // whether a requestId exists + uint256[] randomWords; + } + + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + VRFCoordinatorV2Interface COORDINATOR; + + // Your subscription ID. + uint64 s_subscriptionId; + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/docs/vrf/v2/subscription/supported-networks/#configurations + bytes32 keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 100,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. + uint32 numWords = 2; + + /** + * HARDCODED FOR SEPOLIA + * COORDINATOR: 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625 + */ + constructor( + uint64 subscriptionId + ) VRFConsumerBaseV2(0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625) ConfirmedOwner(msg.sender) { + COORDINATOR = VRFCoordinatorV2Interface(0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625); + s_subscriptionId = subscriptionId; + } + + // Assumes the subscription is funded sufficiently. + function requestRandomWords() external onlyOwner returns (uint256 requestId) { + // Will revert if subscription is not set and funded. + requestId = + COORDINATOR.requestRandomWords(keyHash, s_subscriptionId, requestConfirmations, callbackGasLimit, numWords); + s_requests[requestId] = RequestStatus({randomWords: new uint256[](0), exists: true, fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords( + uint256 _requestId, + uint256[] memory _randomWords + ) internal override { + require(s_requests[_requestId].exists, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords); + } + + function getRequestStatus( + uint256 _requestId + ) external view returns (bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].exists, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.fulfilled, request.randomWords); + } +} +``` + The parameters define how your requests will be processed. You can find the values for your network in the [Configuration](/vrf/v2/subscription/supported-networks) page. - `uint64 s_subscriptionId`: The subscription ID that this contract uses for funding requests. @@ -3714,6 +6065,137 @@ In this example, the contract operates as a subscription owner and can run funct Subscription owners and consumers do not have to be separate. This contract not only allows adding consumers with `addConsumer(address consumerAddress)` but can also act as a consumer by running its own `requestRandomWords()` function. This example contract includes a `createNewSubscription()` function in the `constructor()` that creates the subscription and adds itself as a consumer automatically when you deploy it. +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that also owns and manages the subscription +pragma solidity ^0.8.7; + +import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol"; + +import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol"; +import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol"; + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: + * https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ +contract VRFv2SubscriptionManager is VRFConsumerBaseV2 { + VRFCoordinatorV2Interface COORDINATOR; + LinkTokenInterface LINKTOKEN; + + // Sepolia coordinator. For other networks, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + address vrfCoordinator = 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625; + + // Sepolia LINK token contract. For other networks, see + // https://docs.chain.link/docs/vrf-contracts/#configurations + address link_token_contract = 0x779877A7B0D9E8603169DdbD7836e478b4624789; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + bytes32 keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; + + // A reasonable default is 100000, but this value could be different + // on other networks. + uint32 callbackGasLimit = 100_000; + + // The default is 3, but you can set this higher. + uint16 requestConfirmations = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. + uint32 numWords = 2; + + // Storage parameters + uint256[] public s_randomWords; + uint256 public s_requestId; + uint64 public s_subscriptionId; + address s_owner; + + constructor() VRFConsumerBaseV2(vrfCoordinator) { + COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); + LINKTOKEN = LinkTokenInterface(link_token_contract); + s_owner = msg.sender; + //Create a new subscription when you deploy the contract. + createNewSubscription(); + } + + // Assumes the subscription is funded sufficiently. + function requestRandomWords() external onlyOwner { + // Will revert if subscription is not set and funded. + s_requestId = + COORDINATOR.requestRandomWords(keyHash, s_subscriptionId, requestConfirmations, callbackGasLimit, numWords); + } + + function fulfillRandomWords( + uint256, + /* requestId */ + uint256[] memory randomWords + ) internal override { + s_randomWords = randomWords; + } + + // Create a new subscription when the contract is initially deployed. + function createNewSubscription() private onlyOwner { + s_subscriptionId = COORDINATOR.createSubscription(); + // Add this contract as a consumer of its own subscription. + COORDINATOR.addConsumer(s_subscriptionId, address(this)); + } + + // Assumes this contract owns link. + // 1000000000000000000 = 1 LINK + function topUpSubscription( + uint256 amount + ) external onlyOwner { + LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subscriptionId)); + } + + function addConsumer( + address consumerAddress + ) external onlyOwner { + // Add a consumer contract to the subscription. + COORDINATOR.addConsumer(s_subscriptionId, consumerAddress); + } + + function removeConsumer( + address consumerAddress + ) external onlyOwner { + // Remove a consumer contract from the subscription. + COORDINATOR.removeConsumer(s_subscriptionId, consumerAddress); + } + + function cancelSubscription( + address receivingWallet + ) external onlyOwner { + // Cancel the subscription and send the remaining LINK to a wallet address. + COORDINATOR.cancelSubscription(s_subscriptionId, receivingWallet); + s_subscriptionId = 0; + } + + // Transfer this contract's funds to an address. + // 1000000000000000000 = 1 LINK + function withdraw( + uint256 amount, + address to + ) external onlyOwner { + LINKTOKEN.transfer(to, amount); + } + + modifier onlyOwner() { + require(msg.sender == s_owner); + _; + } +} +``` + To use this contract, compile and deploy it in Remix. 1. Open the contract in [Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFv2SubscriptionManager.sol). @@ -3750,6 +6232,27 @@ To use this contract, compile and deploy it in Remix. You can fund a subscription and request randomness in a single transaction. You must estimate how much the transaction might cost and determine the amount of funding to send to the subscription yourself. See the [Subscription billing](/vrf/v2/subscription/#subscription-limits) page to learn how to estimate request costs. +```sol +// Assumes this contract owns link +// You must estimate LINK cost yourself based on the gas lane and limits. +// 1_000_000_000_000_000_000 = 1 LINK +function fundAndRequestRandomWords(uint256 amount) external onlyOwner { + LINKTOKEN.transferAndCall( + address(COORDINATOR), + amount, + abi.encode(s_subscriptionId) + ); + // Will revert if subscription is not set and funded. + s_requestId = COORDINATOR.requestRandomWords( + keyHash, + s_subscriptionId, + requestConfirmations, + callbackGasLimit, + numWords + ); +} +``` + Add this function to your contracts if you need to provide funding simultaneously with your requests. The `transferAndCall()` function sends LINK from your contract to the subscription, and the `requestRandomWords()` function requests the random words. Your contract still needs the `fulfillRandomWords()` callback function to receive the random values. --- @@ -3789,8 +6292,115 @@ Complete the following tasks to test your VRF v2 consumer locally: Open *VRFCoordinatorV2Mock* and compile in Remix: +```sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import "@chainlink/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol"; +``` + Open *VRFv2Consumer* and compile in Remix: +```sol +// SPDX-License-Identifier: MIT +// An example of a consumer contract that relies on a subscription for funding. +pragma solidity ^0.8.7; + +import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol"; +import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/** + * @title The RandomNumberConsumerV2 contract + * @notice A contract that gets random values from Chainlink VRF V2 + */ +contract RandomNumberConsumerV2 is VRFConsumerBaseV2 { + VRFCoordinatorV2Interface immutable COORDINATOR; + + // Your subscription ID. + uint64 immutable s_subscriptionId; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + bytes32 immutable s_keyHash; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 100,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 constant CALLBACK_GAS_LIMIT = 100_000; + + // The default is 3, but you can set this higher. + uint16 constant REQUEST_CONFIRMATIONS = 3; + + // For this example, retrieve 2 random values in one request. + // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. + uint32 constant NUM_WORDS = 2; + + uint256[] public s_randomWords; + uint256 public s_requestId; + address s_owner; + + event ReturnedRandomness(uint256[] randomWords); + + /** + * @notice Constructor inherits VRFConsumerBaseV2 + * + * @param subscriptionId - the subscription ID that this contract uses for funding requests + * @param vrfCoordinator - coordinator, check https://docs.chain.link/docs/vrf-contracts/#configurations + * @param keyHash - the gas lane to use, which specifies the maximum gas price to bump to + */ + constructor( + uint64 subscriptionId, + address vrfCoordinator, + bytes32 keyHash + ) VRFConsumerBaseV2(vrfCoordinator) { + COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); + s_keyHash = keyHash; + s_owner = msg.sender; + s_subscriptionId = subscriptionId; + } + + /** + * @notice Requests randomness + * Assumes the subscription is funded sufficiently; "Words" refers to unit of data in Computer Science + */ + function requestRandomWords() external onlyOwner { + // Will revert if subscription is not set and funded. + s_requestId = + COORDINATOR.requestRandomWords(s_keyHash, s_subscriptionId, REQUEST_CONFIRMATIONS, CALLBACK_GAS_LIMIT, NUM_WORDS); + } + + /** + * @notice Callback function used by VRF Coordinator + * + * @param - id of the request + * @param randomWords - array of random results from VRF Coordinator + */ + function fulfillRandomWords( + uint256, + /* requestId */ + uint256[] memory randomWords + ) internal override { + s_randomWords = randomWords; + emit ReturnedRandomness(randomWords); + } + + modifier onlyOwner() { + require(msg.sender == s_owner); + _; + } +} +``` + Your RemixIDE file explorer should display *VRFCoordinatorV2Mock.sol* and *VRFv2Consumer.sol*: ### Deploy VRFCoordinatorV2Mock diff --git a/src/content/vrf/v2-5/supported-networks.mdx b/src/content/vrf/v2-5/supported-networks.mdx index be0b59fc33e..ff8ae743a54 100644 --- a/src/content/vrf/v2-5/supported-networks.mdx +++ b/src/content/vrf/v2-5/supported-networks.mdx @@ -215,7 +215,7 @@ Testnet LINK is available from https://faucets.chain.link/fuji | VRF Coordinator | <Address contractUrl="https://basescan.org/address/0xd5D517aBE5cF79B7e95eC98dB0f0277788aFF634" eventName="docs_product_interaction" additionalInfo={{ product: "VRF", action: "vrfCoordinator_copied", extraInfo1: "Subscription2.5", extraInfo2: "Base Mainnet"}} /> | | 2 gwei Key Hash | <CopyText text="0x00b81b5a830cb0a4009fbd8904de511e28631e62ce5ad231373d3cdad373ccab" code/> | | 30 gwei Key Hash | <CopyText text="0xdc2f87677b01473c763cb0aee938ed3341512f6057324a584e5944e786144d70" code/> | -| Premium percentage <br/> (paying with BASE) | 60 | +| Premium percentage <br/> (paying with BASE Mainnet ETH) | 60 | | Premium percentage <br/> (paying with LINK) | 50 | | Max Gas Limit | 2,500,000 | | Minimum Confirmations | 0 | @@ -230,7 +230,7 @@ Testnet LINK is available from https://faucets.chain.link/fuji | VRF Coordinator | <Address contractUrl="https://basescan.org/address/0xd5D517aBE5cF79B7e95eC98dB0f0277788aFF634" eventName="docs_product_interaction" additionalInfo={{ product: "VRF", action: "vrfCoordinator_copied", extraInfo1: "Direct2.5", extraInfo2: "Base Mainnet"}} /> | | 2 gwei Key Hash | <CopyText text="0x00b81b5a830cb0a4009fbd8904de511e28631e62ce5ad231373d3cdad373ccab" code/> | | 30 gwei Key Hash | <CopyText text="0xdc2f87677b01473c763cb0aee938ed3341512f6057324a584e5944e786144d70" code/> | | -| Premium percentage <br/> (paying with BASE) | 60 | +| Premium percentage <br/> (paying with BASE Mainnet ETH) | 60 | | Premium percentage <br/> (paying with LINK) | 50 | | Minimum Confirmations | 0 | | Maximum Confirmations | 200 | diff --git a/src/content/vrf/v2/direct-funding/examples/test-locally.mdx b/src/content/vrf/v2/direct-funding/examples/test-locally.mdx index ee1aff0fdce..58db326b44f 100644 --- a/src/content/vrf/v2/direct-funding/examples/test-locally.mdx +++ b/src/content/vrf/v2/direct-funding/examples/test-locally.mdx @@ -27,7 +27,7 @@ This guide explains how to test Chainlink VRF v2 on a [Remix IDE](https://remix- Complete the following tasks to test your VRF v2 consumer locally: 1. Deploy the [VRFCoordinatorV2Mock](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol). This contract is a mock of the [VRFCoordinatorV2](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol) contract. -1. Deploy the [MockV3Aggregator](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/shared/mocks/MockV3Aggregator.sol) contract. +1. Deploy the [MockV3Aggregator](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/tests/MockV3Aggregator.sol) contract. 1. Deploy the [LinkToken](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/shared/token/ERC677/LinkToken.sol) contract. 1. Deploy the [VRFV2Wrapper](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/VRFV2Wrapper.sol) contract. 1. Call the VRFV2Wrapper [setConfig function](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/VRFV2Wrapper.sol#L119) to set wrapper specific parameters. diff --git a/src/db/feedCategories.ts b/src/db/feedCategories.ts index b08864fb2c4..60003381a76 100644 --- a/src/db/feedCategories.ts +++ b/src/db/feedCategories.ts @@ -35,15 +35,23 @@ export const FEED_CATEGORY_CONFIG = { high: { key: "high", name: "High Market Risk", - icon: "🔴", + icon: "🟠", title: "High Market Risk - Feeds that deliver a heightened degree of some of the risk factors associated with Medium Market Risk Feeds, or a separate risk that makes the market price subject to uncertainty or volatile. In using a high market risk data feed you acknowledge that you understand the risks associated with such a feed and that you are solely responsible for monitoring and mitigating such risks.", link: "/data-feeds/selecting-data-feeds#-high-market-risk-feeds", }, + veryhigh: { + key: "veryhigh", + name: "Very High Market Risk", + icon: "🔴", + title: + "Very High Market Risk - Feeds with significant risk factors that require careful consideration. Users must thoroughly evaluate and understand all associated risks before use.", + link: "/data-feeds/selecting-data-feeds#-very-high-market-risk-feeds", + }, new: { key: "new", name: "New Token", - icon: "🟠", + icon: "🆕", title: "New Token - Tokens without the historical data required to implement a risk assessment framework may be launched in this category. Users must understand the additional market and volatility risks inherent with such assets. Users of New Token Feeds are responsible for independently verifying the liquidity and stability of the assets priced by feeds that they use.", link: "/data-feeds/selecting-data-feeds#-new-token-feeds", @@ -72,11 +80,12 @@ export type CategoryKey = keyof typeof FEED_CATEGORY_CONFIG Small helpers =========================== */ -const TABLE = "docs_feeds_risk" +const TABLE = "prod_feeds_risk_docs" const normalizeKey = (v?: string | null): CategoryKey | undefined => { if (!v) return undefined - const key = v.toLowerCase() as CategoryKey + // Handle "very high" from DB → "veryhigh" config key + const key = v.toLowerCase().replace(/\s+/g, "") as CategoryKey return key in FEED_CATEGORY_CONFIG ? key : undefined } diff --git a/src/db/supabase.ts b/src/db/supabase.ts index 5d62fb69d0a..206ce4b3c91 100644 --- a/src/db/supabase.ts +++ b/src/db/supabase.ts @@ -1,9 +1,10 @@ import { createClient } from "@supabase/supabase-js" +// Try PUBLIC_ prefixed vars first (needed for client-side/browser access in Astro) +// These work both locally and on Vercel when properly configured const supabaseUrl = import.meta.env.PUBLIC_SUPABASE_URL const supabaseKey = import.meta.env.PUBLIC_SUPABASE_ANON_KEY -// Export a function that safely creates the client export function getSupabaseClient() { if (!supabaseUrl || !supabaseKey) { return null @@ -11,5 +12,4 @@ export function getSupabaseClient() { return createClient(supabaseUrl, supabaseKey) } -// Export the client instance (may be null) export const supabase = getSupabaseClient() diff --git a/src/features/ccip/SvmCrossChainTokenProductionPrerequisites.mdx b/src/features/ccip/SvmCrossChainTokenProductionPrerequisites.mdx index 0ffd03021b7..e8ba23b8110 100644 --- a/src/features/ccip/SvmCrossChainTokenProductionPrerequisites.mdx +++ b/src/features/ccip/SvmCrossChainTokenProductionPrerequisites.mdx @@ -205,7 +205,7 @@ This tutorial implements production-grade cross-chain tokens using a three-termi | Terminal | Repository | Purpose | Commands | | -------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------- | -| **Terminal 1** | [CCIP Solana base58 Generator](https://github.com/smartcontractkit/ccip-solana-base58-generator) | Generate governance transactions | `pnpm bs58` | +| **Terminal 1** | [CCIP Solana base58 Generator](https://github.com/smartcontractkit/ccip-solana-bs58-generator) | Generate governance transactions | `pnpm bs58` | | **Terminal 2** | [Smart Contract Examples (Hardhat)](https://github.com/smartcontractkit/smart-contract-examples/tree/main/ccip/cct/hardhat) | Deploy EVM components | `npx hardhat` | | **Terminal 3** | [Solana Starter Kit](https://github.com/smartcontractkit/solana-starter-kit) | Test cross-chain transfers | `yarn` | diff --git a/src/features/chainlink-automation/common/ChainlinkAutomation.astro b/src/features/chainlink-automation/common/ChainlinkAutomation.astro index bea2da769b8..bf4bc6b154b 100644 --- a/src/features/chainlink-automation/common/ChainlinkAutomation.astro +++ b/src/features/chainlink-automation/common/ChainlinkAutomation.astro @@ -2,10 +2,11 @@ import StreamsLookupInterfaceComponent from "./StreamsLookupInterface.mdx" import ILogAutomationComponent from "./iLogAutomation.mdx" import DeprecationCalloutComponent from "./deprecation.mdx" +import CreCalloutComponent from "./cre-callout.mdx" export type Props = { section?: "ilogautomation" | "streamslookup" - callout?: "deprecation" + callout?: "deprecation" | "cre" } const { section, callout } = Astro.props as Props --- @@ -15,3 +16,5 @@ const { section, callout } = Astro.props as Props {section === "streamslookup" && <StreamsLookupInterfaceComponent />} {callout === "deprecation" && <DeprecationCalloutComponent />} + +{callout === "cre" && <CreCalloutComponent />} diff --git a/src/features/chainlink-automation/common/cre-callout.mdx b/src/features/chainlink-automation/common/cre-callout.mdx new file mode 100644 index 00000000000..63c3f2219d3 --- /dev/null +++ b/src/features/chainlink-automation/common/cre-callout.mdx @@ -0,0 +1,7 @@ +import { Aside } from "@components" + +<Aside type="tip" title="Building a new automation task?"> + Check out the [Chainlink Runtime Environment (CRE)](/cre), our latest environment for building and running verifiable + workflows with enhanced capabilities, improved developer experience, and support for everything Automation can do—and + more. +</Aside> diff --git a/src/features/chainlink-automation/components/NetworkIcons.tsx b/src/features/chainlink-automation/components/NetworkIcons.tsx index e8ba7419b95..52b60afa43c 100644 --- a/src/features/chainlink-automation/components/NetworkIcons.tsx +++ b/src/features/chainlink-automation/components/NetworkIcons.tsx @@ -1,6 +1,7 @@ /** @jsxImportSource preact */ import { useEffect } from "preact/compat" import { normalizeTechnologyName } from "@features/utils/index.ts" +import { getNetworkIconUrl } from "~/config/data/ccip/data.ts" // Component to add icons to network headings in the Automation supported-networks page export default function NetworkIcons() { @@ -42,13 +43,13 @@ export default function NetworkIcons() { // Get the normalized technology name for icon path const normalizedTech = normalizeTechnologyName(technology) - const iconPath = `/assets/chains/${normalizedTech}.svg` + const iconPath = getNetworkIconUrl(normalizedTech) console.log(`Adding icon for ${technology}, normalized to ${normalizedTech}, path: ${iconPath}`) // Create the icon element const icon = document.createElement("img") - icon.src = iconPath + icon.src = iconPath || "" icon.alt = `${technology} icon` icon.style.width = "24px" icon.style.height = "24px" diff --git a/src/features/chainlink-functions/common/ChainlinkFunctions.astro b/src/features/chainlink-functions/common/ChainlinkFunctions.astro index 89dc99c65d7..afd02141344 100644 --- a/src/features/chainlink-functions/common/ChainlinkFunctions.astro +++ b/src/features/chainlink-functions/common/ChainlinkFunctions.astro @@ -5,6 +5,7 @@ import CustomAutomatedFunctionsConsumerComponent from "./CustomAutomatedFunction import GuidesPrerequisitesComponent from "./GuidesPrerequisites.mdx" import GuidesWithAutomationPrerequisitesComponent from "./GuidesWithAutomationPrerequisites.mdx" import DenoImportNotesComponent from "./DenoImportNotes.mdx" +import CreCalloutComponent from "./cre-callout.mdx" export type Props = { section?: @@ -14,8 +15,9 @@ export type Props = { | "prerequisites-guides" | "prerequisites-guides-with-automation" | "deno-importe-notes" + callout?: "cre" } -const { section } = Astro.props as Props +const { section, callout } = Astro.props as Props --- {section === "functions-consumer" && <FunctionsConsumerComponent />} @@ -29,3 +31,5 @@ const { section } = Astro.props as Props {section === "prerequisites-guides-with-automation" && <GuidesWithAutomationPrerequisitesComponent />} {section === "deno-importe-notes" && <DenoImportNotesComponent />} + +{callout === "cre" && <CreCalloutComponent />} diff --git a/src/features/chainlink-functions/common/cre-callout.mdx b/src/features/chainlink-functions/common/cre-callout.mdx new file mode 100644 index 00000000000..3d34ef39ee5 --- /dev/null +++ b/src/features/chainlink-functions/common/cre-callout.mdx @@ -0,0 +1,7 @@ +import { Aside } from "@components" + +<Aside type="tip" title="Integrating offchain computation or data?"> + Check out the [Chainlink Runtime Environment (CRE)](/cre), our latest environment for building and running verifiable + workflows with enhanced capabilities, improved developer experience, and support for everything Chainlink Functions + can do—and more. +</Aside> diff --git a/src/features/chainlink-functions/components/NetworkIcons.tsx b/src/features/chainlink-functions/components/NetworkIcons.tsx index 3942514c5f4..03184e362ae 100644 --- a/src/features/chainlink-functions/components/NetworkIcons.tsx +++ b/src/features/chainlink-functions/components/NetworkIcons.tsx @@ -1,6 +1,7 @@ /** @jsxImportSource preact */ import { useEffect } from "preact/compat" import { normalizeTechnologyName } from "@features/utils/index.ts" +import { getNetworkIconUrl } from "~/config/data/ccip/data.ts" // List of valid network names that should have icons const VALID_NETWORKS = ["Arbitrum", "Avalanche", "BASE", "Celo", "Ethereum", "OP", "Polygon", "Soneium", "ZKSync"] @@ -30,11 +31,11 @@ export default function NetworkIcons() { // Get the normalized technology name for the icon path const normalizedTech = normalizeTechnologyName(technology) - const iconPath = `/assets/chains/${normalizedTech}.svg` + const iconPath = getNetworkIconUrl(normalizedTech) // Create the icon element const icon = document.createElement("img") - icon.src = iconPath + icon.src = iconPath || "" icon.alt = `${technology} icon` icon.style.width = "24px" icon.style.height = "24px" diff --git a/src/features/data-streams/common/MarketEventsTabs.astro b/src/features/data-streams/common/MarketEventsTabs.astro new file mode 100644 index 00000000000..25fa87baa76 --- /dev/null +++ b/src/features/data-streams/common/MarketEventsTabs.astro @@ -0,0 +1,20 @@ +--- +import { PageTabs } from "@components" + +const marketEventsPages = [ + { + name: "Standard (v8)", + url: "/data-streams/rwa-streams/handling-market-events", + }, + { + name: "Advanced (v11)", + url: "/data-streams/rwa-streams/handling-market-events-v11", + }, +] +--- + +<PageTabs + pages={marketEventsPages} + headerTitle="Market Events Guide" + headerDescription="Choose the guide version that matches your schema." +/> diff --git a/src/features/data-streams/common/ReportSchemaTabs.astro b/src/features/data-streams/common/ReportSchemaTabs.astro index 60d2d5349fe..d3b6101ffe7 100644 --- a/src/features/data-streams/common/ReportSchemaTabs.astro +++ b/src/features/data-streams/common/ReportSchemaTabs.astro @@ -31,7 +31,7 @@ const allReportSchemaPages = [ url: "/data-streams/reference/report-schema-v11", }, { - name: "NAV (v9)", + name: "SmartData (v9)", url: "/data-streams/reference/report-schema-v9", }, { diff --git a/src/features/data/api/backend.ts b/src/features/data/api/backend.ts index fb3dc24aa13..c4ee9a320bf 100644 --- a/src/features/data/api/backend.ts +++ b/src/features/data/api/backend.ts @@ -2,14 +2,17 @@ import EleventyFetch from "@11ty/eleventy-fetch" import { ChainMetadata, mergeWithMVRFeeds } from "./index.ts" import { Chain, POR_MVR_FEEDS_URL } from "../chains.ts" -export const getServerSideChainMetadata = async (chains: Chain[]): Promise<Record<string, ChainMetadata>> => { +export const getServerSideChainMetadata = async ( + chains: Chain[], + skipCache = false +): Promise<Record<string, ChainMetadata>> => { const cache = {} for (const chain of chains) { const requests = chain.networks.map((nw) => nw?.rddUrl ? EleventyFetch(nw?.rddUrl, { - duration: "1d", // save for 1 day + duration: skipCache ? "0s" : "1d", // No cache if skipCache is true type: "json", // we'll parse JSON for you }).then((metadata) => ({ ...nw, @@ -26,7 +29,7 @@ export const getServerSideChainMetadata = async (chains: Chain[]): Promise<Recor try { const mvrFeeds = await EleventyFetch(POR_MVR_FEEDS_URL, { - duration: "1d", + duration: skipCache ? "0s" : "1d", type: "json", }) diff --git a/src/features/data/chains.ts b/src/features/data/chains.ts index 04c36dd89e3..90001d6a055 100644 --- a/src/features/data/chains.ts +++ b/src/features/data/chains.ts @@ -3,7 +3,7 @@ import { ChainMetadata } from "./api/index.ts" // Cross-networks export const POR_MVR_FEEDS_URL = "https://reference-data-directory.vercel.app/por-data-feeds.json" -type ChainTags = ("default" | "smartData" | "rates" | "streams" | "usGovernmentMacroeconomicData")[] +type ChainTags = ("default" | "smartData" | "rates" | "streams" | "usGovernmentMacroeconomicData" | "tokenizedEquity")[] export interface ChainNetwork { name: string explorerUrl: string @@ -254,7 +254,7 @@ export const CHAINS: Chain[] = [ title: "Data Feeds", img: "/assets/chains/ethereum.svg", networkStatusUrl: "https://ethstats.dev/", - tags: ["default", "smartData", "rates", "usGovernmentMacroeconomicData"], + tags: ["default", "smartData", "rates", "usGovernmentMacroeconomicData", "tokenizedEquity"], supportedFeatures: ["vrfSubscription", "vrfDirectFunding", "feeds"], networks: [ { @@ -264,7 +264,7 @@ export const CHAINS: Chain[] = [ rddUrl: "https://reference-data-directory.vercel.app/feeds-mainnet.json", rddBundleUrl: "https://reference-data-directory.vercel.app/bundle-proxies-mainnet.json", queryString: "ethereum-mainnet", - tags: ["smartData", "usGovernmentMacroeconomicData"], + tags: ["smartData", "usGovernmentMacroeconomicData", "tokenizedEquity"], }, { name: "Sepolia Testnet", @@ -453,13 +453,31 @@ export const CHAINS: Chain[] = [ }, ], }, + { + page: "MegaETH", + label: "MegaETH", + title: "MegaETH Data Feeds", + img: "/assets/chains/megaeth.svg", + networkStatusUrl: "https://uptime.megaeth.com/", + tags: ["default"], + supportedFeatures: ["feeds"], + networks: [ + { + name: "MegaETH Mainnet (Private)", + explorerUrl: "https://megaeth.blockscout.com/address/%s", + networkType: "mainnet", + rddUrl: "https://reference-data-directory.vercel.app/feeds-megaeth-mainnet.json", + queryString: "megaeth-mainnet", + }, + ], + }, { page: "monad", title: "Monad Data Feeds", label: "Monad", img: "/assets/chains/monad.svg", - networkStatusUrl: "", - tags: ["default"], + networkStatusUrl: "https://monadvision.com/", + tags: ["default", "smartData"], supportedFeatures: ["feeds"], networks: [ { @@ -997,6 +1015,13 @@ export const ALL_CHAINS: Chain[] = [ rddUrl: "https://reference-data-directory.vercel.app/feeds-ethereum-mainnet-polygon-zkevm-1.json", queryString: "polygon-zkevm-mainnet", }, + { + name: "Ronin Mainnet", + explorerUrl: "https://app.roninchain.com/address/%s", + networkType: "mainnet", + rddUrl: "https://reference-data-directory.vercel.app/feeds-ronin-mainnet.json", + queryString: "ronin-mainnet", + }, { name: "Solana Mainnet", explorerUrl: "https://solscan.io/account/%s", diff --git a/src/features/feeds/components/FeedList.tsx b/src/features/feeds/components/FeedList.tsx index f3071e16b08..e5f87de7769 100644 --- a/src/features/feeds/components/FeedList.tsx +++ b/src/features/feeds/components/FeedList.tsx @@ -1,6 +1,6 @@ /** @jsxImportSource preact */ import { useEffect, useState, useRef, useMemo } from "preact/hooks" -import { MainnetTable, TestnetTable, StreamsNetworkAddressesTable } from "./Tables.tsx" +import { MainnetTable, TestnetTable, StreamsNetworkAddressesTable, StreamsTHead, StreamsTr } from "./Tables.tsx" import feedList from "./FeedList.module.css" import tableStyles from "./Tables.module.css" import { clsx } from "~/lib/clsx/clsx.ts" @@ -13,14 +13,16 @@ import { getFeedCategories } from "../../../db/feedCategories.js" import SectionWrapper from "~/components/SectionWrapper/SectionWrapper.tsx" import button from "@chainlink/design-system/button.module.css" import { updateTableOfContents } from "~/components/TableOfContents/tocStore.ts" -import alertIcon from "../../../components/Alert/Assets/alert-icon.svg" import { ChainSelector } from "~/components/ChainSelector/ChainSelector.tsx" +import { isFeedVisible } from "../utils/feedVisibility.ts" +import { updateUrlClean, clearFilters } from "./urlStateHelpers.ts" export type DataFeedType = | "default" | "smartdata" | "rates" | "usGovernmentMacroeconomicData" + | "tokenizedEquity" | "streamsCrypto" | "streamsRwa" | "streamsNav" @@ -29,6 +31,7 @@ export type DataFeedType = type SchemaFilterValue = "all" | "v8" | "v11" type StreamsRwaFeedTypeValue = "all" | "datalink" | "equities" | "forex" +type TradingHoursFilterValue = "all" | "regular" | "extended" | "overnight" type FilterOption<T extends string> = { label: string @@ -59,10 +62,19 @@ const feedTypeFilterOptions: FilterOption<StreamsRwaFeedTypeValue>[] = [ { label: "Forex Streams", value: "forex" }, ] +const tradingHoursFilterOptions: FilterOption<TradingHoursFilterValue>[] = [ + { label: "All Time Segments", value: "all" }, + { label: "Regular Hours", value: "regular" }, + { label: "Extended Hours", value: "extended" }, + { label: "Overnight Hours", value: "overnight" }, +] + const isSchemaFilterValue = (value: unknown): value is SchemaFilterValue => value === "all" || value === "v8" || value === "v11" const isStreamsRwaFeedTypeValue = (value: unknown): value is StreamsRwaFeedTypeValue => value === "all" || value === "datalink" || value === "equities" || value === "forex" +const isTradingHoursFilterValue = (value: unknown): value is TradingHoursFilterValue => + value === "all" || value === "regular" || value === "extended" || value === "overnight" const FilterDropdown = <T extends string>({ label, @@ -122,6 +134,8 @@ export const FeedList = ({ initialCache, allowNetworkTableExpansion = false, defaultNetworkTableExpanded = false, + force24x5Only = false, + tokenizedEquityProvider, }: { initialNetwork: string dataFeedType: DataFeedType @@ -129,6 +143,8 @@ export const FeedList = ({ initialCache?: Record<string, ChainMetadata> allowNetworkTableExpansion?: boolean defaultNetworkTableExpanded?: boolean + force24x5Only?: boolean + tokenizedEquityProvider?: string }) => { const chains = ecosystem === "deprecating" ? ALL_CHAINS : CHAINS const isStreams = @@ -259,10 +275,16 @@ export const FeedList = ({ }, []) // Regular query string states - const [searchValue, setSearchValue] = useQueryString("search", "") - const [testnetSearchValue, setTestnetSearchValue] = useQueryString("testnetSearch", "") - const [selectedFeedCategories, setSelectedFeedCategories] = useQueryString("categories", []) - const [currentPage, setCurrentPage] = useQueryString("page", "1") + const [searchValue, setSearchValue] = useQueryString("search") + const [testnetSearchValue, setTestnetSearchValue] = useQueryString("testnetSearch") + const [selectedFeedCategoriesRaw, setSelectedFeedCategories] = useQueryString("categories") + // Ensure categories is always an array + const selectedFeedCategories = Array.isArray(selectedFeedCategoriesRaw) + ? selectedFeedCategoriesRaw + : selectedFeedCategoriesRaw + ? [selectedFeedCategoriesRaw] + : [] + const [currentPage, setCurrentPage] = useQueryString("page") // Initialize all other states const [showCategoriesDropdown, setShowCategoriesDropdown] = useState<boolean>(false) @@ -282,12 +304,43 @@ export const FeedList = ({ const setTestnetStreamCategoryFilter = (next: StreamsRwaFeedTypeValue) => { setTestnetStreamCategoryFilterParam(next === "all" ? [] : next) } - const [showExtraDetails, setShowExtraDetails] = useState(false) + + // Checkbox states backed by URL params + const [showDetailsParam, setShowDetailsParam] = useQueryString("showDetails") + const showExtraDetails = showDetailsParam === "true" + const setShowExtraDetails = (value: boolean) => { + setShowDetailsParam(value ? "true" : "") + updateUrlClean({ showDetails: value || undefined }) + } + + const [showSvrParam, setShowSvrParam] = useQueryString("showSvr") + const showOnlySVR = showSvrParam === "true" + const setShowOnlySVR = (value: boolean) => { + setShowSvrParam(value ? "true" : "") + updateUrlClean({ showSvr: value || undefined }) + if (value) paginate(1) + } + + // MVR and DEX filters are not in URL (too specialized) const [showOnlyMVRFeeds, setShowOnlyMVRFeeds] = useState(false) const [showOnlyMVRFeedsTestnet, setShowOnlyMVRFeedsTestnet] = useState(false) - const [showOnlySVR, setShowOnlySVR] = useState(false) const [showOnlyDEXFeeds, setShowOnlyDEXFeeds] = useState(false) const [showOnlyDEXFeedsTestnet, setShowOnlyDEXFeedsTestnet] = useState(false) + const [show24x5FeedsParam, setShow24x5FeedsParam] = useQueryString("show24x5") + const show24x5Feeds = force24x5Only || show24x5FeedsParam === "true" + const setShow24x5Feeds = (value: boolean) => { + if (!force24x5Only) { + setShow24x5FeedsParam(value ? "true" : []) + } + } + const [tradingHoursFilterParam, setTradingHoursFilterParam] = useQueryString("tradingHours") + const tradingHoursFilter = + typeof tradingHoursFilterParam === "string" && isTradingHoursFilterValue(tradingHoursFilterParam) + ? tradingHoursFilterParam + : "all" + const setTradingHoursFilter = (next: TradingHoursFilterValue) => { + setTradingHoursFilterParam(next === "all" ? [] : next) + } const [rwaSchemaFilterParam, setRwaSchemaFilterParam] = useQueryString("schema") const rwaSchemaFilter = typeof rwaSchemaFilterParam === "string" && isSchemaFilterValue(rwaSchemaFilterParam) ? rwaSchemaFilterParam : "all" @@ -302,6 +355,21 @@ export const FeedList = ({ const setTestnetRwaSchemaFilter = (next: SchemaFilterValue) => { setTestnetRwaSchemaFilterParam(next === "all" ? [] : next) } + const [show24x5FeedsTestnetParam, setShow24x5FeedsTestnetParam] = useQueryString("testnetShow24x5") + const show24x5FeedsTestnet = force24x5Only || show24x5FeedsTestnetParam === "true" + const setShow24x5FeedsTestnet = (value: boolean) => { + if (!force24x5Only) { + setShow24x5FeedsTestnetParam(value ? "true" : []) + } + } + const [testnetTradingHoursFilterParam, setTestnetTradingHoursFilterParam] = useQueryString("testnetTradingHours") + const testnetTradingHoursFilter = + typeof testnetTradingHoursFilterParam === "string" && isTradingHoursFilterValue(testnetTradingHoursFilterParam) + ? testnetTradingHoursFilterParam + : "all" + const setTestnetTradingHoursFilter = (next: TradingHoursFilterValue) => { + setTestnetTradingHoursFilterParam(next === "all" ? [] : next) + } const [openDropdownId, setOpenDropdownId] = useState<string | null>(null) const handleDropdownToggle = (dropdownId: string, isOpen: boolean) => { setOpenDropdownId((current) => { @@ -312,17 +380,26 @@ export const FeedList = ({ }) } const closeAllDropdowns = () => setOpenDropdownId(null) - const paginate = (pageNumber) => setCurrentPage(String(pageNumber)) - // Disable pagination for deprecating feeds by using a very high page size - const addrPerPage = ecosystem === "deprecating" ? 10000 : 8 - const lastAddr = Number(currentPage) * addrPerPage + const paginate = (pageNumber) => { + const pageStr = String(pageNumber) + setCurrentPage(pageStr) + updateUrlClean({ page: pageNumber === 1 ? undefined : pageNumber }) + } + const addrPerPage = ecosystem === "deprecating" && isStreams ? 10 : ecosystem === "deprecating" ? 10000 : 8 + const currentPageNum = Number(currentPage) || 1 + const lastAddr = currentPageNum * addrPerPage const firstAddr = lastAddr - addrPerPage // Pagination for testnet table - const [testnetCurrentPage, setTestnetCurrentPage] = useQueryString("testnetPage", "1") - const testnetPaginate = (pageNumber) => setTestnetCurrentPage(String(pageNumber)) - const testnetAddrPerPage = ecosystem === "deprecating" ? 10000 : 8 - const testnetLastAddr = Number(testnetCurrentPage) * testnetAddrPerPage + const [testnetCurrentPage, setTestnetCurrentPage] = useQueryString("testnetPage") + const testnetPaginate = (pageNumber) => { + const pageStr = String(pageNumber) + setTestnetCurrentPage(pageStr) + updateUrlClean({ testnetPage: pageNumber === 1 ? undefined : pageNumber }) + } + const testnetAddrPerPage = ecosystem === "deprecating" && isStreams ? 10 : ecosystem === "deprecating" ? 10000 : 8 + const testnetPageNum = Number(testnetCurrentPage) || 1 + const testnetLastAddr = testnetPageNum * testnetAddrPerPage const testnetFirstAddr = testnetLastAddr - testnetAddrPerPage // Dynamic feed categories loaded from Supabase @@ -330,6 +407,7 @@ export const FeedList = ({ { key: "low", name: "Low Market Risk" }, { key: "medium", name: "Medium Market Risk" }, { key: "high", name: "High Market Risk" }, + { key: "veryhigh", name: "Very High Market Risk" }, { key: "custom", name: "Custom" }, { key: "new", name: "New Token" }, { key: "deprecating", name: "Deprecating" }, @@ -355,7 +433,20 @@ export const FeedList = ({ const [streamsChain] = useState(initialNetwork) const activeChain = isStreams ? streamsChain : currentNetwork - // Find the selected chain from available chains + // Filter chains by dataFeedType tag to get only chains that support this feed type + const filteredChainsByTag = useMemo(() => { + return chains.filter((chain) => { + if (dataFeedType.includes("streams")) return chain.tags?.includes("streams") ?? false + if (dataFeedType === "smartdata") return chain.tags?.includes("smartData") ?? false + if (dataFeedType === "rates") return chain.tags?.includes("rates") ?? false + if (dataFeedType === "usGovernmentMacroeconomicData") + return chain.tags?.includes("usGovernmentMacroeconomicData") ?? false + if (dataFeedType === "tokenizedEquity") return chain.tags?.includes("tokenizedEquity") ?? false + return chain.tags?.includes("default") ?? false + }) + }, [chains, dataFeedType]) + + // Find the selected chain from available chains (filtered by dataFeedType) const selectedChain = useMemo(() => { // During SSR, try to find the chain from URL param if activeChain is not available if (!activeChain) { @@ -364,21 +455,21 @@ export const FeedList = ({ const urlParams = new URLSearchParams(window.location.search) const networkParam = urlParams.get("network") if (networkParam) { - const foundFromUrl = chains.find((c) => c.page === networkParam) + const foundFromUrl = filteredChainsByTag.find((c) => c.page === networkParam) if (foundFromUrl) { return foundFromUrl } } } - return chains[0] // fallback only if no activeChain + return filteredChainsByTag[0] || chains[0] // fallback to first filtered chain } - const foundChain = chains.find((c) => c.page === activeChain) + const foundChain = filteredChainsByTag.find((c) => c.page === activeChain) if (!foundChain) { - return chains[0] + return filteredChainsByTag[0] || chains[0] } return foundChain - }, [activeChain, chains]) + }, [activeChain, filteredChainsByTag, chains]) const chainMetadata = useGetChainMetadata(selectedChain, initialCache && initialCache[selectedChain.page]) const wrapperRef = useRef(null) @@ -500,56 +591,54 @@ export const FeedList = ({ function handleNetworkSelect(chain: Chain) { closeAllDropdowns() if (!isStreams) { - const params = new URLSearchParams(window.location.search) - params.set("network", chain.page) - // Clear hash when changing networks - const newUrl = window.location.pathname + "?" + params.toString() - window.history.replaceState({ path: newUrl }, "", newUrl) setCurrentNetwork(chain.page) + // Clear all filters and pagination when switching networks + setSearchValue("") + setTestnetSearchValue("") + setSelectedFeedCategories([]) + setCurrentPage("") + setTestnetCurrentPage("") + setShowOnlyMVRFeeds(false) + setShowOnlyMVRFeedsTestnet(false) + // Update URL with just the network (and networkType if not mainnet) + const params = new URLSearchParams(window.location.search) + const networkType = params.get("networkType") + updateUrlClean({ + network: chain.page, + networkType: networkType === "testnet" ? "testnet" : undefined, + search: undefined, + testnetSearch: undefined, + page: undefined, + testnetPage: undefined, + }) } - setSearchValue("") - setSelectedFeedCategories([]) - setCurrentPage("1") - setShowOnlyMVRFeeds(false) - setShowOnlyMVRFeedsTestnet(false) } // Network type change handler for testnet/mainnet switching function handleNetworkTypeChange(networkType: "mainnet" | "testnet") { closeAllDropdowns() - // Update the selected network type setSelectedNetworkType(networkType) - // Update URL parameters to reflect network type state - if (typeof window !== "undefined") { - const params = new URLSearchParams(window.location.search) - - if (networkType === "testnet") { - // Set networkType parameter to testnet - params.set("networkType", "testnet") - // Ensure testnetPage is set (default to 1 if not present) - if (!params.get("testnetPage")) { - params.set("testnetPage", "1") - } - } else { - // Remove testnet-specific parameters when switching to mainnet - params.delete("networkType") - params.delete("testnetSearch") - // Keep testnetPage for potential future navigation - } - - const newUrl = window.location.pathname + "?" + params.toString() - window.history.replaceState({ path: newUrl }, "", newUrl) - } - // Reset filters and pagination when switching network types setSearchValue("") setTestnetSearchValue("") setSelectedFeedCategories([]) - setCurrentPage("1") - setTestnetCurrentPage("1") + setCurrentPage("") + setTestnetCurrentPage("") setShowOnlyMVRFeeds(false) setShowOnlyMVRFeedsTestnet(false) + + // Update URL with clean params + const params = new URLSearchParams(window.location.search) + const network = params.get("network") + updateUrlClean({ + network: network || undefined, + networkType: networkType === "testnet" ? "testnet" : undefined, + search: undefined, + testnetSearch: undefined, + page: undefined, + testnetPage: undefined, + }) } const handleCategorySelection = (category) => { @@ -567,18 +656,14 @@ export const FeedList = ({ } useEffect(() => { + // Clean up empty search params if (searchValue === "") { - const searchParams = new URLSearchParams(window.location.search) - searchParams.delete("search") - const hashFragment = window.location.hash - const newUrl = window.location.pathname + "?" + searchParams.toString() + hashFragment - window.history.replaceState({ path: newUrl }, "", newUrl) - const inputElement = document.getElementById("search") as HTMLInputElement - if (inputElement) { - inputElement.placeholder = "Search" - } + updateUrlClean({ search: undefined }) } - }, [chainMetadata.processedData, searchValue]) + if (testnetSearchValue === "") { + updateUrlClean({ testnetSearch: undefined }) + } + }, [searchValue, testnetSearchValue]) const useOutsideAlerter = (ref: RefObject<HTMLDivElement>) => { useEffect(() => { @@ -606,24 +691,35 @@ export const FeedList = ({ const networkTypes = { mainnet: false, testnet: false } // Filter networks by feed type - const filteredNetworks = chainMetadata.processedData.networks.filter((network) => { - if (isDeprecating) { - let foundDeprecated = false - network.metadata?.forEach((feed: any) => { - if (feed.feedCategory === "deprecating") { - foundDeprecated = true - } - }) - return foundDeprecated - } + const filteredNetworks = chainMetadata.processedData.networks + .filter((network) => { + if (isDeprecating) { + let foundDeprecated = false + network.metadata?.forEach((feed: any) => { + if (feed.feedCategory === "deprecating") { + foundDeprecated = true + } + }) + // A deprecating network is relevant only if it still has at least one non-hidden deprecating feed + if (!foundDeprecated) return false + const hasVisible = network.metadata?.some( + (feed: any) => feed.feedCategory === "deprecating" && !feed.docs?.hidden + ) + return !!hasVisible + } - if (isStreams) return network.tags?.includes("streams") - if (isSmartData) return network.tags?.includes("smartData") - if (isRates) return network.tags?.includes("rates") - if (isUSGovernmentMacroeconomicData) return network.tags?.includes("usGovernmentMacroeconomicData") + if (isStreams) return network.tags?.includes("streams") + if (isSmartData) return network.tags?.includes("smartData") + if (isRates) return network.tags?.includes("rates") + if (isUSGovernmentMacroeconomicData) return network.tags?.includes("usGovernmentMacroeconomicData") - return true - }) + return true + }) + .filter((network) => { + // Ensure the network has at least one visible feed for the current dataFeedType + const feeds = network.metadata || [] + return feeds.some((feed: any) => isFeedVisible(feed, dataFeedType, ecosystem, { tokenizedEquityProvider })) + }) // Check available network types filteredNetworks.forEach((network) => { @@ -689,7 +785,7 @@ export const FeedList = ({ dataFeedType === "streamsCrypto" ? "Mainnet Crypto Streams" : dataFeedType === "streamsNav" - ? "Mainnet NAV Streams" + ? "Mainnet SmartData Streams" : dataFeedType === "streamsExRate" ? "Mainnet Exchange Rate Streams" : dataFeedType === "streamsBacked" @@ -699,7 +795,7 @@ export const FeedList = ({ dataFeedType === "streamsCrypto" ? "Testnet Crypto Streams" : dataFeedType === "streamsNav" - ? "Testnet NAV Streams" + ? "Testnet SmartData Streams" : dataFeedType === "streamsExRate" ? "Testnet Exchange Rate Streams" : dataFeedType === "streamsBacked" @@ -732,6 +828,199 @@ export const FeedList = ({ dataFeedType === "streamsExRate" || dataFeedType === "streamsBacked" ) { + // For deprecating streams, show two separate tables: mainnet and testnet + if (isDeprecating) { + const mainnetDeprecatingStreams: any[] = [] + const testnetDeprecatingStreams: any[] = [] + + if (initialCache) { + Object.values(initialCache).forEach((chainData: any) => { + // Only check Arbitrum chains for streams + if (chainData.page === "arbitrum") { + chainData.networks?.forEach((network: any) => { + network.metadata?.forEach((item: any) => { + // Only include items that are actual streams (have verifier contract type and feedId) + // and have a shutdown date + if (item.contractType === "verifier" && item.feedId && item.docs?.shutdownDate) { + const streamWithNetwork = { + ...item, + networkName: network.name, + } + if (network.networkType === "mainnet") { + mainnetDeprecatingStreams.push(streamWithNetwork) + } else if (network.networkType === "testnet") { + testnetDeprecatingStreams.push(streamWithNetwork) + } + } + }) + }) + } + }) + } + + // Sort alphabetically by asset name or product name + const sortStreams = (streams: any[]) => { + return streams.sort((a, b) => { + const nameA = (a.assetName || a.docs?.clicProductName || "").toUpperCase() + const nameB = (b.assetName || b.docs?.clicProductName || "").toUpperCase() + return nameA.localeCompare(nameB) + }) + } + + sortStreams(mainnetDeprecatingStreams) + sortStreams(testnetDeprecatingStreams) + + // Apply search filter for mainnet + const filteredMainnetStreams = mainnetDeprecatingStreams.filter((stream) => { + if (!searchValue || typeof searchValue !== "string") return true + const searchLower = searchValue.toLowerCase() + return ( + stream.feedId?.toLowerCase().includes(searchLower) || + stream.assetName?.toLowerCase().includes(searchLower) || + stream.feedType?.toLowerCase().includes(searchLower) || + stream.networkName?.toLowerCase().includes(searchLower) || + stream.docs?.clicProductName?.toLowerCase().includes(searchLower) + ) + }) + + // Apply search filter for testnet + const filteredTestnetStreams = testnetDeprecatingStreams.filter((stream) => { + if (!testnetSearchValue || typeof testnetSearchValue !== "string") return true + const searchLower = testnetSearchValue.toLowerCase() + return ( + stream.feedId?.toLowerCase().includes(searchLower) || + stream.assetName?.toLowerCase().includes(searchLower) || + stream.feedType?.toLowerCase().includes(searchLower) || + stream.networkName?.toLowerCase().includes(searchLower) || + stream.docs?.clicProductName?.toLowerCase().includes(searchLower) + ) + }) + + // Calculate mainnet pagination + const paginatedMainnetStreams = filteredMainnetStreams.slice(firstAddr, lastAddr) + + // Calculate testnet pagination + const paginatedTestnetStreams = filteredTestnetStreams.slice(testnetFirstAddr, testnetLastAddr) + + return ( + <> + {chainMetadata.loading && !chainMetadata.processedData && !initialCache && <p>Loading...</p>} + {chainMetadata.error && <p>There was an error loading the streams...</p>} + + <SectionWrapper title="Mainnet Deprecating Streams" depth={2}> + <form class={feedList.filterDropdown_search}> + <input + id="search" + class={feedList.filterDropdown_searchInput} + placeholder="Search" + value={typeof searchValue === "string" ? searchValue : ""} + onInput={(event) => { + setSearchValue((event.target as HTMLInputElement).value) + setCurrentPage("1") + }} + /> + </form> + {filteredMainnetStreams.length > 0 ? ( + <> + <div className={feedList.tableWrapper}> + <table className={clsx(tableStyles.table)}> + <StreamsTHead /> + <tbody> + {paginatedMainnetStreams.map((stream, index) => ( + <StreamsTr key={`${stream.feedId}-${index}`} metadata={stream} isMainnet={true} /> + ))} + </tbody> + </table> + </div> + {filteredMainnetStreams.length > addrPerPage && ( + <div className={tableStyles.pagination} role="navigation" aria-label="Table pagination"> + <button + className={button.secondary} + disabled={currentPageNum === 1} + onClick={() => paginate(currentPageNum - 1)} + > + Prev + </button> + <p aria-live="polite"> + {firstAddr + 1}- + {lastAddr > filteredMainnetStreams.length ? filteredMainnetStreams.length : lastAddr} of{" "} + {filteredMainnetStreams.length} + </p> + <button + className={button.secondary} + disabled={lastAddr >= filteredMainnetStreams.length} + onClick={() => paginate(currentPageNum + 1)} + > + Next + </button> + </div> + )} + </> + ) : ( + <p>No mainnet deprecating streams found.</p> + )} + </SectionWrapper> + + <SectionWrapper title="Testnet Deprecating Streams" depth={2}> + <form class={feedList.filterDropdown_search}> + <input + id="testnetSearch" + class={feedList.filterDropdown_searchInput} + placeholder="Search" + value={typeof testnetSearchValue === "string" ? testnetSearchValue : ""} + onInput={(event) => { + setTestnetSearchValue((event.target as HTMLInputElement).value) + setTestnetCurrentPage("1") + }} + /> + </form> + {filteredTestnetStreams.length > 0 ? ( + <> + <div className={feedList.tableWrapper}> + <table className={clsx(tableStyles.table)}> + <StreamsTHead /> + <tbody> + {paginatedTestnetStreams.map((stream, index) => ( + <StreamsTr key={`${stream.feedId}-${index}`} metadata={stream} isMainnet={false} /> + ))} + </tbody> + </table> + </div> + {filteredTestnetStreams.length > testnetAddrPerPage && ( + <div className={tableStyles.pagination} role="navigation" aria-label="Table pagination"> + <button + className={button.secondary} + disabled={testnetPageNum === 1} + onClick={() => testnetPaginate(testnetPageNum - 1)} + > + Prev + </button> + <p aria-live="polite"> + {testnetFirstAddr + 1}- + {testnetLastAddr > filteredTestnetStreams.length + ? filteredTestnetStreams.length + : testnetLastAddr}{" "} + of {filteredTestnetStreams.length} + </p> + <button + className={button.secondary} + disabled={testnetLastAddr >= filteredTestnetStreams.length} + onClick={() => testnetPaginate(testnetPageNum + 1)} + > + Next + </button> + </div> + )} + </> + ) : ( + <p>No testnet deprecating streams found.</p> + )} + </SectionWrapper> + </> + ) + } + + // Regular streams view (non-deprecating) const mainnetFeeds: ChainNetwork[] = [] const testnetFeeds: ChainNetwork[] = [] @@ -747,20 +1036,24 @@ export const FeedList = ({ return ( <> - {allowNetworkTableExpansion ? ( - <div style={{ marginBottom: "var(--space-2x)" }}> - <StreamsNetworkAddressesTable - allowExpansion={allowNetworkTableExpansion} - defaultExpanded={defaultNetworkTableExpanded} - /> - </div> - ) : ( - <SectionWrapper title="Streams Verifier Network Addresses" depth={2}> - <StreamsNetworkAddressesTable - allowExpansion={allowNetworkTableExpansion} - defaultExpanded={defaultNetworkTableExpanded} - /> - </SectionWrapper> + {!isDeprecating && ( + <> + {allowNetworkTableExpansion ? ( + <div style={{ marginBottom: "var(--space-2x)" }}> + <StreamsNetworkAddressesTable + allowExpansion={allowNetworkTableExpansion} + defaultExpanded={defaultNetworkTableExpanded} + /> + </div> + ) : ( + <SectionWrapper title="Streams Verifier Network Addresses" depth={2}> + <StreamsNetworkAddressesTable + allowExpansion={allowNetworkTableExpansion} + defaultExpanded={defaultNetworkTableExpanded} + /> + </SectionWrapper> + )} + </> )} <SectionWrapper @@ -801,33 +1094,74 @@ export const FeedList = ({ )} {dataFeedType === "streamsRwa" && ( <> - <FilterDropdown - isOpen={openDropdownId === "main-schema"} - onToggle={(isOpen) => handleDropdownToggle("main-schema", isOpen)} - onClose={closeAllDropdowns} - label="Filter schema" - options={schemaFilterOptions} - value={rwaSchemaFilter} - groupId="schema-main" - onSelect={(next) => { - setRwaSchemaFilter(next) - setCurrentPage("1") - }} - /> - <FilterDropdown - isOpen={openDropdownId === "main-feed-type"} - onToggle={(isOpen) => handleDropdownToggle("main-feed-type", isOpen)} - onClose={closeAllDropdowns} - label="Filter category" - options={feedTypeFilterOptions} - value={streamCategoryFilter} - groupId="feed-type-main" - onSelect={(next) => { - setStreamCategoryFilter(next) - setCurrentPage("1") - }} - /> - {(searchValue || rwaSchemaFilter !== "all" || streamCategoryFilter !== "all") && ( + {!show24x5Feeds && ( + <> + <FilterDropdown + isOpen={openDropdownId === "main-schema"} + onToggle={(isOpen) => handleDropdownToggle("main-schema", isOpen)} + onClose={closeAllDropdowns} + label="Filter schema" + options={schemaFilterOptions} + value={rwaSchemaFilter} + groupId="schema-main" + onSelect={(next) => { + setRwaSchemaFilter(next) + setCurrentPage("1") + }} + /> + <FilterDropdown + isOpen={openDropdownId === "main-feed-type"} + onToggle={(isOpen) => handleDropdownToggle("main-feed-type", isOpen)} + onClose={closeAllDropdowns} + label="Filter category" + options={feedTypeFilterOptions} + value={streamCategoryFilter} + groupId="feed-type-main" + onSelect={(next) => { + setStreamCategoryFilter(next) + setCurrentPage("1") + }} + /> + </> + )} + {!force24x5Only && ( + <div className={feedList.checkboxContainer}> + <label className={feedList.detailsLabel}> + <input + type="checkbox" + style="width:15px;height:15px;display:inline;margin-right:8px;" + checked={show24x5Feeds} + onChange={() => { + closeAllDropdowns() + const newValue = !show24x5Feeds + setShow24x5Feeds(newValue) + if (newValue) { + // Reset trading hours filter when enabling 24/5 + setTradingHoursFilter("all") + } + setCurrentPage("1") + }} + /> + Show only 24/5 Equity Streams + </label> + </div> + )} + {show24x5Feeds && ( + <FilterDropdown + isOpen={openDropdownId === "main-trading-hours"} + onToggle={(isOpen) => handleDropdownToggle("main-trading-hours", isOpen)} + onClose={closeAllDropdowns} + label="Time segment" + options={tradingHoursFilterOptions} + value={tradingHoursFilter} + groupId="trading-hours-main" + onSelect={(next) => { + setTradingHoursFilter(next) + setCurrentPage("1") + }} + /> + )} + {(searchValue || rwaSchemaFilter !== "all" || streamCategoryFilter !== "all" || show24x5Feeds) && ( <button type="button" className={clsx(button.secondary, feedList.clearFilterBtn)} @@ -836,6 +1170,8 @@ export const FeedList = ({ setSearchValue("") setRwaSchemaFilter("all") setStreamCategoryFilter("all") + setShow24x5Feeds(false) + setTradingHoursFilter("all") setCurrentPage("1") const inputElement = document.getElementById("search") as HTMLInputElement if (inputElement) { @@ -869,14 +1205,17 @@ export const FeedList = ({ showOnlyDEXFeeds={showOnlyDEXFeeds} rwaSchemaFilter={rwaSchemaFilter} streamCategoryFilter={streamCategoryFilter} + show24x5Feeds={show24x5Feeds} + tradingHoursFilter={tradingHoursFilter} dataFeedType={dataFeedType} ecosystem={ecosystem} lastAddr={lastAddr} firstAddr={firstAddr} addrPerPage={addrPerPage} - currentPage={Number(currentPage)} + currentPage={currentPageNum} paginate={paginate} searchValue={typeof searchValue === "string" ? searchValue : ""} + tokenizedEquityProvider={tokenizedEquityProvider} /> )) ) : ( @@ -921,33 +1260,77 @@ export const FeedList = ({ )} {dataFeedType === "streamsRwa" && ( <> - <FilterDropdown - isOpen={openDropdownId === "test-schema"} - onToggle={(isOpen) => handleDropdownToggle("test-schema", isOpen)} - onClose={closeAllDropdowns} - label="Filter schema" - options={schemaFilterOptions} - value={testnetRwaSchemaFilter} - groupId="schema-testnet" - onSelect={(next) => { - setTestnetRwaSchemaFilter(next) - setTestnetCurrentPage("1") - }} - /> - <FilterDropdown - isOpen={openDropdownId === "test-feed-type"} - onToggle={(isOpen) => handleDropdownToggle("test-feed-type", isOpen)} - onClose={closeAllDropdowns} - label="Filter category" - options={feedTypeFilterOptions} - value={testnetStreamCategoryFilter} - groupId="feed-type-testnet" - onSelect={(next) => { - setTestnetStreamCategoryFilter(next) - setTestnetCurrentPage("1") - }} - /> - {(testnetSearchValue || testnetRwaSchemaFilter !== "all" || testnetStreamCategoryFilter !== "all") && ( + {!show24x5FeedsTestnet && ( + <> + <FilterDropdown + isOpen={openDropdownId === "test-schema"} + onToggle={(isOpen) => handleDropdownToggle("test-schema", isOpen)} + onClose={closeAllDropdowns} + label="Filter schema" + options={schemaFilterOptions} + value={testnetRwaSchemaFilter} + groupId="schema-testnet" + onSelect={(next) => { + setTestnetRwaSchemaFilter(next) + setTestnetCurrentPage("1") + }} + /> + <FilterDropdown + isOpen={openDropdownId === "test-feed-type"} + onToggle={(isOpen) => handleDropdownToggle("test-feed-type", isOpen)} + onClose={closeAllDropdowns} + label="Filter category" + options={feedTypeFilterOptions} + value={testnetStreamCategoryFilter} + groupId="feed-type-testnet" + onSelect={(next) => { + setTestnetStreamCategoryFilter(next) + setTestnetCurrentPage("1") + }} + /> + </> + )} + {!force24x5Only && ( + <div className={feedList.checkboxContainer}> + <label className={feedList.detailsLabel}> + <input + type="checkbox" + style="width:15px;height:15px;display:inline;margin-right:8px;" + checked={show24x5FeedsTestnet} + onChange={() => { + closeAllDropdowns() + const newValue = !show24x5FeedsTestnet + setShow24x5FeedsTestnet(newValue) + if (newValue) { + // Reset trading hours filter when enabling 24/5 + setTestnetTradingHoursFilter("all") + } + setTestnetCurrentPage("1") + }} + /> + Show only 24/5 Equity Streams + </label> + </div> + )} + {show24x5FeedsTestnet && ( + <FilterDropdown + isOpen={openDropdownId === "test-trading-hours"} + onToggle={(isOpen) => handleDropdownToggle("test-trading-hours", isOpen)} + onClose={closeAllDropdowns} + label="Time segment" + options={tradingHoursFilterOptions} + value={testnetTradingHoursFilter} + groupId="trading-hours-testnet" + onSelect={(next) => { + setTestnetTradingHoursFilter(next) + setTestnetCurrentPage("1") + }} + /> + )} + {(testnetSearchValue || + testnetRwaSchemaFilter !== "all" || + testnetStreamCategoryFilter !== "all" || + show24x5FeedsTestnet) && ( <button type="button" className={clsx(button.secondary, feedList.clearFilterBtn)} @@ -956,6 +1339,8 @@ export const FeedList = ({ setTestnetSearchValue("") setTestnetRwaSchemaFilter("all") setTestnetStreamCategoryFilter("all") + setShow24x5FeedsTestnet(false) + setTestnetTradingHoursFilter("all") setTestnetCurrentPage("1") const inputElement = document.getElementById("testnetSearch") as HTMLInputElement if (inputElement) { @@ -990,12 +1375,15 @@ export const FeedList = ({ showOnlyDEXFeeds={showOnlyDEXFeedsTestnet} rwaSchemaFilter={testnetRwaSchemaFilter} streamCategoryFilter={testnetStreamCategoryFilter} + show24x5Feeds={show24x5FeedsTestnet} + tradingHoursFilter={testnetTradingHoursFilter} firstAddr={testnetFirstAddr} lastAddr={testnetLastAddr} addrPerPage={testnetAddrPerPage} - currentPage={Number(testnetCurrentPage)} + currentPage={testnetPageNum} paginate={testnetPaginate} searchValue={typeof testnetSearchValue === "string" ? testnetSearchValue : ""} + tokenizedEquityProvider={tokenizedEquityProvider} /> )) ) : ( @@ -1045,7 +1433,8 @@ export const FeedList = ({ .filter((network: any) => { let foundDeprecated = false network.metadata?.forEach((feed: any) => { - if (feed.feedCategory === "deprecating") { + // Only include actual feeds (not streams) with deprecating status + if (feed.feedCategory === "deprecating" && !(feed.contractType === "verifier" && feed.feedId)) { foundDeprecated = true } }) @@ -1071,7 +1460,10 @@ export const FeedList = ({ } network={{ ...network, - metadata: network.metadata.filter((feed: any) => feed.feedCategory === "deprecating"), + metadata: network.metadata.filter( + (feed: any) => + feed.feedCategory === "deprecating" && !(feed.contractType === "verifier" && feed.feedId) + ), }} showExtraDetails={showExtraDetails} showOnlySVR={showOnlySVR} @@ -1082,9 +1474,10 @@ export const FeedList = ({ lastAddr={lastAddr} firstAddr={firstAddr} addrPerPage={addrPerPage} - currentPage={Number(currentPage)} + currentPage={currentPageNum} paginate={paginate} searchValue={typeof searchValue === "string" ? searchValue : ""} + tokenizedEquityProvider={tokenizedEquityProvider} /> </SectionWrapper> )) @@ -1096,7 +1489,8 @@ export const FeedList = ({ if (isDeprecating) { let foundDeprecated = false network.metadata?.forEach((feed: any) => { - if (feed.feedCategory === "deprecating") { + // Only include actual feeds (not streams) with deprecating status + if (feed.feedCategory === "deprecating" && !(feed.contractType === "verifier" && feed.feedId)) { foundDeprecated = true } }) @@ -1272,7 +1666,7 @@ export const FeedList = ({ type="checkbox" style="width:15px;height:15px;display:inline;margin-right:8px;" checked={showExtraDetails} - onChange={() => setShowExtraDetails((old) => !old)} + onChange={() => setShowExtraDetails(!showExtraDetails)} /> Show more details </label> @@ -1299,10 +1693,7 @@ export const FeedList = ({ type="checkbox" style="width:15px;height:15px;display:inline;margin-right:8px;" checked={showOnlySVR} - onChange={() => { - setShowOnlySVR((old) => !old) - setCurrentPage("1") - }} + onChange={() => setShowOnlySVR(!showOnlySVR)} /> Show Smart Value Recapture (SVR) feeds </label> @@ -1327,9 +1718,10 @@ export const FeedList = ({ lastAddr={lastAddr} firstAddr={firstAddr} addrPerPage={addrPerPage} - currentPage={Number(currentPage)} + currentPage={currentPageNum} paginate={paginate} searchValue={typeof searchValue === "string" ? searchValue : ""} + tokenizedEquityProvider={tokenizedEquityProvider} /> </> ) : ( @@ -1434,7 +1826,7 @@ export const FeedList = ({ type="checkbox" style="width:15px;height:15px;display:inline;margin-right:8px;" checked={showExtraDetails} - onChange={() => setShowExtraDetails((old) => !old)} + onChange={() => setShowExtraDetails(!showExtraDetails)} /> Show more details </label> @@ -1504,9 +1896,10 @@ export const FeedList = ({ firstAddr={testnetFirstAddr} lastAddr={testnetLastAddr} addrPerPage={testnetAddrPerPage} - currentPage={Number(testnetCurrentPage)} + currentPage={testnetPageNum} paginate={testnetPaginate} searchValue={typeof testnetSearchValue === "string" ? testnetSearchValue : ""} + tokenizedEquityProvider={tokenizedEquityProvider} /> </> )} diff --git a/src/features/feeds/components/FeedPage.astro b/src/features/feeds/components/FeedPage.astro index f48355afa8b..821d173d482 100644 --- a/src/features/feeds/components/FeedPage.astro +++ b/src/features/feeds/components/FeedPage.astro @@ -25,7 +25,9 @@ import { FeedDataItem, monitoredFeeds } from "~/features/data" const { initialNetwork, ecosystem, dataFeedType, allowNetworkTableExpansion, defaultNetworkTableExpanded } = Astro.props -const initialCache = await getServerSideChainMetadata([...CHAINS, ...ALL_CHAINS]) +// Skip cache for deprecating page to always fetch fresh data +const isDeprecating = ecosystem === "deprecating" +const initialCache = await getServerSideChainMetadata([...CHAINS, ...ALL_CHAINS], isDeprecating) const feedItems: FeedDataItem[] = monitoredFeeds.mainnet --- diff --git a/src/features/feeds/components/Tables.module.css b/src/features/feeds/components/Tables.module.css index ad1d7f3e3cf..2a9b96e74ae 100644 --- a/src/features/feeds/components/Tables.module.css +++ b/src/features/feeds/components/Tables.module.css @@ -49,6 +49,13 @@ margin-right: var(--space-1x); } +.note { + font-style: italic; + font-size: 0.9em; + margin-top: 0.25rem; + color: var(--color-text-secondary); +} + /* Expandable wrapper and header */ .expandableWrapper { background-color: var(--gray-50); @@ -284,6 +291,53 @@ text-align: left; } +.infoCallout { + padding: var(--space-4x); + gap: var(--space-4x); + background-color: var(--color-background-info); + border: 1px solid #eee; + border-radius: var(--border-radius-10); + color: var(--color-text-info); + outline: 1px solid transparent; + display: flex; + margin-top: 12px; + margin-bottom: 12px; +} + +.infoCalloutIcon { + flex-shrink: 0; + width: 1.5em; +} + +.infoCalloutIcon img { + width: 1.5em; + height: 1.5em; +} + +.infoCalloutContent { + flex: 1; +} + +.infoCalloutTitle { + font-weight: bold; + text-transform: uppercase; + color: var(--theme-text); + margin-bottom: var(--space-1x); + font-size: 14px; +} + +.infoCalloutContent p { + color: var(--theme-text-light); + line-height: 1.5; + font-size: 14px; + margin: 0; +} + +.infoCalloutContent a { + color: var(--color-text-link); + text-decoration: underline; +} + .feedVariantBadge { display: inline-block; font-size: 0.75rem; diff --git a/src/features/feeds/components/Tables.tsx b/src/features/feeds/components/Tables.tsx index 31baeb4545e..c9118a600e4 100644 --- a/src/features/feeds/components/Tables.tsx +++ b/src/features/feeds/components/Tables.tsx @@ -13,9 +13,34 @@ import { FEED_CATEGORY_CONFIG } from "../../../db/feedCategories.js" import { useBatchedFeedCategories, getFeedCategoryFromBatch, getNetworkIdentifier } from "./useBatchedFeedCategories.ts" import { isSharedSVR, isAaveSVR } from "~/features/feeds/utils/svrDetection.ts" import { ExpandableTableWrapper } from "./ExpandableTableWrapper.tsx" +import { isFeedVisible } from "~/features/feeds/utils/feedVisibility.ts" const feedItems = monitoredFeeds.mainnet +// Helper function to extract schema version from clicProductName +// e.g., "HOOD/USD-Streams-RegularHoursEquityPrice-DS-Premium-Global-011" -> "v11" +// e.g., "USD/SEK-Datalink-DeutscheBoerse-DS-Premium-Global-008" -> "v8" +// e.g., "AAPL/USD-Streams-EquityPrice-DS-Premium-Global-004" -> "v8" +const getSchemaVersion = (metadata: any): string | undefined => { + // First try to get from docs.schema + if (metadata.docs?.schema) { + return metadata.docs.schema + } + + // Fallback: parse from clicProductName + const clicProductName = metadata.docs?.clicProductName + if (clicProductName) { + const match = clicProductName.match(/-0(\d{2})$/) + if (match) { + const version = match[1] + if (version === "04" || version === "08") return "v8" + if (version === "11") return "v11" + } + } + + return undefined +} + // Helper function to parse markdown links and render them const parseMarkdownLink = (text: string) => { // Match markdown link format: [text](url) @@ -49,7 +74,9 @@ const parseMarkdownLink = (text: string) => { // Render a category icon/link from the config const getFeedCategoryElement = (riskTier: string | undefined) => { if (!riskTier) return "" - const category = FEED_CATEGORY_CONFIG[riskTier.toLowerCase()] + // Normalize: "very high" → "veryhigh" to match config keys + const normalizedKey = riskTier.toLowerCase().replace(/\s+/g, "") + const category = FEED_CATEGORY_CONFIG[normalizedKey] if (!category) return "" return ( <span className={clsx(feedList.hoverText, tableStyles.statusIcon, "feed-category")} title={category.title}> @@ -191,23 +218,19 @@ const DefaultTHead = ({ ) } +// Contact email for tokenized equity feeds (can be updated as needed) +const TOKENIZED_EQUITY_CONTACT_EMAIL = "chainlink_data_feeds@smartcontract.com" + const DefaultTr = ({ network, metadata, showExtraDetails, batchedCategoryData, dataFeedType }) => { - // Risk categorization logic - const contractAddress = metadata.contractAddress || metadata.proxyAddress - const networkIdentifier = getNetworkIdentifier(network) - let finalTier = - contractAddress && batchedCategoryData?.size - ? (getFeedCategoryFromBatch(batchedCategoryData, contractAddress, networkIdentifier, metadata.feedCategory) - ?.final ?? metadata.feedCategory) - : metadata.feedCategory - - // Override with deprecating category if feed has shutdown date - if (metadata.docs?.shutdownDate) { - finalTier = "deprecating" - } + // Use the pre-computed finalCategory from enriched metadata + // (already includes deprecating status and Supabase risk tier) + const finalTier = metadata.finalCategory || metadata.feedCategory - // US Government Macroeconomic Data logic + // Feed type checks const isUSGovernmentMacroeconomicData = dataFeedType === "usGovernmentMacroeconomicData" + // Detect tokenized equity feeds by metadata so the badge shows on any page (e.g., standard price feeds) + const isTokenizedEquityFeed = metadata.docs?.assetClass === "Equities" && metadata.contractType !== "verifier" + const label = isUSGovernmentMacroeconomicData ? "Category" : "Asset type" const value = isUSGovernmentMacroeconomicData ? metadata.docs.assetClass === "Macroeconomics" @@ -242,6 +265,17 @@ const DefaultTr = ({ network, metadata, showExtraDetails, batchedCategoryData, d </a> </div> )} + {isTokenizedEquityFeed && ( + <div style={{ marginTop: "5px" }}> + <a + href="/data-feeds/tokenized-equity-feeds" + className={tableStyles.feedVariantBadge} + title="Tokenized Equity Feed" + > + Tokenized Equity + </a> + </div> + )} </div> {metadata.docs.shutdownDate && ( <div className={clsx(feedList.shutDate)}> @@ -271,30 +305,40 @@ const DefaultTr = ({ network, metadata, showExtraDetails, batchedCategoryData, d </dt> )} <dd> - <div className={tableStyles.assetAddress}> - <button - className={clsx(tableStyles.copyBtn, "copy-iconbutton")} - data-clipboard-text={metadata.proxyAddress ?? metadata.transmissionsAccount} - onClick={(e) => - handleClick(e, { - product: "FEEDS", - action: "feedId_copied", - extraInfo1: network.name, - extraInfo2: metadata.name, - extraInfo3: metadata.proxyAddress, - }) - } - > - <img src="/assets/icons/copyIcon.svg" alt="copy to clipboard" /> - </button> - <a - className={tableStyles.addressLink} - href={network.explorerUrl.replace("%s", metadata.proxyAddress ?? metadata.transmissionsAccount)} - target="_blank" - > - {metadata.proxyAddress ?? metadata.transmissionsAccount} - </a> - </div> + {isTokenizedEquityFeed ? ( + // Tokenized equity feeds show a contact email instead of proxy address + <span> + Contact us:{" "} + <a href={`mailto:${TOKENIZED_EQUITY_CONTACT_EMAIL}`} className={tableStyles.addressLink}> + {TOKENIZED_EQUITY_CONTACT_EMAIL} + </a> + </span> + ) : ( + <div className={tableStyles.assetAddress}> + <button + className={clsx(tableStyles.copyBtn, "copy-iconbutton")} + data-clipboard-text={metadata.proxyAddress ?? metadata.transmissionsAccount} + onClick={(e) => + handleClick(e, { + product: "FEEDS", + action: "feedId_copied", + extraInfo1: network.name, + extraInfo2: metadata.name, + extraInfo3: metadata.proxyAddress, + }) + } + > + <img src="/assets/icons/copyIcon.svg" alt="copy to clipboard" /> + </button> + <a + className={tableStyles.addressLink} + href={network.explorerUrl.replace("%s", metadata.proxyAddress ?? metadata.transmissionsAccount)} + target="_blank" + > + {metadata.proxyAddress ?? metadata.transmissionsAccount} + </a> + </div> + )} </dd> </div> {metadata.assetName && ( @@ -336,31 +380,43 @@ const DefaultTr = ({ network, metadata, showExtraDetails, batchedCategoryData, d <span className="label">{isAaveSVR(metadata) ? "AAVE SVR Proxy:" : "SVR Proxy:"}</span> </dt> <dd> - <button - className={clsx(tableStyles.copyBtn, "copy-iconbutton")} - data-clipboard-text={metadata.secondaryProxyAddress} - onClick={(e) => - handleClick(e, { - product: "FEEDS", - action: "SVR_proxy_copied", - extraInfo1: network.name, - extraInfo2: metadata.name, - extraInfo3: metadata.secondaryProxyAddress, - }) - } - > - <img src="/assets/icons/copyIcon.svg" alt="copy to clipboard" /> - </button> - <a - className={tableStyles.addressLink} - href={network.explorerUrl.replace("%s", metadata.secondaryProxyAddress)} - target="_blank" - > - {metadata.secondaryProxyAddress} - </a> + {isTokenizedEquityFeed ? ( + // Tokenized equity feeds show a contact email instead of SVR proxy address + <span> + Contact us:{" "} + <a href={`mailto:${TOKENIZED_EQUITY_CONTACT_EMAIL}`} className={tableStyles.addressLink}> + {TOKENIZED_EQUITY_CONTACT_EMAIL} + </a> + </span> + ) : ( + <> + <button + className={clsx(tableStyles.copyBtn, "copy-iconbutton")} + data-clipboard-text={metadata.secondaryProxyAddress} + onClick={(e) => + handleClick(e, { + product: "FEEDS", + action: "SVR_proxy_copied", + extraInfo1: network.name, + extraInfo2: metadata.name, + extraInfo3: metadata.secondaryProxyAddress, + }) + } + > + <img src="/assets/icons/copyIcon.svg" alt="copy to clipboard" /> + </button> + <a + className={tableStyles.addressLink} + href={network.explorerUrl.replace("%s", metadata.secondaryProxyAddress)} + target="_blank" + > + {metadata.secondaryProxyAddress} + </a> + </> + )} </dd> </div> - {isAaveSVR(metadata) && ( + {isAaveSVR(metadata) && !isTokenizedEquityFeed && ( <div className={clsx(tableStyles.aaveCallout)}> <strong>⚠️ Aave Dedicated Feed:</strong> This SVR proxy feed is dedicated exclusively for use by the Aave protocol. Learn more about{" "} @@ -370,7 +426,7 @@ const DefaultTr = ({ network, metadata, showExtraDetails, batchedCategoryData, d . </div> )} - {isSharedSVR(metadata) && ( + {isSharedSVR(metadata) && !isTokenizedEquityFeed && ( <div className={clsx(tableStyles.sharedCallout)}> <strong>🔗 SVR Feed:</strong> This SVR proxy feed is usable by any protocol. Learn more about{" "} <a href="/data-feeds/svr-feeds" target="_blank"> @@ -408,19 +464,9 @@ const SmartDataTr = ({ network, metadata, showExtraDetails, batchedCategoryData // Only show MVR badge if explicitly flagged as MVR const finalIsMVRFeed = isMVRFlagSet && hasDecoding - // Resolve final category from batch (fallback to metadata) - const contractAddress = metadata.contractAddress || metadata.proxyAddress - const networkIdentifier = getNetworkIdentifier(network) - let finalTier = - contractAddress && batchedCategoryData?.size - ? (getFeedCategoryFromBatch(batchedCategoryData, contractAddress, networkIdentifier, metadata.feedCategory) - ?.final ?? metadata.feedCategory) - : metadata.feedCategory - - // Override with deprecating category if feed has shutdown date - if (metadata.docs?.shutdownDate) { - finalTier = "deprecating" - } + // Use the pre-computed finalCategory from enriched metadata + // (already includes deprecating status and Supabase risk tier) + const finalTier = metadata.finalCategory || metadata.feedCategory return ( <tr> @@ -719,7 +765,15 @@ export const StreamsNetworkAddressesTable = ({ <span>{network.network}</span> </div> </td> - <td>{network.mainnet?.label}</td> + <td> + {network.mainnet?.label} + {network.mainnet?.note && ( + <div + className={tableStyles.note} + dangerouslySetInnerHTML={{ __html: network.mainnet.note }} + /> + )} + </td> <td className={tableStyles.addressColumn}> {network.isSolana ? ( <> @@ -767,7 +821,15 @@ export const StreamsNetworkAddressesTable = ({ </div> )} </td> - <td>{network.testnet?.label}</td> + <td> + {network.testnet?.label} + {network.testnet?.note && ( + <div + className={tableStyles.note} + dangerouslySetInnerHTML={{ __html: network.testnet.note }} + /> + )} + </td> <td className={tableStyles.addressColumn}> {network.isSolana ? ( <> @@ -841,7 +903,7 @@ export const StreamsNetworkAddressesTable = ({ ) } -const StreamsTHead = () => ( +export const StreamsTHead = () => ( <thead> <tr> <th className={tableStyles.heading}>Stream</th> @@ -861,204 +923,297 @@ const streamsCategoryMap = { }, } -const StreamsTr = ({ metadata, isMainnet }) => ( - <tr> - <td className={tableStyles.pairCol}> - <div className={tableStyles.assetPair}> - {metadata.pair[0]}/{metadata.pair[1]} - {metadata.feedType === "Crypto-DEX" && ( - <a - href="/data-streams/concepts/dex-state-price-streams" - target="_blank" - className={tableStyles.feedVariantBadge} - > - DEX State Price - </a> - )} - </div> - {metadata.docs.shutdownDate && ( - <div className={clsx(feedList.shutDate)}> - <hr /> - Deprecating: - <br /> - {metadata.docs.shutdownDate} - </div> - )} - </td> - <td style="width:80%;"> - <div className={tableStyles.assetAddress}> - <span className={tableStyles.streamAddress}>{metadata.feedId}</span> - <button - className={clsx(tableStyles.copyBtn, "copy-iconbutton")} - style={{ height: "16px", width: "16px" }} - data-clipboard-text={metadata.feedId} - onClick={(e) => - handleClick(e, { - product: "STREAMS", - action: "feedId_copied", - extraInfo1: isMainnet ? "Mainnet" : "Testnet", - extraInfo2: metadata.pair[0], - extraInfo3: metadata.feedId, - }) - } - > - <img src="/assets/icons/copyIcon.svg" alt="copy to clipboard" /> - </button> - </div> - <div> - <dl className={tableStyles.listContainer}> - {isMainnet && metadata.docs.clicProductName && metadata.feedType !== "Tokenized Equities" && ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Full name:</span> - </dt> - <dd>{metadata.docs.clicProductName}</dd> - </div> - )} - {metadata.assetName && ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Asset name:</span> - </dt> - <dd>{metadata.assetName}</dd> - </div> - )} - {metadata.docs.assetClass ? ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Asset class:</span> - </dt> - <dd> - {metadata.docs.assetClass} - {metadata.docs.assetSubClass && - metadata.docs.assetSubClass !== "Crypto" && - metadata.docs.assetSubClass !== "Equities" - ? " - " + metadata.docs.assetSubClass - : ""} - </dd> - </div> - ) : null} - {metadata.docs.marketHours ? ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Market hours:</span> - </dt> - <dd> - <a href="/data-streams/market-hours" target="_blank"> - {metadata.docs.marketHours} - </a> - </dd> - </div> - ) : null} - {streamsCategoryMap[metadata.feedCategory] ? ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Category:</span> - </dt> - <dd> - <a href={streamsCategoryMap[metadata.feedCategory].link}> - {streamsCategoryMap[metadata.feedCategory].text} - </a> - </dd> - </div> - ) : null} - {metadata.decimals ? ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Decimals:</span> - </dt> - <dd>{metadata.decimals}</dd> - </div> - ) : null} +export const StreamsTr = ({ metadata, isMainnet }) => { + // Determine if stream is deprecating + const isDeprecating = !!metadata.docs?.shutdownDate + + // Temporary calculated stream detection until proper metadata tagging is implemented + // TODO: Replace with metadata.docs.isCalculated or similar once available + const isCalculatedStream = + metadata.docs?.productTypeCode === "ExRate" && + metadata.docs?.attributeType === "ExchangeRate" && + metadata.docs?.assetClass === "Tokenized Debt" + + return ( + <tr> + <td className={tableStyles.pairCol}> + <div className={tableStyles.assetPair}> + {metadata.pair[0]}/{metadata.pair[1]} {metadata.feedType === "Crypto-DEX" && ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Report Schema:</span> - </dt> - <dd> - <a href="/data-streams/reference/report-schema-v3-dex" rel="noreferrer" target="_blank"> - Report Schema v3 (Crypto DEX) - </a> - </dd> - </div> - )} - {metadata.feedType === "Crypto" && metadata.docs?.productTypeCode !== "ExRate" && ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Report Schema:</span> - </dt> - <dd> - <a href="/data-streams/reference/report-schema-v3" rel="noreferrer" target="_blank"> - Report Schema v3 (Crypto) - </a> - </dd> - </div> - )} - {(metadata.feedType === "Equities" || metadata.feedType === "Forex") && metadata.docs?.schema !== "v11" && ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Report Schema:</span> - </dt> - <dd> - <a href="/data-streams/reference/report-schema-v8" rel="noreferrer" target="_blank"> - Report Schema v8 (RWA) - </a> - </dd> - </div> - )} - {metadata.docs?.productTypeCode === "ExRate" && ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Report Schema:</span> - </dt> - <dd> - <a href="/data-streams/reference/report-schema-v7" rel="noreferrer" target="_blank"> - Report Schema v7 (Redemption Rates) - </a> - </dd> - </div> - )} - {metadata.feedType === "Net Asset Value" && ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Report Schema:</span> - </dt> - <dd> - <a href="/data-streams/reference/report-schema-v9" rel="noreferrer" target="_blank"> - Report Schema v9 (NAV) - </a> - </dd> - </div> - )} - {metadata.feedType === "Tokenized Equities" && ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Report Schema:</span> - </dt> - <dd> - <a href="/data-streams/reference/report-schema-v10" rel="noreferrer" target="_blank"> - Report Schema v10 (Tokenized Assets) - </a> - </dd> - </div> + <a + href="/data-streams/concepts/dex-state-price-streams" + target="_blank" + className={tableStyles.feedVariantBadge} + > + DEX State Price + </a> )} - {metadata.docs?.schema === "v11" && ( - <div className={tableStyles.definitionGroup}> - <dt> - <span className="label">Report Schema:</span> - </dt> - <dd> - <a href="/data-streams/reference/report-schema-v11" rel="noreferrer" target="_blank"> - RWA Advanced (v11) - </a> - </dd> - </div> + {isCalculatedStream && ( + <a + href="/data-streams/concepts/calculated-streams" + target="_blank" + className={tableStyles.feedVariantBadge} + title="Calculated Stream" + > + Calculated + </a> )} - </dl> - </div> - </td> - </tr> -) + </div> + {metadata.docs.shutdownDate && ( + <div className={clsx(feedList.shutDate)}> + <hr /> + <a + href="/data-streams/deprecating-streams" + style={{ color: "inherit", textDecoration: "underline dotted" }} + > + Deprecating: + </a> + <br /> + {metadata.docs.shutdownDate} + </div> + )} + </td> + <td style="width:80%;"> + <div className={tableStyles.assetAddress}> + <span className={tableStyles.streamAddress}>{metadata.feedId}</span> + <button + className={clsx(tableStyles.copyBtn, "copy-iconbutton")} + style={{ height: "16px", width: "16px" }} + data-clipboard-text={metadata.feedId} + onClick={(e) => + handleClick(e, { + product: "STREAMS", + action: "feedId_copied", + extraInfo1: isMainnet ? "Mainnet" : "Testnet", + extraInfo2: metadata.pair[0], + extraInfo3: metadata.feedId, + }) + } + > + <img src="/assets/icons/copyIcon.svg" alt="copy to clipboard" /> + </button> + </div> + <div> + <dl className={tableStyles.listContainer}> + {isMainnet && metadata.docs.clicProductName && metadata.feedType !== "Tokenized Equities" && ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Full name:</span> + </dt> + <dd>{metadata.docs.clicProductName}</dd> + </div> + )} + {metadata.assetName && ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Asset name:</span> + </dt> + <dd>{metadata.assetName}</dd> + </div> + )} + {metadata.docs.assetClass ? ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Asset class:</span> + </dt> + <dd> + {metadata.docs.assetClass} + {metadata.docs.assetSubClass && + metadata.docs.assetSubClass !== "Crypto" && + metadata.docs.assetSubClass !== "Equities" + ? " - " + metadata.docs.assetSubClass + : ""} + </dd> + </div> + ) : null} + {(() => { + const assetSubClass = (metadata.docs as any)?.assetSubClass + const clicProductName = (metadata.docs as any)?.clicProductName || "" + + // Determine the trading hours type from either assetSubClass or clicProductName + let hoursType = "" + let timeRange = "" + + if ( + assetSubClass === "Regular Hours" || + (clicProductName.includes("RegularHours") && + !clicProductName.includes("ExtendedHours") && + !clicProductName.includes("OvernightHours")) + ) { + hoursType = "Regular Hours" + timeRange = "9:30am–4:00pm Mon–Fri" + } else if (assetSubClass === "Extended Hours" || clicProductName.includes("ExtendedHours")) { + hoursType = "Extended Hours" + timeRange = "4:00am–9:30am & 4:00pm–8:00pm Mon–Fri" + } else if (assetSubClass === "Overnight Hours" || clicProductName.includes("OvernightHours")) { + hoursType = "Overnight Hours" + timeRange = "8:00pm–4:00am Sun evening–Fri morning" + } + + if (hoursType) { + return ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Trading hours:</span> + </dt> + <dd> + <a href="/data-streams/market-hours" target="_blank"> + <strong>{hoursType}</strong> + </a>{" "} + — {timeRange} ET + </dd> + </div> + ) + } + return null + })()} + {metadata.docs.marketHours ? ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Market hours:</span> + </dt> + <dd> + <a href="/data-streams/market-hours" target="_blank"> + {metadata.docs.marketHours} + </a> + </dd> + </div> + ) : null} + {streamsCategoryMap[metadata.feedCategory] ? ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Category:</span> + </dt> + <dd> + <a href={streamsCategoryMap[metadata.feedCategory].link}> + {streamsCategoryMap[metadata.feedCategory].text} + </a> + </dd> + </div> + ) : null} + {metadata.decimals ? ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Decimals:</span> + </dt> + <dd>{metadata.decimals}</dd> + </div> + ) : null} + {metadata.feedType === "Crypto-DEX" && ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Report Schema:</span> + </dt> + <dd> + <a href="/data-streams/reference/report-schema-v3-dex" rel="noreferrer" target="_blank"> + Report Schema v3 (Crypto DEX) + </a> + </dd> + </div> + )} + {metadata.feedType === "Crypto" && metadata.docs?.productTypeCode !== "ExRate" && ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Report Schema:</span> + </dt> + <dd> + <a href="/data-streams/reference/report-schema-v3" rel="noreferrer" target="_blank"> + Report Schema v3 (Crypto) + </a> + </dd> + </div> + )} + {(() => { + const schemaVersion = getSchemaVersion(metadata) + const feedType = metadata.feedType || metadata.docs?.feedType + + // RWA streams (Equities, Forex, Datalink) - v8 or v11 + if (feedType === "Equities" || feedType === "Forex" || feedType === "Datalink") { + if (schemaVersion === "v11") { + return ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Report Schema:</span> + </dt> + <dd> + <a href="/data-streams/reference/report-schema-v11" rel="noreferrer" target="_blank"> + Report Schema v11 (RWA Advanced) + </a> + </dd> + </div> + ) + } else if (schemaVersion === "v8") { + return ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Report Schema:</span> + </dt> + <dd> + <a href="/data-streams/reference/report-schema-v8" rel="noreferrer" target="_blank"> + Report Schema v8 (RWA Standard) + </a> + </dd> + </div> + ) + } + } + + // Exchange Rate streams + if (metadata.docs?.productTypeCode === "ExRate") { + return ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Report Schema:</span> + </dt> + <dd> + <a href="/data-streams/reference/report-schema-v7" rel="noreferrer" target="_blank"> + Report Schema v7 (Redemption Rates) + </a> + </dd> + </div> + ) + } + + // NAV streams + if (feedType === "Net Asset Value") { + return ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Report Schema:</span> + </dt> + <dd> + <a href="/data-streams/reference/report-schema-v9" rel="noreferrer" target="_blank"> + Report Schema v9 (NAV) + </a> + </dd> + </div> + ) + } + + // Tokenized Equities streams + if (feedType === "Tokenized Equities") { + return ( + <div className={tableStyles.definitionGroup}> + <dt> + <span className="label">Report Schema:</span> + </dt> + <dd> + <a href="/data-streams/reference/report-schema-v10" rel="noreferrer" target="_blank"> + Report Schema v10 (Tokenized Assets) + </a> + </dd> + </div> + ) + } + + return null + })()} + </dl> + </div> + </td> + </tr> + ) +} export const MainnetTable = ({ network, @@ -1068,6 +1223,8 @@ export const MainnetTable = ({ showOnlyDEXFeeds, rwaSchemaFilter, streamCategoryFilter, + show24x5Feeds, + tradingHoursFilter, dataFeedType, ecosystem, selectedFeedCategories, @@ -1077,6 +1234,7 @@ export const MainnetTable = ({ currentPage, paginate, searchValue, + tokenizedEquityProvider, }: { network: ChainNetwork showExtraDetails: boolean @@ -1085,6 +1243,8 @@ export const MainnetTable = ({ showOnlyDEXFeeds: boolean rwaSchemaFilter?: "all" | "v8" | "v11" streamCategoryFilter?: "all" | "datalink" | "equities" | "forex" + show24x5Feeds?: boolean + tradingHoursFilter?: "all" | "regular" | "extended" | "overnight" dataFeedType: string ecosystem: string selectedFeedCategories: string[] @@ -1094,6 +1254,7 @@ export const MainnetTable = ({ currentPage: number paginate searchValue: string + tokenizedEquityProvider?: string }) => { if (!network.metadata) return null @@ -1110,122 +1271,89 @@ export const MainnetTable = ({ const isDefault = !isStreams && !isSmartData && !isUSGovernmentMacroeconomicData const isDeprecating = ecosystem === "deprecating" - const filteredMetadata = network.metadata - .sort((a, b) => (a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1)) - .filter((metadata) => { - // --- - // Categorization logic: - // 1. Try to get the risk category for this feed from Supabase (batchedCategoryData). - // - Uses contractAddress and networkIdentifier as lookup keys. - // - If found, use the DB value; if not, fall back to the default from metadata. - // 2. If the risk category is 'hidden', exclude this feed from the docs. - // --- - const contractAddress = metadata.contractAddress || metadata.proxyAddress - const networkIdentifier = getNetworkIdentifier(network) - let batchCategory = metadata.feedCategory - - if (contractAddress && batchedCategoryData?.size) { - const categoryResult = getFeedCategoryFromBatch( - batchedCategoryData, - contractAddress, - networkIdentifier, - metadata.feedCategory - ) - const finalCategory = categoryResult?.final ?? null - - if (finalCategory) { - batchCategory = finalCategory - } - } - - if (batchCategory === "hidden") return false - if (showOnlySVR && !metadata.secondaryProxyAddress) { - return false - } - - if (isDeprecating) return !!metadata.docs.shutdownDate - - if (dataFeedType === "streamsCrypto") { - const isValidStreamsFeed = - metadata.contractType === "verifier" && - (metadata.docs.feedType === "Crypto" || metadata.docs.feedType === "Crypto-DEX") - - if (showOnlyDEXFeeds) { - return isValidStreamsFeed && metadata.docs.feedType === "Crypto-DEX" - } - - return isValidStreamsFeed - } - if (dataFeedType === "streamsRwa") { - const isRwaFeed = - metadata.contractType === "verifier" && - (metadata.docs.feedType === "Equities" || - metadata.docs.feedType === "Forex" || - metadata.docs.feedType === "Datalink") - - if (!isRwaFeed) return false - - // Apply feed type filter - if (streamCategoryFilter === "datalink") { - if (metadata.docs.feedType !== "Datalink") return false - } else if (streamCategoryFilter === "equities") { - if (metadata.docs.feedType !== "Equities") return false - } else if (streamCategoryFilter === "forex") { - if (metadata.docs.feedType !== "Forex") return false - } + // Enrich metadata with final category (combining RDD and Supabase data) + // Priority: deprecating status from RDD > Supabase risk tier > RDD category fallback + const enrichedMetadata = network.metadata.map((metadata) => { + // Check for deprecating status from RDD first (has shutdown date) + if (metadata.docs?.shutdownDate) { + return { ...metadata, finalCategory: "deprecating" } + } - // Apply schema filter - if (rwaSchemaFilter === "v8") { - return metadata.docs?.schema === "v8" || !metadata.docs?.schema - } - if (rwaSchemaFilter === "v11") { - return metadata.docs?.schema === "v11" - } + // Otherwise, get risk category from Supabase (or fall back to RDD) + const contractAddress = metadata.contractAddress || metadata.proxyAddress + const networkIdentifier = getNetworkIdentifier(network) + let finalCategory = metadata.feedCategory + + if (contractAddress && batchedCategoryData?.size) { + const categoryResult = getFeedCategoryFromBatch( + batchedCategoryData, + contractAddress, + networkIdentifier, + metadata.feedCategory + ) + const supabaseCategory = categoryResult?.final ?? null - return true + if (supabaseCategory) { + finalCategory = supabaseCategory } + } - if (dataFeedType === "streamsNav") { - return metadata.contractType === "verifier" && metadata.docs.feedType === "Net Asset Value" - } + return { ...metadata, finalCategory } + }) - if (dataFeedType === "streamsExRate") { - return metadata.contractType === "verifier" && metadata.docs?.productTypeCode === "ExRate" + const filteredMetadata = enrichedMetadata + .sort((a, b) => (a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1)) + .filter((metadata) => { + if (showOnlySVR && !metadata.secondaryProxyAddress) { + return false } - if (dataFeedType === "streamsBacked") { - return metadata.contractType === "verifier" && metadata.docs.feedType === "Tokenized Equities" + if (isDeprecating) { + // Only show feeds (not streams) with shutdown dates + return !!metadata.docs.shutdownDate && !(metadata.contractType === "verifier" && metadata.feedId) } - if (isSmartData) { - if (showOnlyMVRFeeds) { - return !metadata.docs?.hidden && metadata.docs?.isMVR === true && metadata.docs?.deliveryChannelCode !== "DS" + // Use shared visibility logic with filters + return isFeedVisible(metadata, dataFeedType as any, ecosystem, { + showOnlyDEXFeeds, + streamCategoryFilter, + rwaSchemaFilter, + showOnlyMVRFeeds, + tokenizedEquityProvider, + }) + }) + .filter((metadata) => { + // When 24/5 checkbox is checked, ONLY show 24/5 feeds + if (show24x5Feeds) { + const schemaVersion = getSchemaVersion(metadata) + const feedType = metadata.feedType || metadata.docs?.feedType + + // 24/5 feeds are Equities/Forex with v11 schema + const is24x5Feed = (feedType === "Equities" || feedType === "Forex") && schemaVersion === "v11" + + if (!is24x5Feed) return false + + // Apply trading hours sub-filter + if (tradingHoursFilter && tradingHoursFilter !== "all") { + const assetSubClass = (metadata.docs as any)?.assetSubClass + const clicProductName = (metadata.docs as any)?.clicProductName || "" + + // Check both assetSubClass and clicProductName for hours identification + const isRegularHours = + assetSubClass === "Regular Hours" || + (clicProductName.includes("RegularHours") && + !clicProductName.includes("ExtendedHours") && + !clicProductName.includes("OvernightHours")) + const isExtendedHours = assetSubClass === "Extended Hours" || clicProductName.includes("ExtendedHours") + const isOvernightHours = assetSubClass === "Overnight Hours" || clicProductName.includes("OvernightHours") + + if (tradingHoursFilter === "regular" && !isRegularHours) return false + if (tradingHoursFilter === "extended" && !isExtendedHours) return false + if (tradingHoursFilter === "overnight" && !isOvernightHours) return false } - - return ( - !metadata.docs?.hidden && - metadata.docs?.deliveryChannelCode !== "DS" && - (metadata.docs?.productType === "Proof of Reserve" || - metadata.docs?.productType === "NAVLink" || - metadata.docs?.productType === "SmartAUM" || - metadata.docs?.isMVR === true) - ) } - if (isUSGovernmentMacroeconomicData) { - const isMacro = metadata.docs?.productTypeCode === "RefMacro" - return isMacro - } - - // Exclude MVR feeds from default view - return ( - !metadata.docs.porType && - metadata.contractType !== "verifier" && - metadata.docs.productType !== "Proof of Reserve" && - metadata.docs.productType !== "NAVLink" && - metadata.docs.productType !== "SmartAUM" && - metadata.docs?.productTypeCode !== "RefMacro" - ) + return true }) .filter((metadata) => { if (isSmartData) { @@ -1241,9 +1369,12 @@ export const MainnetTable = ({ return included } + // Filter by final category (Supabase risk tier takes precedence over RDD) + // Normalize spaces for comparison (e.g., "very high" → "veryhigh") + const normalizedFinalCategory = metadata.finalCategory?.toLowerCase().replace(/\s+/g, "") return ( selectedFeedCategories.length === 0 || - selectedFeedCategories.map((cat) => cat.toLowerCase()).includes(metadata.feedCategory?.toLowerCase()) + selectedFeedCategories.map((cat) => cat.toLowerCase().replace(/\s+/g, "")).includes(normalizedFinalCategory) ) }) .filter( @@ -1368,6 +1499,9 @@ export const TestnetTable = ({ showOnlyDEXFeeds, rwaSchemaFilter, streamCategoryFilter, + show24x5Feeds, + tradingHoursFilter, + tokenizedEquityProvider, }: { network: ChainNetwork showExtraDetails: boolean @@ -1383,6 +1517,9 @@ export const TestnetTable = ({ showOnlyDEXFeeds?: boolean rwaSchemaFilter?: "all" | "v8" | "v11" streamCategoryFilter?: "all" | "datalink" | "equities" | "forex" + show24x5Feeds?: boolean + tradingHoursFilter?: "all" | "regular" | "extended" | "overnight" + tokenizedEquityProvider?: string }) => { if (!network.metadata) return null @@ -1399,127 +1536,80 @@ export const TestnetTable = ({ const isUSGovernmentMacroeconomicData = dataFeedType === "usGovernmentMacroeconomicData" const isDefault = !isSmartData && !isRates && !isStreams && !isUSGovernmentMacroeconomicData - const filteredMetadata = network.metadata - .sort((a, b) => (a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1)) - .filter((metadata) => { - // --- - // Categorization logic: - // 1. Try to get the risk category for this feed from Supabase (batchedCategoryData). - // - Uses contractAddress and networkIdentifier as lookup keys. - // - If found, use the DB value; if not, fall back to the default from metadata. - // 2. If the risk category is 'hidden', exclude this feed from the docs. - // --- - const contractAddress = metadata.contractAddress || metadata.proxyAddress - const networkIdentifier = getNetworkIdentifier(network) - let batchCategory = metadata.feedCategory - - if (contractAddress && batchedCategoryData?.size) { - const categoryResult = getFeedCategoryFromBatch( - batchedCategoryData, - contractAddress, - networkIdentifier, - metadata.feedCategory - ) - const finalCategory = categoryResult?.final ?? null - - if (finalCategory) { - batchCategory = finalCategory - } - } - - if (batchCategory === "hidden") return false - if (isStreams) { - if (dataFeedType === "streamsCrypto") { - const isValidStreamsFeed = - metadata.contractType === "verifier" && - (metadata.feedType === "Crypto" || metadata.feedType === "Crypto-DEX") - - if (showOnlyDEXFeeds) { - return isValidStreamsFeed && metadata.feedType === "Crypto-DEX" - } - - return isValidStreamsFeed - } - - if (dataFeedType === "streamsRwa") { - const isRwaFeed = - metadata.contractType === "verifier" && - (metadata.docs.feedType === "Equities" || - metadata.docs.feedType === "Forex" || - metadata.docs.feedType === "Datalink") - - if (!isRwaFeed) return false - - // Apply feed type filter - if (streamCategoryFilter === "datalink") { - if (metadata.docs.feedType !== "Datalink") return false - } else if (streamCategoryFilter === "equities") { - if (metadata.docs.feedType !== "Equities") return false - } else if (streamCategoryFilter === "forex") { - if (metadata.docs.feedType !== "Forex") return false - } - - // Apply schema filter - if (rwaSchemaFilter === "v8") { - return metadata.docs?.schema === "v8" || !metadata.docs?.schema - } - if (rwaSchemaFilter === "v11") { - return metadata.docs?.schema === "v11" - } - - return true - } - - if (dataFeedType === "streamsExRate") { - return metadata.contractType === "verifier" && metadata.docs?.productTypeCode === "ExRate" - } - - if (dataFeedType === "streamsNav") { - return metadata.contractType === "verifier" && metadata.docs.feedType === "Net Asset Value" - } - - if (dataFeedType === "streamsBacked") { - return metadata.contractType === "verifier" && metadata.docs.feedType === "Tokenized Equities" - } - - // If we're in streams mode but didn't match any specific stream type, exclude this feed - return false - } + // Enrich metadata with final category (combining RDD and Supabase data) + // Priority: deprecating status from RDD > Supabase risk tier > RDD category fallback + const enrichedMetadata = network.metadata.map((metadata) => { + // Check for deprecating status from RDD first (has shutdown date) + if (metadata.docs?.shutdownDate) { + return { ...metadata, finalCategory: "deprecating" } + } - if (isSmartData) { - if (showOnlyMVRFeeds) { - return !metadata.docs?.hidden && metadata.docs?.isMVR === true && metadata.docs?.deliveryChannelCode !== "DS" - } + // Otherwise, get risk category from Supabase (or fall back to RDD) + const contractAddress = metadata.contractAddress || metadata.proxyAddress + const networkIdentifier = getNetworkIdentifier(network) + let finalCategory = metadata.feedCategory + + if (contractAddress && batchedCategoryData?.size) { + const categoryResult = getFeedCategoryFromBatch( + batchedCategoryData, + contractAddress, + networkIdentifier, + metadata.feedCategory + ) + const supabaseCategory = categoryResult?.final ?? null - // Otherwise, include all SmartData feeds (MVR, PoR, NAVLink, SmartAUM) - return ( - !metadata.docs?.hidden && - metadata.docs?.deliveryChannelCode !== "DS" && - (metadata.docs?.productType === "Proof of Reserve" || - metadata.docs?.productType === "NAVLink" || - metadata.docs?.productType === "SmartAUM" || - metadata.docs?.isMVR === true) - ) + if (supabaseCategory) { + finalCategory = supabaseCategory } + } - if (isRates) - return !!(metadata.docs.productType === "Rates" || metadata.docs.productSubType === "Realized Volatility") + return { ...metadata, finalCategory } + }) - if (isUSGovernmentMacroeconomicData) { - return metadata.docs?.productTypeCode === "RefMacro" + const filteredMetadata = enrichedMetadata + .sort((a, b) => (a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1)) + .filter((metadata) => { + // Use shared visibility logic with filters + return isFeedVisible(metadata, dataFeedType as any, undefined, { + showOnlyDEXFeeds, + streamCategoryFilter, + rwaSchemaFilter, + showOnlyMVRFeeds, + tokenizedEquityProvider, + }) + }) + .filter((metadata) => { + // When 24/5 checkbox is checked, ONLY show 24/5 feeds + if (show24x5Feeds) { + const schemaVersion = getSchemaVersion(metadata) + const feedType = metadata.feedType || metadata.docs?.feedType + + // 24/5 feeds are Equities/Forex with v11 schema + const is24x5Feed = (feedType === "Equities" || feedType === "Forex") && schemaVersion === "v11" + + if (!is24x5Feed) return false + + // Apply trading hours sub-filter + if (tradingHoursFilter && tradingHoursFilter !== "all") { + const assetSubClass = (metadata.docs as any)?.assetSubClass + const clicProductName = (metadata.docs as any)?.clicProductName || "" + + // Check both assetSubClass and clicProductName for hours identification + const isRegularHours = + assetSubClass === "Regular Hours" || + (clicProductName.includes("RegularHours") && + !clicProductName.includes("ExtendedHours") && + !clicProductName.includes("OvernightHours")) + const isExtendedHours = assetSubClass === "Extended Hours" || clicProductName.includes("ExtendedHours") + const isOvernightHours = assetSubClass === "Overnight Hours" || clicProductName.includes("OvernightHours") + + if (tradingHoursFilter === "regular" && !isRegularHours) return false + if (tradingHoursFilter === "extended" && !isExtendedHours) return false + if (tradingHoursFilter === "overnight" && !isOvernightHours) return false + } } - // Exclude MVR feeds from default view - return ( - !metadata.feedId && - !metadata.docs.porType && - metadata.docs.productType !== "Rates" && - metadata.docs.productSubType !== "Realized Volatility" && - metadata.docs.productType !== "Proof of Reserve" && - metadata.docs.productType !== "NAVLink" && - metadata.docs.productType !== "SmartAUM" && - metadata.docs?.productTypeCode !== "RefMacro" - ) + return true }) .filter((metadata) => { if (isSmartData) { @@ -1534,9 +1624,12 @@ export const TestnetTable = ({ return included } + // Filter by final category (Supabase risk tier takes precedence over RDD) + // Normalize spaces for comparison (e.g., "very high" → "veryhigh") + const normalizedFinalCategory = metadata.finalCategory?.toLowerCase().replace(/\s+/g, "") return ( selectedFeedCategories.length === 0 || - selectedFeedCategories.map((cat) => cat.toLowerCase()).includes(metadata.feedCategory?.toLowerCase()) + selectedFeedCategories.map((cat) => cat.toLowerCase().replace(/\s+/g, "")).includes(normalizedFinalCategory) ) }) .filter( diff --git a/src/features/feeds/components/urlStateHelpers.ts b/src/features/feeds/components/urlStateHelpers.ts new file mode 100644 index 00000000000..4203e37b79b --- /dev/null +++ b/src/features/feeds/components/urlStateHelpers.ts @@ -0,0 +1,86 @@ +/** + * URL state management helpers for feed tables + * Clean up empty and default values from URLs + */ + +/** + * Update URL with only non-empty, non-default values + * Removes clutter like search=&page=1 + */ +export function updateUrlClean(updates: Record<string, string | number | boolean | undefined>) { + if (typeof window === "undefined") return + + const params = new URLSearchParams(window.location.search) + + // Apply updates + Object.entries(updates).forEach(([key, value]) => { + // Remove param if undefined, empty string, or default value + if ( + value === undefined || + value === "" || + (key === "page" && value === 1) || + (key === "page" && value === "1") || + (key === "testnetPage" && value === 1) || + (key === "testnetPage" && value === "1") || + (key.includes("Schema") && value === "all") || + (key.includes("FeedType") && value === "all") || + value === false + ) { + params.delete(key) + } else { + params.set(key, String(value)) + } + }) + + // Build URL with params in logical order: network → networkType → filters → pagination + const orderedParams = new URLSearchParams() + const order = [ + "network", + "networkType", + "search", + "testnetSearch", + "categories", + "showSvr", + "showDetails", + "feedType", + "testnetFeedType", + "schema", + "testnetSchema", + "page", + "testnetPage", + ] + + order.forEach((key) => { + if (params.has(key)) { + const values = params.getAll(key) + values.forEach((v) => orderedParams.append(key, v)) + } + }) + + const queryString = orderedParams.toString() + const newUrl = window.location.pathname + (queryString ? "?" + queryString : "") + window.location.hash + window.history.replaceState({ path: newUrl }, "", newUrl) +} + +/** + * Clear all filter-related params, optionally keeping network selection + */ +export function clearFilters(keepNetwork = true) { + if (typeof window === "undefined") return + + const params = new URLSearchParams(window.location.search) + const network = params.get("network") + const networkType = params.get("networkType") + + // Start fresh + const newParams = new URLSearchParams() + + if (keepNetwork) { + if (network) newParams.set("network", network) + if (networkType && networkType !== "mainnet") newParams.set("networkType", networkType) + } + + const queryString = newParams.toString() + const newUrl = window.location.pathname + (queryString ? "?" + queryString : "") + window.location.hash + window.history.replaceState({ path: newUrl }, "", newUrl) +} diff --git a/src/features/feeds/components/useCleanUrlParams.ts b/src/features/feeds/components/useCleanUrlParams.ts new file mode 100644 index 00000000000..b85aa7200e0 --- /dev/null +++ b/src/features/feeds/components/useCleanUrlParams.ts @@ -0,0 +1,184 @@ +/** + * Clean URL parameter management for feed tables + * + * Philosophy: + * - Only add params when they differ from defaults + * - Keep URL minimal and human-readable + * - Order params logically: network → type → filters → pagination + * - Clear related params when context changes (e.g., switching networks) + */ + +import { useCallback } from "preact/hooks" + +export type FeedUrlParams = { + // Network selection + network?: string + networkType?: "mainnet" | "testnet" + + // Search filters + search?: string + testnetSearch?: string + + // Category filters + categories?: string[] + + // Feature flags + showSvr?: boolean + showDetails?: boolean + + // Pagination + page?: number + testnetPage?: number + + // Streams-specific filters + feedType?: string + testnetFeedType?: string + schema?: string + testnetSchema?: string +} + +const DEFAULT_VALUES: Required<FeedUrlParams> = { + network: "", + networkType: "mainnet", + search: "", + testnetSearch: "", + categories: [], + showSvr: false, + showDetails: false, + page: 1, + testnetPage: 1, + feedType: "all", + testnetFeedType: "all", + schema: "all", + testnetSchema: "all", +} + +/** + * Build a clean URL with only non-default parameters + */ +function buildCleanUrl(params: Partial<FeedUrlParams>, pathname: string, hash = ""): string { + const urlParams = new URLSearchParams() + + // Add params in logical order (network first, then filters, then pagination) + const orderedKeys: (keyof FeedUrlParams)[] = [ + "network", + "networkType", + "search", + "testnetSearch", + "categories", + "showSvr", + "showDetails", + "feedType", + "testnetFeedType", + "schema", + "testnetSchema", + "page", + "testnetPage", + ] + + orderedKeys.forEach((key) => { + const value = params[key] + const defaultValue = DEFAULT_VALUES[key] + + // Skip if value is undefined or matches default + if (value === undefined) return + + // Handle arrays + if (Array.isArray(value)) { + if (value.length === 0) return // Skip empty arrays + value.forEach((v) => urlParams.append(key, v)) + return + } + + // Handle booleans + if (typeof value === "boolean") { + if (!value) return // Only add true values + urlParams.set(key, "true") + return + } + + // Handle strings and numbers + const stringValue = String(value) + const defaultStringValue = String(defaultValue) + + if (stringValue !== defaultStringValue && stringValue !== "") { + urlParams.set(key, stringValue) + } + }) + + const queryString = urlParams.toString() + return pathname + (queryString ? "?" + queryString : "") + hash +} + +/** + * Parse current URL params into a typed object + */ +function parseUrlParams(initialNetwork?: string): FeedUrlParams { + if (typeof window === "undefined") { + return { network: initialNetwork } + } + + const urlParams = new URLSearchParams(window.location.search) + + return { + network: urlParams.get("network") || undefined, + networkType: (urlParams.get("networkType") as "mainnet" | "testnet") || undefined, + search: urlParams.get("search") || undefined, + testnetSearch: urlParams.get("testnetSearch") || undefined, + categories: urlParams.getAll("categories").filter(Boolean), + showSvr: urlParams.get("showSvr") === "true" || undefined, + showDetails: urlParams.get("showDetails") === "true" || undefined, + page: urlParams.get("page") ? parseInt(urlParams.get("page") || "1") : undefined, + testnetPage: urlParams.get("testnetPage") ? parseInt(urlParams.get("testnetPage") || "1") : undefined, + feedType: urlParams.get("feedType") || undefined, + testnetFeedType: urlParams.get("testnetFeedType") || undefined, + schema: urlParams.get("schema") || undefined, + testnetSchema: urlParams.get("testnetSchema") || undefined, + } +} + +export function useCleanUrlParams(initialNetwork: string) { + const updateUrl = useCallback( + (updates: Partial<FeedUrlParams>, clearRelated = false) => { + if (typeof window === "undefined") return + + const current = parseUrlParams(initialNetwork) + let newParams: Partial<FeedUrlParams> + + if (clearRelated) { + // When clearing related params, start fresh with only the updates + newParams = { ...updates } + } else { + // Merge with existing params + newParams = { ...current, ...updates } + } + + const newUrl = buildCleanUrl(newParams, window.location.pathname, window.location.hash) + window.history.replaceState({ path: newUrl }, "", newUrl) + }, + [initialNetwork] + ) + + const getCurrentParams = useCallback(() => { + return parseUrlParams(initialNetwork) + }, [initialNetwork]) + + const clearAllFilters = useCallback( + (keepNetwork = true) => { + const newParams: Partial<FeedUrlParams> = {} + if (keepNetwork) { + const current = parseUrlParams(initialNetwork) + if (current.network) newParams.network = current.network + if (current.networkType) newParams.networkType = current.networkType + } + updateUrl(newParams, true) + }, + [updateUrl, initialNetwork] + ) + + return { + updateUrl, + getCurrentParams, + clearAllFilters, + } +} diff --git a/src/features/feeds/data/StreamsNetworksData.ts b/src/features/feeds/data/StreamsNetworksData.ts index 37ed9544dfe..841810082b3 100644 --- a/src/features/feeds/data/StreamsNetworksData.ts +++ b/src/features/feeds/data/StreamsNetworksData.ts @@ -4,6 +4,7 @@ export type NetworkDetails = { accessController?: string explorerUrl: string label: string + note?: string } export type NetworkData = { @@ -283,12 +284,12 @@ export const StreamsNetworksData: NetworkData[] = [ mainnet: { label: "HyperEVM Mainnet", verifierProxy: "0x60fAa7faC949aF392DFc858F5d97E3EEfa07E9EB", - explorerUrl: "https://hyperliquid.cloud.blockscout.com/address/%s", + explorerUrl: "https://hyperevmscan.io/address/address/%s", }, testnet: { label: "HyperEVM Testnet", verifierProxy: "0x60fAa7faC949aF392DFc858F5d97E3EEfa07E9EB", - explorerUrl: "https://evm.hyperstats.xyz/address/%s", + explorerUrl: "https://testnet.purrsec.com/address/%s", }, }, { @@ -391,10 +392,15 @@ export const StreamsNetworksData: NetworkData[] = [ network: "MegaETH", logoUrl: "/assets/chains/megaeth.svg", networkStatus: "https://uptime.megaeth.com", + mainnet: { + label: "MegaETH Mainnet", + verifierProxy: "0x60fAa7faC949aF392DFc858F5d97E3EEfa07E9EB", + explorerUrl: "https://megaeth.blockscout.com/address/%s", + }, testnet: { label: "MegaETH Testnet", - verifierProxy: "0xfBFff08fE4169853F7B1b5Ac67eC10dc8806801d", - explorerUrl: "https://www.megaexplorer.xyz/address/%s", + verifierProxy: "0xa33c1F0561eECe58ee7b7349D5BE018dd94EC9B6", + explorerUrl: "https://megaeth-testnet-v2.blockscout.com/address/%s", }, }, { @@ -454,6 +460,20 @@ export const StreamsNetworksData: NetworkData[] = [ explorerUrl: "https://sepolia-optimism.etherscan.io/address/%s", }, }, + { + network: "Pharos", + logoUrl: "/assets/chains/pharos.svg", + mainnet: { + label: "Pharos Mainnet (Private)", + verifierProxy: "0xa094978891512268f4a4a4641B8da1A2a3E3BEB7", + explorerUrl: "https://pharos.socialscan.io/address/%s", + }, + testnet: { + label: "Pharos Atlantic Testnet", + verifierProxy: "0x72790f9eb82db492a7ddb6d2af22a270dcc3db64", + explorerUrl: "https://atlantic.pharosscan.xyz/address/%s", + }, + }, { network: "Polygon", logoUrl: "/assets/chains/polygon.svg", diff --git a/src/features/feeds/utils/feedVisibility.ts b/src/features/feeds/utils/feedVisibility.ts new file mode 100644 index 00000000000..2eaa09556b8 --- /dev/null +++ b/src/features/feeds/utils/feedVisibility.ts @@ -0,0 +1,183 @@ +import { DataFeedType } from "../components/FeedList.tsx" + +/** + * Helper function to extract schema version from feed metadata + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function getSchemaVersion(feed: any): string | undefined { + // First try to get from docs.schema + if (feed.docs?.schema) { + return feed.docs.schema + } + + // Fallback: parse from clicProductName + const clicProductName = feed.docs?.clicProductName + if (clicProductName) { + const match = clicProductName.match(/-0(\d{2})$/) + if (match) { + const version = match[1] + if (version === "04" || version === "08") return "v8" + if (version === "11") return "v11" + } + } + + return undefined +} + +/** + * Determines if a feed should be visible based on: + * - Hidden flags (feedCategory === "hidden" or docs.hidden) + * - Data feed type filtering (streams, smartdata, rates, etc.) + * - Ecosystem filtering (deprecating) + * + * This logic is shared between table filtering and network availability checks. + */ +export interface FeedVisibilityOptions { + showOnlyDEXFeeds?: boolean + streamCategoryFilter?: string + rwaSchemaFilter?: string + showOnlyMVRFeeds?: boolean + tokenizedEquityProvider?: string // Filter tokenized equity feeds by provider (e.g., "ondo") +} + +/** + * Determines if a feed should be visible based on: + * - Hidden flags (feedCategory === "hidden" or docs.hidden) + * - Data feed type filtering (streams, smartdata, rates, etc.) + * - Ecosystem filtering (deprecating) + * - Optional filters (DEX only, MVR only, schema version, etc.) + * + * This logic is shared between table filtering and network availability checks. + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isFeedVisible( + feed: any, + dataFeedType: DataFeedType, + ecosystem = "", + options: FeedVisibilityOptions = {} +): boolean { + // =========================================================================== + // 1. Universal Exclusions + // =========================================================================== + // Tokenized equity feeds are allowed to bypass the hidden flag since they are + // marked hidden in the general feed list but should show on their dedicated page + const isTokenizedEquity = dataFeedType === "tokenizedEquity" + if (feed.docs?.hidden && !isTokenizedEquity) return false + + const isDeprecating = ecosystem === "deprecating" + const isStreams = + dataFeedType === "streamsCrypto" || + dataFeedType === "streamsRwa" || + dataFeedType === "streamsNav" || + dataFeedType === "streamsExRate" || + dataFeedType === "streamsBacked" + const isSmartData = dataFeedType === "smartdata" + const isRates = dataFeedType === "rates" + const isUSGovernmentMacroeconomicData = dataFeedType === "usGovernmentMacroeconomicData" + + // =========================================================================== + // 2. Ecosystem-Specific Logic + // =========================================================================== + // If we are in the "deprecating" ecosystem view, ONLY show deprecating feeds. + if (isDeprecating && feed.feedCategory !== "deprecating") return false + + let isVisible = false + + // =========================================================================== + // 3. Data Feed Type Logic (Base Visibility) + // =========================================================================== + // Determine if the feed belongs to the requested category (Streams, SmartData, etc.) + + if (isStreams) { + // Streams feeds must be verified contracts + if (feed.contractType !== "verifier") return false + + if (dataFeedType === "streamsCrypto") { + isVisible = ["Crypto", "Crypto-DEX"].includes(feed.docs?.feedType) + } else if (dataFeedType === "streamsRwa") { + isVisible = ["Equities", "Forex", "Datalink"].includes(feed.docs?.feedType) + } else if (dataFeedType === "streamsNav") { + isVisible = feed.docs?.feedType === "Net Asset Value" + } else if (dataFeedType === "streamsExRate") { + isVisible = feed.docs?.productTypeCode === "ExRate" + } else if (dataFeedType === "streamsBacked") { + isVisible = feed.docs?.feedType === "Tokenized Equities" + } + } else if (isSmartData) { + // SmartData feeds (excluding DS delivery channel) + if (feed.docs?.deliveryChannelCode === "DS") isVisible = false + else + isVisible = + feed.docs?.isMVR === true || + feed.docs?.productType === "Proof of Reserve" || + feed.docs?.productType === "NAVLink" || + feed.docs?.productType === "SmartAUM" + } else if (isUSGovernmentMacroeconomicData) { + isVisible = feed.docs?.productTypeCode === "RefMacro" + } else if (isRates) { + isVisible = feed.docs?.productType === "Rates" || feed.docs?.productSubType === "Realized Volatility" + } else if (isTokenizedEquity) { + // Tokenized equity feeds (Ondo and other providers) + // Filter by assetClass "Equities" for Data Feeds (not Streams verifier contracts) + isVisible = feed.docs?.assetClass === "Equities" && feed.contractType !== "verifier" + } else { + // Default data feeds (Standard Price Feeds) + // Exclude all special types to leave only the standard feeds + isVisible = + !feed.docs?.porType && + feed.contractType !== "verifier" && + feed.docs?.productType !== "Proof of Reserve" && + feed.docs?.productType !== "NAVLink" && + feed.docs?.productType !== "SmartAUM" && + feed.docs?.productType !== "Rates" && + feed.docs?.productTypeCode !== "RefMacro" && + !feed.docs?.isMVR + } + + if (!isVisible) return false + + // =========================================================================== + // 4. Optional Filters (User Selection) + // =========================================================================== + // Apply additional filters selected by the user in the UI + + // Filter: Show only DEX feeds (Streams Crypto) + if (dataFeedType === "streamsCrypto" && options.showOnlyDEXFeeds) { + if (feed.docs?.feedType !== "Crypto-DEX") return false + } + + // Filter: RWA Category & Schema (Streams RWA) + if (dataFeedType === "streamsRwa") { + if (options.streamCategoryFilter === "datalink" && feed.docs.feedType !== "Datalink") return false + if (options.streamCategoryFilter === "equities" && feed.docs.feedType !== "Equities") return false + if (options.streamCategoryFilter === "forex" && feed.docs.feedType !== "Forex") return false + + const schemaVersion = getSchemaVersion(feed) + if (options.rwaSchemaFilter === "v8" && schemaVersion !== "v8") return false + if (options.rwaSchemaFilter === "v11" && schemaVersion !== "v11") return false + } + + // Filter: Show only MVR feeds (SmartData) + if (isSmartData && options.showOnlyMVRFeeds) { + if (feed.docs?.isMVR !== true) return false + } + + // Filter: Tokenized equity feeds by provider + if (isTokenizedEquity && options.tokenizedEquityProvider) { + const provider = options.tokenizedEquityProvider.toLowerCase() + + if (provider === "ondo") { + // Ondo tokenized equity feeds are identified by BOTH: + // 1. "Ondo" in assetName — distinguishes from other tokenized equity providers + // 2. productTypeCode "primaryTokenizedPrice" — distinguishes from ONDO token feeds + // Neither signal alone is sufficient: other providers may share the productTypeCode, + // and ONDO governance token feeds may contain "Ondo" in the asset name. + const assetName = (feed.assetName || "").toLowerCase() + const isOndoFeed = assetName.includes("ondo") && feed.docs?.productTypeCode === "primaryTokenizedPrice" + if (!isOndoFeed) return false + } + // Add more provider patterns here as needed + } + + return true +} diff --git a/src/features/redirects/redirects.json b/src/features/redirects/redirects.json index a059180af4f..d36c068fe2d 100644 --- a/src/features/redirects/redirects.json +++ b/src/features/redirects/redirects.json @@ -2569,6 +2569,51 @@ "source": "ccip/tools-resources/tools", "destination": "ccip/tools-resources/cli", "statusCode": 301 + }, + { + "source": "ccip/concepts/architecture/offchain/risk-management-network", + "destination": "ccip/concepts/architecture/offchain/overview", + "statusCode": 301 + }, + { + "source": "cre/guides/workflow/using-evm-client/supported-networks", + "destination": "cre/supported-networks", + "statusCode": 301 + }, + { + "source": "cre/guides/workflow/using-evm-client/supported-networks-go", + "destination": "cre/supported-networks-go", + "statusCode": 301 + }, + { + "source": "cre/guides/workflow/using-evm-client/supported-networks-ts", + "destination": "cre/supported-networks-ts", + "statusCode": 301 + }, + { + "source": "cre/concepts/time-in-cre", + "destination": "cre/guides/workflow/time-in-workflows", + "statusCode": 301 + }, + { + "source": "cre/concepts/time-in-cre-go", + "destination": "cre/guides/workflow/time-in-workflows-go", + "statusCode": 301 + }, + { + "source": "cre/concepts/time-in-cre-ts", + "destination": "cre/guides/workflow/time-in-workflows-ts", + "statusCode": 301 + }, + { + "source": "cre/getting-started/conclusion", + "destination": "cre/getting-started/before-you-build", + "statusCode": 301 + }, + { + "source": "cre/concepts/random-in-cre", + "destination": "cre/guides/workflow/using-randomness", + "statusCode": 301 } ] } diff --git a/src/features/streams/components/StreamsPage.astro b/src/features/streams/components/StreamsPage.astro new file mode 100644 index 00000000000..ad49e83bc6e --- /dev/null +++ b/src/features/streams/components/StreamsPage.astro @@ -0,0 +1,88 @@ +--- +import { FeedList, DataFeedType } from "@features/feeds/components/FeedList" +import { Aside } from "@components" +export type Props = { + initialNetwork?: string + ecosystem?: string + dataFeedType?: DataFeedType + allowNetworkTableExpansion?: boolean + defaultNetworkTableExpanded?: boolean +} +import { getServerSideChainMetadata } from "~/features/data/api/backend" +import { CHAINS, ALL_CHAINS } from "~/features/data/chains" + +const { initialNetwork, ecosystem, dataFeedType, allowNetworkTableExpansion, defaultNetworkTableExpanded } = Astro.props + +// Skip cache for deprecating page to always fetch fresh data +const isDeprecating = ecosystem === "deprecating" +const initialCache = await getServerSideChainMetadata([...CHAINS, ...ALL_CHAINS], isDeprecating) +--- + +{ + ecosystem === "deprecating" ? ( + <> + <p> + Due to the rapid evolution of onchain ecosystems, Chainlink Data Streams feeds are regularly evaluated to ensure + that network usage, cost efficiency, and long-term sustainability remain aligned with the needs of the + ecosystem. + </p> + <p> + As part of this ongoing evaluation, Data Streams feeds without publicly known active users may be scheduled for + deprecation. Doing so not only allows us to keep our Data Streams offering aligned with today's market + landscape, but it also helps to reduce unnecessary costs incurred by Chainlink node operators. This process is + part of a broader ecosystem initiative to maximize the adoption of the Chainlink network while optimizing for + cost-efficiency and long-term economic sustainability. + </p> + <p> + For status updates regarding Data Streams and Data Feeds, users should join the official{" "} + <a href="https://chain.link/discord">Chainlink Discord</a> and subscribe to the{" "} + <a href="https://discord.gg/Dqy5N9UbsR">data-feeds-user-notifications channel</a>. + </p> + <p> + A list of Data Streams feeds designated for deprecation, along with their corresponding shutdown date, can be + found below. + </p> + <Aside type="note" title="Reactivation"> + <p> + <strong>Deprecated Data Streams feeds can be reactivated at any time should new demand emerge</strong>. Teams + interested in re-enabling a deprecated Data Streams feed (or requesting a new one) can{" "} + <a href="https://chainlinkcommunity.typeform.com/datastreams?#ref_id=docs">reach out</a> to discuss + requirements, expected usage, and deployment timelines. + </p> + <p> + Always use caution and perform proper due diligence before integrating Chainlink Data Streams into your + application. Review our <a href="/data-streams/concepts/best-practices">Data Streams Best Practices</a> to + help manage risks, optimize performance, and ensure compliance with market standards. + </p> + </Aside> + </> + ) : ( + <> + <p> + To learn how to use Data Streams, see the{" "} + <a href="/data-streams/tutorials/go-sdk-fetch">Fetch and decode reports</a> tutorial. + </p> + <p> + For LINK token and Faucet details, see the{" "} + <a href="/resources/link-token-contracts?parent=dataFeeds">LINK Token Contracts</a> page. + </p> + + <Aside type="note" title="Talk to an expert"> + <p> + <a href="https://chainlinkcommunity.typeform.com/datastreams?#ref_id=docs">Contact us</a> to talk to an expert + about integrating Chainlink Data Streams with your applications. + </p> + </Aside> + </> + ) +} + +<FeedList + client:idle + initialNetwork={initialNetwork ?? "arbitrum"} + dataFeedType={dataFeedType ?? "streamsCrypto"} + ecosystem={ecosystem ?? ""} + initialCache={initialCache} + allowNetworkTableExpansion={allowNetworkTableExpansion} + defaultNetworkTableExpanded={defaultNetworkTableExpanded} +/> diff --git a/src/features/tokenized-equity-feeds/common/TokenizedEquityFeeds.astro b/src/features/tokenized-equity-feeds/common/TokenizedEquityFeeds.astro new file mode 100644 index 00000000000..04a7d838aa5 --- /dev/null +++ b/src/features/tokenized-equity-feeds/common/TokenizedEquityFeeds.astro @@ -0,0 +1,10 @@ +--- +import TokenizedEquityNoteComponent from "./tokenizedEquityNote.mdx" + +export type Props = { + section?: "tokenizedEquityNote" +} +const { section } = Astro.props as Props +--- + +{section === "tokenizedEquityNote" && <TokenizedEquityNoteComponent />} diff --git a/src/features/tokenized-equity-feeds/common/tokenizedEquityNote.mdx b/src/features/tokenized-equity-feeds/common/tokenizedEquityNote.mdx new file mode 100644 index 00000000000..671554c158b --- /dev/null +++ b/src/features/tokenized-equity-feeds/common/tokenizedEquityNote.mdx @@ -0,0 +1,11 @@ +import { Aside } from "@components" + +<Aside type="note"> + Tokenized equity feeds present unique operational considerations, requiring careful integration on behalf of your + protocol. Developers remain responsible for ensuring that protocol risk parameters are configured appropriately and + that the operation and performance of Chainlink Tokenized Equity Feeds matches expectations. Please review the + [Selecting Quality Data Feeds](/data-feeds/selecting-data-feeds) webpage and [Chainlink Terms of + Service](https://chain.link/terms) for important information and disclosures. Contact Chainlink Labs at + [chainlink_data_feeds@smartcontract.com](mailto:chainlink_data_feeds@smartcontract.com) to learn more about + integrating Tokenized Equity feeds in your solution. +</Aside> diff --git a/src/features/utils/index.ts b/src/features/utils/index.ts index 5b9732cd5a8..23e362a0c4e 100644 --- a/src/features/utils/index.ts +++ b/src/features/utils/index.ts @@ -9,8 +9,9 @@ import { ChainFamily, } from "@config/index.ts" import { CCIP_TOKEN_ICON_MAPPINGS } from "@config/data/ccip/tokenIconMappings.ts" +import { TOKEN_ICONS_PATH } from "@config/cdn.ts" import { toQuantity } from "ethers" -import referenceChains from "src/scripts/reference/chains.json" with { type: "json" } +import referenceChains from "~/scripts/reference/chains.json" with { type: "json" } interface AddEthereumChainParameter { chainId: string @@ -156,10 +157,11 @@ export const getTokenIconUrl = (token: string, size = 40) => { // Request appropriately sized images from CloudFront // For 40x40 display, request 80x80 for retina displays (2x) - return `https://d2f70xi62kby8n.cloudfront.net/tokens/${transformTokenName(iconIdentifier)}.webp?auto=compress%2Cformat&q=60&w=${size}&h=${size}&fit=cover` + return `${TOKEN_ICONS_PATH}/${transformTokenName(iconIdentifier)}.webp?auto=compress%2Cformat&q=60&w=${size}&h=${size}&fit=cover` } export const fallbackTokenIconUrl = "/assets/icons/generic-token.svg" +export const fallbackVerifierIconUrl = "/assets/icons/generic-verifier.svg" export const getChainId = (supportedChain: SupportedChain) => { const technology = chainToTechnology[supportedChain] @@ -276,6 +278,8 @@ export const directoryToSupportedChain = (chainInRdd: string): SupportedChain => return "SONEIUM_MINATO" case "ethereum-testnet-holesky": return "ETHEREUM_HOLESKY" + case "ethereum-testnet-hoodi": + return "ETHEREUM_HOODI" case "polkadot-mainnet-astar": return "ASTAR_MAINNET" case "polkadot-testnet-astar-shibuya": @@ -302,8 +306,10 @@ export const directoryToSupportedChain = (chainInRdd: string): SupportedChain => return "SHIBARIUM_PUPPYNET" case "sonic-mainnet": return "SONIC_MAINNET" + case "sonic-testnet": + return "SONIC_TESTNET" case "sonic-testnet-blaze": - return "SONIC_BLAZE" + return "SONIC_TESTNET_BLAZE" case "bitcoin-mainnet-bob-1": return "BOB_MAINNET" case "bitcoin-testnet-sepolia-bob-1": @@ -402,6 +408,8 @@ export const directoryToSupportedChain = (chainInRdd: string): SupportedChain => return "0G_MAINNET" case "megaeth-testnet": return "MEGAETH_TESTNET" + case "megaeth-mainnet": + return "MEGAETH_MAINNET" case "mind-testnet": return "MIND_NETWORK_TESTNET" case "mind-mainnet": @@ -514,6 +522,23 @@ export const directoryToSupportedChain = (chainInRdd: string): SupportedChain => return "NEXON_HENESYS_MAINNET" case "pharos-atlantic-testnet": return "PHAROS_ATLANTIC_TESTNET" + case "morph-mainnet": + return "MORPH_MAINNET" + case "ethereum-testnet-hoodi-morph": + return "MORPH_HOODI_TESTNET" + case "jovay-mainnet": + return "JOVAY_MAINNET" + case "jovay-testnet": + return "JOVAY_TESTNET" + case "stable-mainnet": + return "STABLE_MAINNET" + case "tempo-testnet": + return "TEMPO_TESTNET" + case "arc-testnet": + return "ARC_NETWORK_TESTNET" + case "doge-os-chikyu-testnet": + case "dogeos-testnet-chikyu": + return "DOGE_OS_CHIKYU_TESTNET" default: throw Error(`Chain not found ${chainInRdd}`) } @@ -595,6 +620,8 @@ export const supportedChainToChainInRdd = (supportedChain: SupportedChain): stri return "ethereum-testnet-sepolia-soneium-1" case "ETHEREUM_HOLESKY": return "ethereum-testnet-holesky" + case "ETHEREUM_HOODI": + return "ethereum-testnet-hoodi" case "ASTAR_MAINNET": return "polkadot-mainnet-astar" case "ASTAR_SHIBUYA": @@ -621,7 +648,9 @@ export const supportedChainToChainInRdd = (supportedChain: SupportedChain): stri return "shibarium-testnet-puppynet" case "SONIC_MAINNET": return "sonic-mainnet" - case "SONIC_BLAZE": + case "SONIC_TESTNET": + return "sonic-testnet" + case "SONIC_TESTNET_BLAZE": return "sonic-testnet-blaze" case "BOB_MAINNET": return "bitcoin-mainnet-bob-1" @@ -717,6 +746,8 @@ export const supportedChainToChainInRdd = (supportedChain: SupportedChain): stri return "0g-mainnet" case "MEGAETH_TESTNET": return "megaeth-testnet" + case "MEGAETH_MAINNET": + return "megaeth-mainnet" case "MIND_NETWORK_TESTNET": return "mind-testnet" case "MIND_NETWORK_MAINNET": @@ -827,6 +858,22 @@ export const supportedChainToChainInRdd = (supportedChain: SupportedChain): stri return "nexon-mainnet-henesys" case "PHAROS_ATLANTIC_TESTNET": return "pharos-atlantic-testnet" + case "MORPH_MAINNET": + return "morph-mainnet" + case "MORPH_HOODI_TESTNET": + return "ethereum-testnet-hoodi-morph" + case "JOVAY_MAINNET": + return "jovay-mainnet" + case "JOVAY_TESTNET": + return "jovay-testnet" + case "STABLE_MAINNET": + return "stable-mainnet" + case "TEMPO_TESTNET": + return "tempo-testnet" + case "ARC_NETWORK_TESTNET": + return "arc-testnet" + case "DOGE_OS_CHIKYU_TESTNET": + return "dogeos-testnet-chikyu" default: throw Error(`Chain not found ${supportedChain}`) } diff --git a/src/features/utils/networkIcons.ts b/src/features/utils/networkIcons.ts index a16711288ad..2ab3ec73b4b 100644 --- a/src/features/utils/networkIcons.ts +++ b/src/features/utils/networkIcons.ts @@ -39,5 +39,5 @@ export const normalizeTechnologyName = (technology: string): string => { } // Default: convert to lowercase and replace underscores with hyphens - return technology.toLowerCase().replace(/_/g, "-") + return technology.toLowerCase().replace(/[_ ]/g, "-") } diff --git a/src/features/vrf/v2/components/CostTable.tsx b/src/features/vrf/v2/components/CostTable.tsx index 44debc53d9d..72ffd702f08 100644 --- a/src/features/vrf/v2/components/CostTable.tsx +++ b/src/features/vrf/v2/components/CostTable.tsx @@ -4,7 +4,7 @@ import "./costTable.css" import { useCallback, useEffect, useReducer } from "preact/hooks" import { parseUnits, formatUnits, parseEther } from "ethers" import button from "@chainlink/design-system/button.module.css" -import { commify } from "~/utils/index.js" +import { commify } from "~/utils/number.ts" interface Props { method: "vrfSubscription" | "vrfDirectFunding" diff --git a/src/hooks/useLaneTokens.ts b/src/hooks/useLaneTokens.ts new file mode 100644 index 00000000000..12fcdc3e808 --- /dev/null +++ b/src/hooks/useLaneTokens.ts @@ -0,0 +1,64 @@ +import { useMemo } from "react" +import { Environment, LaneFilter, Version } from "~/config/data/ccip/types.ts" +import { getTokenData } from "~/config/data/ccip/data.ts" +import { getTokenIconUrl } from "~/features/utils/index.ts" +import { realtimeDataService } from "~/lib/ccip/services/realtime-data-instance.ts" + +export interface ProcessedToken { + id: string + data: ReturnType<typeof getTokenData> + logo: string + rateLimits: { + standard: { capacity: string; rate: string; isEnabled: boolean } | null + ftf: { capacity: string; rate: string; isEnabled: boolean } | null + } + isPaused: boolean +} + +interface UseLaneTokensParams { + tokens: string[] | undefined + environment: Environment + rateLimitsData: Record<string, any> + inOutbound: LaneFilter + searchQuery: string +} + +export function useLaneTokens({ tokens, environment, rateLimitsData, inOutbound, searchQuery }: UseLaneTokensParams) { + const processedTokens = useMemo(() => { + if (!tokens) return [] + + const direction = inOutbound === LaneFilter.Outbound ? "out" : "in" + + return tokens + .filter((token) => token.toLowerCase().includes(searchQuery.toLowerCase())) + .map((token) => { + const data = getTokenData({ + environment, + version: Version.V1_2_0, + tokenId: token || "", + }) + + // Skip tokens with no data + if (!Object.keys(data).length) return null + + const logo = getTokenIconUrl(token) + const tokenRateLimits = rateLimitsData[token] + const allLimits = realtimeDataService.getAllRateLimitsForDirection(tokenRateLimits, direction) + const isPaused = allLimits.standard?.capacity === "0" + + return { + id: token, + data, + logo, + rateLimits: allLimits, + isPaused, + } + }) + .filter((token): token is ProcessedToken => token !== null) + }, [tokens, environment, rateLimitsData, inOutbound, searchQuery]) + + return { + tokens: processedTokens, + count: tokens?.length ?? 0, + } +} diff --git a/src/hooks/useMultiLaneRateLimits.ts b/src/hooks/useMultiLaneRateLimits.ts new file mode 100644 index 00000000000..2f0274e810f --- /dev/null +++ b/src/hooks/useMultiLaneRateLimits.ts @@ -0,0 +1,78 @@ +import { useState, useEffect } from "react" +import type { TokenRateLimits, Environment } from "~/lib/ccip/types/index.ts" +import { realtimeDataService } from "~/lib/ccip/services/realtime-data-instance.ts" + +interface LaneConfig { + source: string + destination: string +} + +interface UseMultiLaneRateLimitsResult { + rateLimitsMap: Record<string, Record<string, TokenRateLimits>> + isLoading: boolean + error: Error | null +} + +/** + * Custom hook to fetch rate limits for multiple lanes + * Useful for components that need to display rate limits across multiple lanes + * @param lanes - Array of lane configurations with source and destination + * @param environment - Network environment (mainnet/testnet) + * @returns Map of rate limits keyed by lane (source-destination), loading state, and error state + */ +export function useMultiLaneRateLimits(lanes: LaneConfig[], environment: Environment): UseMultiLaneRateLimitsResult { + const [rateLimitsMap, setRateLimitsMap] = useState<Record<string, Record<string, TokenRateLimits>>>({}) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState<Error | null>(null) + + useEffect(() => { + let isMounted = true + + const fetchAllRateLimits = async () => { + setIsLoading(true) + setError(null) + + try { + const newRateLimits: Record<string, Record<string, TokenRateLimits>> = {} + + // Fetch all lanes in parallel + const promises = lanes.map(async ({ source, destination }) => { + const laneKey = `${source}-${destination}` + const response = await realtimeDataService.getLaneSupportedTokens(source, destination, environment) + + if (response?.data) { + newRateLimits[laneKey] = response.data + } + }) + + await Promise.all(promises) + + if (isMounted) { + setRateLimitsMap(newRateLimits) + } + } catch (err) { + if (isMounted) { + console.error("Error fetching multi-lane rate limits:", err) + setError(err instanceof Error ? err : new Error("Failed to fetch rate limits")) + setRateLimitsMap({}) + } + } finally { + if (isMounted) { + setIsLoading(false) + } + } + } + + if (lanes.length > 0) { + fetchAllRateLimits() + } else { + setIsLoading(false) + } + + return () => { + isMounted = false + } + }, [lanes, environment]) + + return { rateLimitsMap, isLoading, error } +} diff --git a/src/hooks/useQueryString.ts b/src/hooks/useQueryString.ts index 9cdabeb9c7d..115229cbdd7 100644 --- a/src/hooks/useQueryString.ts +++ b/src/hooks/useQueryString.ts @@ -15,12 +15,13 @@ export const setQueryStringValue = (searchParamKey: string, value: SearchParamVa } // Preserve the hash fragment if it exists const hashFragment = window.location.hash + const queryString = currentSearchParams.toString() const newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + - `?${currentSearchParams.toString()}` + + (queryString ? `?${queryString}` : "") + hashFragment window.history.replaceState({ path: newurl }, "", newurl) diff --git a/src/hooks/useTokenFinality.ts b/src/hooks/useTokenFinality.ts new file mode 100644 index 00000000000..5036a3848f0 --- /dev/null +++ b/src/hooks/useTokenFinality.ts @@ -0,0 +1,66 @@ +import { useState, useEffect } from "react" +import type { TokenFinalityData, Environment, OutputKeyType } from "~/lib/ccip/types/index.ts" +import { realtimeDataService } from "~/lib/ccip/services/realtime-data-instance.ts" + +interface UseTokenFinalityResult { + finalityData: Record<string, TokenFinalityData> + isLoading: boolean + error: Error | null +} + +/** + * Custom hook to fetch token finality data across all chains + * @param tokenCanonicalSymbol - Token canonical symbol (e.g., "BETS", "LINK") + * @param environment - Network environment (mainnet/testnet) + * @param outputKey - Format to use for displaying chain keys (optional) + * @returns Finality data for all chains, loading state, and error state + */ +export function useTokenFinality( + tokenCanonicalSymbol: string, + environment: Environment, + outputKey?: OutputKeyType +): UseTokenFinalityResult { + const [finalityData, setFinalityData] = useState<Record<string, TokenFinalityData>>({}) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState<Error | null>(null) + + useEffect(() => { + let isMounted = true + + const fetchFinalityData = async () => { + setIsLoading(true) + setError(null) + + try { + const result = await realtimeDataService.getTokenFinality(tokenCanonicalSymbol, environment, outputKey) + + if (isMounted) { + if (result?.data) { + setFinalityData(result.data) + } else { + console.warn("[useTokenFinality] No data received") + setFinalityData({}) + } + } + } catch (err) { + if (isMounted) { + console.error("Failed to fetch token finality data:", err) + setError(err instanceof Error ? err : new Error("Failed to fetch token finality")) + setFinalityData({}) + } + } finally { + if (isMounted) { + setIsLoading(false) + } + } + } + + fetchFinalityData() + + return () => { + isMounted = false + } + }, [tokenCanonicalSymbol, environment, outputKey]) + + return { finalityData, isLoading, error } +} diff --git a/src/hooks/useTokenRateLimits.ts b/src/hooks/useTokenRateLimits.ts new file mode 100644 index 00000000000..cbfd8ce04df --- /dev/null +++ b/src/hooks/useTokenRateLimits.ts @@ -0,0 +1,65 @@ +import { useState, useEffect } from "react" +import type { TokenRateLimits, Environment } from "~/lib/ccip/types/index.ts" +import { realtimeDataService } from "~/lib/ccip/services/realtime-data-instance.ts" + +interface UseTokenRateLimitsResult { + rateLimits: Record<string, TokenRateLimits> + isLoading: boolean + error: Error | null +} + +/** + * Custom hook to fetch token rate limits for a specific lane + * @param source - Source chain internal ID + * @param destination - Destination chain internal ID + * @param environment - Network environment (mainnet/testnet) + * @returns Rate limits data, loading state, and error state + */ +export function useTokenRateLimits( + source: string, + destination: string, + environment: Environment +): UseTokenRateLimitsResult { + const [rateLimits, setRateLimits] = useState<Record<string, TokenRateLimits>>({}) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState<Error | null>(null) + + useEffect(() => { + let isMounted = true + + const fetchRateLimits = async () => { + setIsLoading(true) + setError(null) + + try { + const response = await realtimeDataService.getLaneSupportedTokens(source, destination, environment) + + if (isMounted) { + if (response?.data) { + setRateLimits(response.data) + } else { + setRateLimits({}) + } + } + } catch (err) { + if (isMounted) { + console.error("Error fetching rate limits:", err) + setError(err instanceof Error ? err : new Error("Failed to fetch rate limits")) + setRateLimits({}) + } + } finally { + if (isMounted) { + setIsLoading(false) + } + } + } + + fetchRateLimits() + + return () => { + isMounted = false + } + }, [source, destination, environment]) + + return { rateLimits, isLoading, error } +} diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index 73f06501528..2a8ae9cfa79 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -6,6 +6,8 @@ import Header from "~/components/Header/Header.astro" import { NewsletterCTA } from "~/components/Footer/NewsletterCTA" import Footer from "~/components/Footer/Footer.astro" import { Metadata, QuickstartsFrontmatter } from "~/content.config.ts" +import "@chainlink/blocks/src/theme/globals.css" + // interface Props { diff --git a/src/layouts/DocsLayout.astro b/src/layouts/DocsLayout.astro index 3693d42a46a..b877a0763c9 100644 --- a/src/layouts/DocsLayout.astro +++ b/src/layouts/DocsLayout.astro @@ -8,9 +8,9 @@ import WhatsNext from "~/components/PageContent/WhatsNext.astro" import type { MarkdownHeading } from "astro" import StickyHeader from "~/components/StickyHeader/StickyHeader" import BaseLayout from "./BaseLayout.astro" -import DocsNavigation from "~/components/DocsNavigation" import { VersionSelector } from "~/components/VersionSelector/index.js" import { detectApiReference } from "@components/VersionSelector/utils/versions" +import CardsWrapper from "~/components/Cards/CardsWrapper.astro" import { LanguageSwitcherDropdown } from "~/components/LanguageSwitcherDropdown" import { ChainTypeSelector } from "~/components/ChainSelector" import { isChainAwareSection } from "~/config/chainTypes" @@ -67,7 +67,6 @@ const howToSteps = initialHeadings > <slot name="head-scripts" slot="head-scripts" /> <StickyHeader client:media="(max-width: 50em)" {initialHeadings} /> - <DocsNavigation client:load pathname={currentPage} /> <main> <div id="left-bg"></div> <div class="layout"> @@ -96,12 +95,7 @@ const howToSteps = initialHeadings {whatsNext && <WhatsNext content={whatsNext} />} </div> <aside id="grid-right"> - <RightSidebar - {githubEditUrl} - headings={initialHeadings} - showLanguageSwitcher={frontmatter.section === "cre"} - frontmatter={frontmatter} - /> + <RightSidebar {githubEditUrl} headings={initialHeadings} frontmatter={frontmatter} /> </aside> </div> </main> @@ -145,11 +139,6 @@ const howToSteps = initialHeadings max-width: 1505px; } - #grid-left, - #left-bg { - background: #fafbfd; - } - #grid-left, #grid-right { display: flex; diff --git a/src/layouts/DocsV3Layout/DocsV3Layout.astro b/src/layouts/DocsV3Layout/DocsV3Layout.astro new file mode 100644 index 00000000000..05aa3478a5e --- /dev/null +++ b/src/layouts/DocsV3Layout/DocsV3Layout.astro @@ -0,0 +1,149 @@ +--- +import StickyHeader from "~/components/StickyHeader/StickyHeader" +import BaseLayout from "../BaseLayout.astro" +import { MarkdownHeading } from "astro" +import { BaseFrontmatter } from "~/content.config" +import * as CONFIG from "~/config" +import LeftSidebar from "~/components/LeftSidebar/LeftSidebar.astro" +import PageContent from "~/components/PageContent/PageContent.astro" + +interface Props { + frontmatter: BaseFrontmatter + headings?: MarkdownHeading[] +} +const { frontmatter, headings } = Astro.props + +const titleHeading: MarkdownHeading = { + text: frontmatter.title, + slug: "overview", + depth: 1, +} + +const filteredHeadings = headings?.filter((h) => h.depth < 5) +const initialHeadings = [titleHeading].concat(filteredHeadings ?? []) + +const formattedContentTitle = `${frontmatter.title} | ${CONFIG.SITE.title}` + +const currentPage = new URL(Astro.request.url).pathname + +const includeLinkToWalletScript = !!Astro.props.frontmatter.metadata?.linkToWallet +--- + +<BaseLayout title={formattedContentTitle} metadata={frontmatter.metadata} pageTitle={frontmatter.title}> + <StickyHeader client:media="(max-width: 50em)" {initialHeadings} /> + + <main> + <div id="left-bg"></div> + <div class="layout"> + <aside id="grid-left"> + <LeftSidebar currentPage={currentPage} section={frontmatter.section} /> + </aside> + <div id="grid-main"> + <PageContent + {titleHeading} + disableDefaultStyles={frontmatter.disableDefaultStyles} + hideTitle={frontmatter.hideTitle} + > + <slot /> + </PageContent> + </div> + </div> + </main> + + <style> + main { + margin-bottom: 0 !important; + } + + .layout { + display: grid; + grid-template-columns: auto; + --gutter: var(--space-6x); + --doc-padding: var(--space-6x); + margin-bottom: 0; + } + + #grid-left, + #grid-right { + display: none; + } + + #grid-main { + padding: var(--doc-padding) var(--gutter); + display: flex; + flex-direction: column; + margin-bottom: var(--space-10x); + min-width: 0; + } + + @media screen and (max-width: 768px) { + #grid-main { + padding: 0 var(--space-12x) var(--doc-padding) var(--space-12x); + } + } + + @media (min-width: 50em) { + main { + display: grid; + grid-template-columns: auto fit-content(100%) auto; + } + + .layout { + grid-template-columns: auto 1fr auto; + gap: var(--gutter); + width: 100vw; + max-width: 1505px; + } + + #grid-left, + #grid-right { + display: flex; + } + + #grid-main { + padding: 0 0 var(--doc-padding) 0; + } + + #grid-left { + width: 260px; + padding-left: var(--space-6x); + } + + #grid-right { + width: 0; + padding-right: 0; + transition: 300ms ease-in-out; + transition-property: width padding-right; + } + } + + @media (min-width: 992px) { + .layout { + gap: var(--doc-padding); + } + + #grid-left { + width: 350px; + padding-left: var(--space-6x); + } + } + + @media (min-width: 1200px) { + #grid-right { + width: 315px; + padding-right: var(--space-16x); + } + } + </style> + + <script define:vars={{ includeLinkToWalletScript }}> + window["includeLinkToWalletScript"] = includeLinkToWalletScript + </script> + + <script> + import "~/scripts" + if (window["includeLinkToWalletScript"]) { + import("~/scripts/link-to-wallet.ts") + } + </script> +</BaseLayout> diff --git a/src/layouts/DocsV3Layout/README.md b/src/layouts/DocsV3Layout/README.md new file mode 100644 index 00000000000..6d316fbf9ef --- /dev/null +++ b/src/layouts/DocsV3Layout/README.md @@ -0,0 +1,110 @@ +# DocsV3Layout Component Guide + +## What is DocsV3Layout? + +DocsV3Layout is the template that creates the standard layout for documentation pages on the Chainlink Docs website. Think of it as a "frame" that wraps around your content to give it a consistent look and feel. + +## What Does It Do? + +When you use this layout, it automatically creates: + +- **A left sidebar** with navigation links to help users find related pages +- **A main content area** where your documentation content appears +- **A header** that shows the page outline (on mobile devices) +- **Responsive design** that adapts to different screen sizes (mobile, tablet, desktop) + +## How to Use It + +### Basic Setup + +To use this layout for a documentation page, you need to specify it at the top of your Markdown file: + +``` +--- +layout: ~/layouts/DocsV3Layout/DocsV3Layout.astro +title: Your Page Title +section: your-section-name +--- + +Your content goes here... +``` + +### Required Information + +You need to provide two key pieces of information: + +1. **Title** - The name of your documentation page + - Example: `title: Getting Started with Chainlink` + +2. **Section** - Which documentation section this page belongs to + - Example: `section: quickstarts` + - This helps organize pages in the left sidebar navigation + +### Optional Information + +You can also include: + +- **Metadata** - Special settings for the page, like SEO information +- **Link to Wallet** - If your page needs blockchain wallet integration, add: + ``` + metadata: + linkToWallet: true + ``` + +## Example Usage + +Here's a complete example of how to set up a documentation page: + +``` +--- +layout: ~/layouts/DocsV3Layout/DocsV3Layout.astro +title: How to Use Chainlink Data Feeds +section: data-feeds +--- + +# How to Use Chainlink Data Feeds + +This guide will teach you how to use data feeds... + +## Step 1: Prerequisites + +Before you begin, make sure you have... + +## Step 2: Installation + +To install the required packages... +``` + +## What Happens Behind the Scenes + +When you use this layout: + +1. **Your title** becomes the main heading and appears in the page outline +2. **Your headings** (anything starting with `#`, `##`, `###`) are automatically collected and used for navigation +3. **The sidebar** is populated with links based on your section +4. **The layout adapts** to the user's screen size automatically + +## Layout Structure + +The page is divided into three columns: + +``` +┌──────────────┬─────────────────────┬──────────────┐ +│ │ │ │ +│ Left │ Main Content │ Right │ +│ Sidebar │ (Your Docs) │ Sidebar │ +│ (Navigation) │ │ (Future) │ +│ │ │ │ +└──────────────┴─────────────────────┴──────────────┘ +``` + +- **Left Sidebar**: Shows navigation for the current section +- **Main Content**: Your documentation content +- **Right Sidebar**: Reserved for future use (currently empty) + +## Tips for Best Results + +1. **Use clear headings** - Your headings create the page outline, so make them descriptive +2. **Keep titles concise** - The title appears in multiple places, so shorter is better +3. **Choose the right section** - Make sure your page is in the correct section so users can find it +4. **Limit heading depth** - Only headings up to level 4 (`####`) are included in the navigation diff --git a/src/layouts/TutorialLayout.astro b/src/layouts/TutorialLayout.astro index 6c572bb9647..c968d9cf957 100644 --- a/src/layouts/TutorialLayout.astro +++ b/src/layouts/TutorialLayout.astro @@ -7,7 +7,6 @@ import WhatsNext from "~/components/PageContent/WhatsNext.astro" import type { MarkdownHeading } from "astro" import StickyHeader from "~/components/StickyHeader/StickyHeader" import BaseLayout from "./BaseLayout.astro" -import DocsNavigation from "~/components/DocsNavigation" import { TutorialProgress } from "~/components/CCIP/TutorialProgress/TutorialProgress" interface Props { @@ -32,7 +31,6 @@ const formattedContentTitle = `${frontmatter.title} | ${SITE.title}` <BaseLayout title={formattedContentTitle} metadata={frontmatter.metadata}> <StickyHeader client:media="(max-width: 50em)" {initialHeadings} /> - <DocsNavigation client:load pathname={currentPage} /> <main> <div id="left-bg"></div> <div class="layout"> diff --git a/src/lib/api/cacheHeaders.ts b/src/lib/api/cacheHeaders.ts new file mode 100644 index 00000000000..92312d1448a --- /dev/null +++ b/src/lib/api/cacheHeaders.ts @@ -0,0 +1,47 @@ +/** + * Shared cache header configurations for API endpoints + * + * Cache Strategy: + * - 5-minute CDN cache (s-max-age=300) + * - Stale-while-revalidate for graceful degradation + * - CDN-specific headers for Vercel optimization + * - No browser cache (CDN-only caching) + */ + +/** + * Standard cache headers for all API endpoints + * - CDN cache: 5 minutes + * - Serves stale content while revalidating in background + * - Optimized for Vercel CDN + */ +export const standardCacheHeaders = { + "Cache-Control": "s-max-age=300, stale-while-revalidate", + "CDN-Cache-Control": "max-age=300", + "Vercel-CDN-Cache-Control": "max-age=300", +} + +/** + * Cache headers for text/plain responses + * Used by: /api/page-markdown + */ +export const textPlainHeaders = { + "Content-Type": "text/plain; charset=utf-8", + ...standardCacheHeaders, +} + +/** + * Cache headers for application/json responses + * Used by: /api/ccip/v1/* endpoints + */ +export const jsonHeaders = { + "Content-Type": "application/json", + ...standardCacheHeaders, +} + +/** + * Common headers without caching directives + * For endpoints that need custom cache control + */ +export const commonHeaders = { + "Content-Type": "application/json", +} diff --git a/src/pages/api/ccip/faucet/adapters/index.ts b/src/lib/ccip/faucet/adapters/index.ts similarity index 83% rename from src/pages/api/ccip/faucet/adapters/index.ts rename to src/lib/ccip/faucet/adapters/index.ts index 1a27125ced8..ae1962dad49 100644 --- a/src/pages/api/ccip/faucet/adapters/index.ts +++ b/src/lib/ccip/faucet/adapters/index.ts @@ -1,5 +1,5 @@ import { ChainFamily } from "@config/types.ts" -import { FamilyAdapter } from "@api/ccip/types/faucet.ts" +import { FamilyAdapter } from "~/lib/ccip/types/faucet.ts" import { SvmAdapter } from "./svm.ts" export const prerender = false @@ -20,6 +20,6 @@ export class FaucetAdapterFactory { } // Re-export types and adapters -export type { FamilyAdapter } from "@api/ccip/types/faucet.ts" +export type { FamilyAdapter } from "~/lib/ccip/types/faucet.ts" export { SvmAdapter } from "./svm.ts" export { SvmDripAdapter } from "./svm-drip.ts" diff --git a/src/pages/api/ccip/faucet/adapters/svm-drip.ts b/src/lib/ccip/faucet/adapters/svm-drip.ts similarity index 94% rename from src/pages/api/ccip/faucet/adapters/svm-drip.ts rename to src/lib/ccip/faucet/adapters/svm-drip.ts index 4fc62dba32a..190bd4f6c83 100644 --- a/src/pages/api/ccip/faucet/adapters/svm-drip.ts +++ b/src/lib/ccip/faucet/adapters/svm-drip.ts @@ -2,9 +2,9 @@ import { randomUUID } from "node:crypto" import { createSolanaLogger } from "@lib/logging/index.js" import type { Logger } from "@lib/logging/index.js" import { ensureSolAddress } from "@lib/solana/index.js" -import { ChainConfigurationService } from "@api/ccip/services/chain-config.ts" -import { DripOrchestrator, type DripParams, type DripResult } from "@api/ccip/services/faucet/drip-orchestrator.ts" -import type { FaucetChainConfig } from "@api/ccip/types/faucet.ts" +import { ChainConfigurationService } from "~/lib/ccip/services-api/chain-config.ts" +import { DripOrchestrator, type DripParams, type DripResult } from "~/lib/ccip/services-api/faucet/drip-orchestrator.ts" +import type { FaucetChainConfig } from "~/lib/ccip/types/faucet.ts" export const prerender = false diff --git a/src/pages/api/ccip/faucet/adapters/svm.ts b/src/lib/ccip/faucet/adapters/svm.ts similarity index 99% rename from src/pages/api/ccip/faucet/adapters/svm.ts rename to src/lib/ccip/faucet/adapters/svm.ts index cf156985bf9..4b0fecd4848 100644 --- a/src/pages/api/ccip/faucet/adapters/svm.ts +++ b/src/lib/ccip/faucet/adapters/svm.ts @@ -1,4 +1,4 @@ -import { FamilyAdapter, VerifySignatureArgs, FaucetChainConfig } from "@api/ccip/types/faucet.ts" +import { FamilyAdapter, VerifySignatureArgs, FaucetChainConfig } from "~/lib/ccip/types/faucet.ts" import { ensureSolAddress } from "@lib/solana/core/address/validator.ts" import { SolanaSignatureService } from "@lib/solana/domain/services/signature-verification.ts" import { logger } from "@lib/logging/index.js" diff --git a/src/pages/api/ccip/faucet/chain-resolver.ts b/src/lib/ccip/faucet/chain-resolver.ts similarity index 96% rename from src/pages/api/ccip/faucet/chain-resolver.ts rename to src/lib/ccip/faucet/chain-resolver.ts index 88a6f81c189..a8d5d0f7798 100644 --- a/src/pages/api/ccip/faucet/chain-resolver.ts +++ b/src/lib/ccip/faucet/chain-resolver.ts @@ -1,7 +1,7 @@ import { getSelectorEntry } from "@config/data/ccip/selectors.ts" -import { resolveChainOrThrow } from "@api/ccip/utils.ts" +import { resolveChainOrThrow } from "~/lib/ccip/utils.ts" import { getChainTypeAndFamily, getChainId, directoryToSupportedChain } from "@features/utils/index.ts" -import { FaucetChainConfig } from "@api/ccip/types/faucet.ts" +import { FaucetChainConfig } from "~/lib/ccip/types/faucet.ts" import { getFaucetAddress, getSolanaDevnetConfig } from "@lib/core/config/index.ts" import { BNM_MINT_ADDRESSES } from "@lib/solana/core/constants/token-resolver.ts" diff --git a/src/pages/api/ccip/faucet/codec/index.ts b/src/lib/ccip/faucet/codec/index.ts similarity index 100% rename from src/pages/api/ccip/faucet/codec/index.ts rename to src/lib/ccip/faucet/codec/index.ts diff --git a/src/pages/api/ccip/faucet/config.ts b/src/lib/ccip/faucet/config.ts similarity index 100% rename from src/pages/api/ccip/faucet/config.ts rename to src/lib/ccip/faucet/config.ts diff --git a/src/pages/api/ccip/services/chain-config.ts b/src/lib/ccip/services-api/chain-config.ts similarity index 97% rename from src/pages/api/ccip/services/chain-config.ts rename to src/lib/ccip/services-api/chain-config.ts index 0123472a0ce..3c67528964d 100644 --- a/src/pages/api/ccip/services/chain-config.ts +++ b/src/lib/ccip/services-api/chain-config.ts @@ -7,7 +7,7 @@ import { getSolanaDevnetConfig } from "@lib/core/config/index.ts" import { createRpcContext } from "@lib/solana/infrastructure/rpc/solana-rpc.ts" import type { IRpcContext } from "@lib/solana/infrastructure/rpc/types.ts" -import type { FaucetChainConfig } from "@api/ccip/types/faucet.ts" +import type { FaucetChainConfig } from "~/lib/ccip/types/faucet.ts" export const prerender = false diff --git a/src/pages/api/ccip/services/faucet/drip-orchestrator.ts b/src/lib/ccip/services-api/faucet/drip-orchestrator.ts similarity index 99% rename from src/pages/api/ccip/services/faucet/drip-orchestrator.ts rename to src/lib/ccip/services-api/faucet/drip-orchestrator.ts index 95cd2c97af9..6eb6aa3ecb0 100644 --- a/src/pages/api/ccip/services/faucet/drip-orchestrator.ts +++ b/src/lib/ccip/services-api/faucet/drip-orchestrator.ts @@ -16,7 +16,7 @@ import { TransactionManager } from "@lib/solana/domain/transaction/services/mana import { detectTokenProgram, getBackendSigner } from "@lib/solana/core/services/index.ts" import { NetworkComputeBudgetService, TransactionComplexity } from "@lib/solana/core/services/network-compute-budget.ts" import type { IRpcContext } from "@lib/solana/infrastructure/rpc/types.ts" -import type { FaucetChainConfig } from "@api/ccip/types/faucet.ts" +import type { FaucetChainConfig } from "~/lib/ccip/types/faucet.ts" import type { Address } from "@solana/kit" import { directoryToSupportedChain } from "@features/utils/index.ts" diff --git a/src/pages/api/ccip/services/faucet/error-handler.ts b/src/lib/ccip/services-api/faucet/error-handler.ts similarity index 99% rename from src/pages/api/ccip/services/faucet/error-handler.ts rename to src/lib/ccip/services-api/faucet/error-handler.ts index e79b173580f..a34b6e00c1c 100644 --- a/src/pages/api/ccip/services/faucet/error-handler.ts +++ b/src/lib/ccip/services-api/faucet/error-handler.ts @@ -4,7 +4,7 @@ * to appropriate HTTP status codes following RESTful principles */ -import { APIErrorType, createErrorResponse } from "@api/ccip/utils.ts" +import { APIErrorType, createErrorResponse } from "~/lib/ccip/utils.ts" import { FaucetStateService } from "@lib/solana/domain/services/faucet-state.ts" import { address } from "@lib/solana/index.js" import { logger } from "@lib/logging/index.js" diff --git a/src/pages/api/services/chain-data.ts b/src/lib/ccip/services/chain-data.ts similarity index 99% rename from src/pages/api/services/chain-data.ts rename to src/lib/ccip/services/chain-data.ts index 4e0b6a6fd22..c268c3ea39b 100644 --- a/src/pages/api/services/chain-data.ts +++ b/src/lib/ccip/services/chain-data.ts @@ -1,7 +1,7 @@ -import { Environment, ChainDetails, FilterType, ChainConfigError, FeeTokenEnriched } from "../ccip/types/index.ts" +import { Environment, ChainDetails, FilterType, ChainConfigError, FeeTokenEnriched } from "~/lib/ccip/types/index.ts" import { ChainsConfig } from "@config/data/ccip/index.ts" import { getSelectorEntry } from "@config/data/ccip/selectors.ts" -import { resolveChainOrThrow } from "@api/ccip/utils.ts" +import { resolveChainOrThrow } from "~/lib/ccip/utils.ts" import { logger } from "@lib/logging/index.js" import { getChainId, getNativeCurrency, getTitle, getChainTypeAndFamily } from "../../../features/utils/index.ts" import { SupportedChain, ChainType, ChainFamily } from "~/config/index.ts" diff --git a/src/pages/api/services/faucet-service.ts b/src/lib/ccip/services/faucet-service.ts similarity index 96% rename from src/pages/api/services/faucet-service.ts rename to src/lib/ccip/services/faucet-service.ts index 676a407008d..ef0ddab181d 100644 --- a/src/pages/api/services/faucet-service.ts +++ b/src/lib/ccip/services/faucet-service.ts @@ -1,7 +1,7 @@ import { logger } from "@lib/logging/index.js" -import { resolveFaucetChain } from "@api/ccip/faucet/chain-resolver.ts" -import { FaucetAdapterFactory } from "@api/ccip/faucet/adapters/index.ts" -import { ChallengeParams, ChallengeResponse, VerifyRequest, VerifyResponse } from "@api/ccip/types/faucet.ts" +import { resolveFaucetChain } from "~/lib/ccip/faucet/chain-resolver.ts" +import { FaucetAdapterFactory } from "~/lib/ccip/faucet/adapters/index.ts" +import { ChallengeParams, ChallengeResponse, VerifyRequest, VerifyResponse } from "~/lib/ccip/types/faucet.ts" export const prerender = false diff --git a/src/lib/ccip/services/lane-data.ts b/src/lib/ccip/services/lane-data.ts new file mode 100644 index 00000000000..fa3211c3646 --- /dev/null +++ b/src/lib/ccip/services/lane-data.ts @@ -0,0 +1,771 @@ +import { + Environment, + LaneDetails, + LaneFilterType, + LaneConfigError, + LaneServiceResponse, + LaneDetailServiceResponse, + LaneDetailWithRateLimits, + SupportedTokensServiceResponse, + ChainInfo, + ChainInfoInternal, + OutputKeyType, + ChainType, + ChainFamily, + LaneInputKeyType, + TokenRateLimits, + RateLimitsData, +} from "~/lib/ccip/types/index.ts" +import { loadReferenceData, Version } from "@config/data/ccip/index.ts" +import type { LaneConfig, ChainConfig } from "@config/data/ccip/types.ts" +import { generateChainKey, normalizeVersion } from "~/lib/ccip/utils.ts" +import { logger } from "@lib/logging/index.js" +import { + getChainId, + getTitle, + getChainTypeAndFamily, + directoryToSupportedChain, +} from "../../../features/utils/index.ts" + +// Import rate limits mock data +import rateLimitsMainnet from "~/__mocks__/rate-limits-mainnet.json" with { type: "json" } +import rateLimitsTestnet from "~/__mocks__/rate-limits-testnet.json" with { type: "json" } + +export const prerender = false + +/** + * Service class for handling CCIP lane data operations + * Provides functionality to validate and filter lane configurations + */ +export class LaneDataService { + private errors: LaneConfigError[] = [] + private readonly requestId: string + private skippedLanesCount = 0 + + /** + * Creates a new instance of LaneDataService + */ + constructor() { + this.requestId = crypto.randomUUID() + + logger.debug({ + message: "LaneDataService initialized", + requestId: this.requestId, + }) + } + + /** + * Retrieves and filters lane data based on environment and filters + * + * @param environment - Network environment (mainnet/testnet) + * @param filters - Filter parameters for lanes + * @param outputKey - Format to use for displaying lane keys + * @returns Filtered lane data with metadata + */ + async getFilteredLanes( + environment: Environment, + filters: LaneFilterType, + outputKey: OutputKeyType + ): Promise<LaneServiceResponse> { + logger.debug({ + message: "Processing lane data", + requestId: this.requestId, + environment, + filters, + outputKey, + }) + + try { + // Load reference data + const { lanesReferenceData, chainsReferenceData } = loadReferenceData({ + environment, + version: Version.V1_2_0, + }) + + const result: Record<string, LaneDetails> = {} + this.errors = [] + this.skippedLanesCount = 0 + + // Process all lanes + for (const [sourceChainKey, destinations] of Object.entries(lanesReferenceData)) { + for (const [destChainKey, laneConfig] of Object.entries(destinations)) { + try { + // Get chain information + const sourceChain = this.resolveChainInfo(sourceChainKey, chainsReferenceData) + const destChain = this.resolveChainInfo(destChainKey, chainsReferenceData) + + if (!sourceChain || !destChain) { + this.addError(sourceChainKey, destChainKey, "Failed to resolve chain information", [ + "sourceChain", + "destinationChain", + ]) + continue + } + + // Apply filters + if (!this.passesFilters(sourceChain, destChain, filters)) { + this.skippedLanesCount++ + continue + } + + // Generate lane key + const laneKey = this.generateLaneKey(sourceChain, destChain, outputKey) + + // Build lane details + const laneDetails = this.buildLaneDetails(sourceChain, destChain, laneConfig) + + // Check for version mismatch + if (laneDetails.onRamp.version !== laneDetails.offRamp.version) { + this.addError( + sourceChainKey, + destChainKey, + `Version mismatch: onRamp v${laneDetails.onRamp.version} != offRamp v${laneDetails.offRamp.version}`, + ["version"] + ) + continue + } + + // Apply version filter if provided + if (filters.version) { + // Both onRamp and offRamp must match the specified version + if (laneDetails.onRamp.version !== filters.version || laneDetails.offRamp.version !== filters.version) { + this.skippedLanesCount++ + continue + } + } + + result[laneKey] = laneDetails + + logger.debug({ + message: "Lane processed successfully", + requestId: this.requestId, + laneKey, + sourceChain: sourceChainKey, + destinationChain: destChainKey, + }) + } catch (error) { + this.addError( + sourceChainKey, + destChainKey, + `Lane processing failed: ${error instanceof Error ? error.message : "Unknown error"}`, + ["laneConfig"] + ) + } + } + } + + const validLaneCount = Object.keys(result).length + const ignoredLaneCount = this.errors.length + + logger.info({ + message: "Lane data processing completed", + requestId: this.requestId, + validLaneCount, + ignoredLaneCount, + skippedLanesCount: this.skippedLanesCount, + }) + + return { + data: result, + errors: this.errors, + metadata: { + validLaneCount, + ignoredLaneCount, + }, + } + } catch (error) { + logger.error({ + message: "Failed to process lane data", + requestId: this.requestId, + error: error instanceof Error ? error.message : "Unknown error", + }) + + throw error + } + } + + /** + * Resolves chain information from chain key + */ + private resolveChainInfo(chainKey: string, chainsReferenceData: Record<string, unknown>): ChainInfoInternal | null { + try { + const chainConfig = chainsReferenceData[chainKey] + + if (!chainConfig) { + return null + } + + // Try to get supported chain for additional info, but don't fail if not found + let chainId: string | number = chainKey // fallback to chainKey + let displayName: string = chainKey // fallback to chainKey + let chainType: ChainType = "evm" // default to evm + let chainFamily: ChainFamily = "evm" // default to evm + + try { + const supportedChain = directoryToSupportedChain(chainKey) + const resolvedChainId = getChainId(supportedChain) + const resolvedDisplayName = getTitle(supportedChain) + const { chainType: resolvedChainType, chainFamily: resolvedChainFamily } = getChainTypeAndFamily(supportedChain) + + if (resolvedChainId) chainId = resolvedChainId + if (resolvedDisplayName) displayName = resolvedDisplayName + chainType = resolvedChainType + chainFamily = resolvedChainFamily + } catch { + // If directoryToSupportedChain fails, continue with fallback values + // This allows processing of chains not yet in the mapping + } + + // Get selector from chain configuration + const configData = chainConfig as ChainConfig + const selector = configData.chainSelector + + if (!selector) { + return null + } + + return { + chainId, + displayName, + selector, + internalId: chainKey, + chainType, + chainFamily, + } + } catch (error) { + logger.warn({ + message: "Failed to resolve chain info", + requestId: this.requestId, + chainKey, + error: error instanceof Error ? error.message : "Unknown error", + }) + return null + } + } + + /** + * Checks if a lane passes the given filters + */ + private passesFilters( + sourceChain: ChainInfoInternal, + destChain: ChainInfoInternal, + filters: LaneFilterType + ): boolean { + // Check source chain filters + if (filters.sourceChainId && !this.matchesChainFilter(sourceChain, filters.sourceChainId, "chain_id")) { + return false + } + if (filters.sourceSelector && !this.matchesChainFilter(sourceChain, filters.sourceSelector, "selector")) { + return false + } + if (filters.sourceInternalId && !this.matchesChainFilter(sourceChain, filters.sourceInternalId, "internal_id")) { + return false + } + + // Check destination chain filters + if (filters.destinationChainId && !this.matchesChainFilter(destChain, filters.destinationChainId, "chain_id")) { + return false + } + if (filters.destinationSelector && !this.matchesChainFilter(destChain, filters.destinationSelector, "selector")) { + return false + } + if ( + filters.destinationInternalId && + !this.matchesChainFilter(destChain, filters.destinationInternalId, "internal_id") + ) { + return false + } + + return true + } + + /** + * Checks if a chain matches a specific filter value + */ + private matchesChainFilter( + chain: ChainInfoInternal, + filterValue: string, + filterType: "chain_id" | "selector" | "internal_id" + ): boolean { + const filterValues = filterValue.split(",").map((v) => v.trim()) + // Map snake_case filter types to camelCase property names + const propertyMap: Record<string, keyof ChainInfoInternal> = { + chain_id: "chainId", + selector: "selector", + internal_id: "internalId", + } + const propertyName = propertyMap[filterType] + const chainValue = chain[propertyName].toString() + + // For chain_id, also check generated chain key format + if (filterType === "chain_id") { + const generatedKey = generateChainKey(chain.chainId, chain.chainType, "chain_id") + return filterValues.includes(chainValue) || filterValues.includes(generatedKey) + } + + return filterValues.includes(chainValue) + } + + /** + * Generates a lane key based on source and destination chains + */ + private generateLaneKey( + sourceChain: ChainInfoInternal, + destChain: ChainInfoInternal, + outputKey: OutputKeyType + ): string { + // Map snake_case output keys to camelCase property names + const propertyMap: Record<string, keyof ChainInfoInternal> = { + chain_id: "chainId", + selector: "selector", + internal_id: "internalId", + } + const propertyName = propertyMap[outputKey] + + const sourceKey = + outputKey === "chain_id" + ? generateChainKey(sourceChain.chainId, sourceChain.chainType, outputKey) + : sourceChain[propertyName].toString() + + const destKey = + outputKey === "chain_id" + ? generateChainKey(destChain.chainId, destChain.chainType, outputKey) + : destChain[propertyName].toString() + + return `${sourceKey}_to_${destKey}` + } + + /** + * Builds lane details from chain info and lane config + */ + private buildLaneDetails( + sourceChain: ChainInfoInternal, + destChain: ChainInfoInternal, + laneConfig: LaneConfig + ): LaneDetails { + // Convert internal chain info to public interface (remove chainType and chainFamily) + const publicSourceChain: ChainInfo = { + chainId: sourceChain.chainId, + displayName: sourceChain.displayName, + selector: sourceChain.selector, + internalId: sourceChain.internalId, + } + + const publicDestChain: ChainInfo = { + chainId: destChain.chainId, + displayName: destChain.displayName, + selector: destChain.selector, + internalId: destChain.internalId, + } + + return { + sourceChain: publicSourceChain, + destinationChain: publicDestChain, + onRamp: { + address: laneConfig.onRamp.address, + version: normalizeVersion(laneConfig.onRamp.version), + enforceOutOfOrder: laneConfig.onRamp.enforceOutOfOrder, + }, + offRamp: { + address: laneConfig.offRamp.address, + version: normalizeVersion(laneConfig.offRamp.version), + }, + supportedTokens: this.extractSupportedTokens(laneConfig), + } + } + + /** + * Extracts supported token keys from lane configuration + */ + private extractSupportedTokens(laneConfig: LaneConfig): string[] { + if (!laneConfig.supportedTokens || !Array.isArray(laneConfig.supportedTokens)) { + return [] + } + + // lanes.json structure: "supportedTokens": ["LINK", "CCIP-BnM", ...] + return laneConfig.supportedTokens + } + + /** + * Adds an error to the error collection + */ + private addError(sourceChain: string, destinationChain: string, reason: string, missingFields: string[]): void { + this.errors.push({ + sourceChain, + destinationChain, + reason, + missingFields, + }) + + logger.warn({ + message: "Lane validation error", + requestId: this.requestId, + sourceChain, + destinationChain, + reason, + missingFields, + }) + } + + /** + * Gets the request ID for this service instance + */ + getRequestId(): string { + return this.requestId + } + + /** + * Retrieves details for a specific lane by source and destination chain identifiers + * + * @param environment - Network environment (mainnet/testnet) + * @param sourceIdentifier - Source chain identifier (chainId, selector, or internalId) + * @param destinationIdentifier - Destination chain identifier + * @param inputKeyType - Type of identifier used (chainId, selector, internalId) + * @returns Lane details or null if not found + */ + async getLaneDetails( + environment: Environment, + sourceIdentifier: string, + destinationIdentifier: string, + inputKeyType: LaneInputKeyType + ): Promise<LaneDetailServiceResponse> { + logger.info({ + message: "Getting lane details", + requestId: this.requestId, + environment, + sourceIdentifier, + destinationIdentifier, + inputKeyType, + }) + + try { + // Load reference data + const { lanesReferenceData, chainsReferenceData } = loadReferenceData({ + environment, + version: Version.V1_2_0, + }) + + // Resolve identifiers to internal IDs + const sourceInternalId = this.resolveToInternalId( + sourceIdentifier, + inputKeyType, + chainsReferenceData as Record<string, ChainConfig> + ) + const destinationInternalId = this.resolveToInternalId( + destinationIdentifier, + inputKeyType, + chainsReferenceData as Record<string, ChainConfig> + ) + + if (!sourceInternalId || !destinationInternalId) { + logger.warn({ + message: "Could not resolve chain identifiers", + requestId: this.requestId, + sourceIdentifier, + destinationIdentifier, + sourceInternalId, + destinationInternalId, + }) + return { data: null } + } + + // Get lane data + const sourceLanes = lanesReferenceData[sourceInternalId] as Record<string, LaneConfig> | undefined + if (!sourceLanes) { + return { data: null } + } + + const laneConfig = sourceLanes[destinationInternalId] + if (!laneConfig) { + return { data: null } + } + + // Resolve chain info + const sourceChain = this.resolveChainInfo(sourceInternalId, chainsReferenceData) + const destChain = this.resolveChainInfo(destinationInternalId, chainsReferenceData) + + if (!sourceChain || !destChain) { + return { data: null } + } + + // Build lane details with rate limits + const laneDetails = this.buildLaneDetailsWithRateLimits( + sourceChain, + destChain, + laneConfig, + sourceInternalId, + destinationInternalId, + environment + ) + + logger.info({ + message: "Lane details with rate limits retrieved", + requestId: this.requestId, + sourceInternalId, + destinationInternalId, + tokenCount: Object.keys(laneDetails.supportedTokens).length, + }) + + return { data: laneDetails } + } catch (error) { + logger.error({ + message: "Failed to get lane details", + requestId: this.requestId, + error: error instanceof Error ? error.message : "Unknown error", + }) + return { data: null } + } + } + + /** + * Resolves a chain identifier to its internal ID + * + * @param identifier - Chain identifier (chainId, selector, or internalId) + * @param inputKeyType - Type of identifier + * @param chainsReferenceData - Chain configuration data + * @returns Internal ID or null if not found + */ + resolveToInternalId( + identifier: string, + inputKeyType: LaneInputKeyType, + chainsReferenceData: Record<string, ChainConfig> + ): string | null { + // If already an internal_id, return it directly + if (inputKeyType === "internal_id") { + return chainsReferenceData[identifier] ? identifier : null + } + + // Search through chains to find matching chain_id or selector + for (const [internalId, chainConfig] of Object.entries(chainsReferenceData)) { + if (inputKeyType === "chain_id") { + // Try to match by numeric chain ID + try { + const supportedChain = directoryToSupportedChain(internalId) + const chainId = getChainId(supportedChain) + if (chainId && chainId.toString() === identifier) { + return internalId + } + } catch { + // Skip chains that can't be resolved + } + } else if (inputKeyType === "selector") { + // Match by selector + if (chainConfig.chainSelector === identifier) { + return internalId + } + } + } + + return null + } + + /** + * Loads rate limits data for the specified environment + */ + private loadRateLimitsData(environment: Environment): RateLimitsData { + return environment === "mainnet" + ? (rateLimitsMainnet as unknown as RateLimitsData) + : (rateLimitsTestnet as unknown as RateLimitsData) + } + + /** + * Builds lane details with rate limits included in supportedTokens + */ + private buildLaneDetailsWithRateLimits( + sourceChain: ChainInfoInternal, + destChain: ChainInfoInternal, + laneConfig: LaneConfig, + sourceInternalId: string, + destinationInternalId: string, + environment: Environment + ): LaneDetailWithRateLimits { + // Convert internal chain info to public interface + const publicSourceChain: ChainInfo = { + chainId: sourceChain.chainId, + displayName: sourceChain.displayName, + selector: sourceChain.selector, + internalId: sourceChain.internalId, + } + + const publicDestChain: ChainInfo = { + chainId: destChain.chainId, + displayName: destChain.displayName, + selector: destChain.selector, + internalId: destChain.internalId, + } + + // Extract supported token symbols + const tokenSymbols = this.extractSupportedTokens(laneConfig) + + // Load rate limits data + const rateLimitsData = this.loadRateLimitsData(environment) + + // Build supportedTokens with rate limits + const supportedTokensWithRateLimits: Record<string, TokenRateLimits> = {} + + for (const tokenSymbol of tokenSymbols) { + const tokenData = rateLimitsData[tokenSymbol] + if (tokenData) { + const sourceData = tokenData[sourceInternalId] + if (sourceData?.remote) { + const destData = sourceData.remote[destinationInternalId] + if (destData) { + supportedTokensWithRateLimits[tokenSymbol] = { + standard: destData.standard, + custom: destData.custom, + } + } else { + // Token exists but no rate limits for this lane - use null for unavailable + supportedTokensWithRateLimits[tokenSymbol] = { + standard: null, + custom: null, + } + } + } else { + // Token exists but no data for source chain + supportedTokensWithRateLimits[tokenSymbol] = { + standard: null, + custom: null, + } + } + } else { + // Token not found in rate limits data + supportedTokensWithRateLimits[tokenSymbol] = { + standard: null, + custom: null, + } + } + } + + return { + sourceChain: publicSourceChain, + destinationChain: publicDestChain, + onRamp: { + address: laneConfig.onRamp.address, + version: normalizeVersion(laneConfig.onRamp.version), + enforceOutOfOrder: laneConfig.onRamp.enforceOutOfOrder, + }, + offRamp: { + address: laneConfig.offRamp.address, + version: normalizeVersion(laneConfig.offRamp.version), + }, + supportedTokens: supportedTokensWithRateLimits, + } + } + + /** + * Retrieves only supported tokens with rate limits for a specific lane + * + * @param environment - Network environment (mainnet/testnet) + * @param sourceIdentifier - Source chain identifier (chainId, selector, or internalId) + * @param destinationIdentifier - Destination chain identifier + * @param inputKeyType - Type of identifier used (chainId, selector, internalId) + * @returns Supported tokens with rate limits or null if lane not found + */ + async getSupportedTokensWithRateLimits( + environment: Environment, + sourceIdentifier: string, + destinationIdentifier: string, + inputKeyType: LaneInputKeyType + ): Promise<SupportedTokensServiceResponse> { + logger.info({ + message: "Getting supported tokens with rate limits", + requestId: this.requestId, + environment, + sourceIdentifier, + destinationIdentifier, + inputKeyType, + }) + + try { + // Load reference data + const { lanesReferenceData, chainsReferenceData } = loadReferenceData({ + environment, + version: Version.V1_2_0, + }) + + // Resolve identifiers to internal IDs + const sourceInternalId = this.resolveToInternalId( + sourceIdentifier, + inputKeyType, + chainsReferenceData as Record<string, ChainConfig> + ) + const destinationInternalId = this.resolveToInternalId( + destinationIdentifier, + inputKeyType, + chainsReferenceData as Record<string, ChainConfig> + ) + + if (!sourceInternalId || !destinationInternalId) { + logger.warn({ + message: "Could not resolve chain identifiers", + requestId: this.requestId, + sourceIdentifier, + destinationIdentifier, + }) + return { data: null, tokenCount: 0 } + } + + // Get lane data + const sourceLanes = lanesReferenceData[sourceInternalId] as Record<string, LaneConfig> | undefined + if (!sourceLanes) { + return { data: null, tokenCount: 0 } + } + + const laneConfig = sourceLanes[destinationInternalId] + if (!laneConfig) { + return { data: null, tokenCount: 0 } + } + + // Extract supported token symbols + const tokenSymbols = this.extractSupportedTokens(laneConfig) + + // Load rate limits data + const rateLimitsData = this.loadRateLimitsData(environment) + + // Build supportedTokens with rate limits + const supportedTokensWithRateLimits: Record<string, TokenRateLimits> = {} + + for (const tokenSymbol of tokenSymbols) { + const tokenData = rateLimitsData[tokenSymbol] + if (tokenData) { + const sourceData = tokenData[sourceInternalId] + if (sourceData?.remote) { + const destData = sourceData.remote[destinationInternalId] + if (destData) { + supportedTokensWithRateLimits[tokenSymbol] = { + standard: destData.standard, + custom: destData.custom, + } + } else { + supportedTokensWithRateLimits[tokenSymbol] = { standard: null, custom: null } + } + } else { + supportedTokensWithRateLimits[tokenSymbol] = { standard: null, custom: null } + } + } else { + supportedTokensWithRateLimits[tokenSymbol] = { standard: null, custom: null } + } + } + + const tokenCount = Object.keys(supportedTokensWithRateLimits).length + + logger.info({ + message: "Supported tokens with rate limits retrieved", + requestId: this.requestId, + sourceInternalId, + destinationInternalId, + tokenCount, + }) + + return { data: supportedTokensWithRateLimits, tokenCount } + } catch (error) { + logger.error({ + message: "Failed to get supported tokens with rate limits", + requestId: this.requestId, + error: error instanceof Error ? error.message : "Unknown error", + }) + return { data: null, tokenCount: 0 } + } + } +} diff --git a/src/lib/ccip/services/rate-limits-data.ts b/src/lib/ccip/services/rate-limits-data.ts new file mode 100644 index 00000000000..cce168ac68e --- /dev/null +++ b/src/lib/ccip/services/rate-limits-data.ts @@ -0,0 +1,352 @@ +import { + Environment, + RateLimitsFilterType, + RateLimitsServiceResponse, + RateLimitsData, + TokenRateLimits, + RateLimiterConfig, + RateLimiterEntry, + RateLimiterDirections, + isRateLimiterUnavailable, + LaneRateLimitsFilterType, + LaneInputKeyType, +} from "~/lib/ccip/types/index.ts" +import { LaneDataService } from "./lane-data.ts" +import { loadReferenceData, Version } from "@config/data/ccip/index.ts" +import type { ChainConfig } from "@config/data/ccip/types.ts" +import { logger } from "@lib/logging/index.js" + +// Import the mock data files +import rateLimitsMainnet from "~/__mocks__/rate-limits-mainnet.json" with { type: "json" } +import rateLimitsTestnet from "~/__mocks__/rate-limits-testnet.json" with { type: "json" } + +export const prerender = false + +/** + * Service class for handling CCIP rate limits data operations + * Provides functionality to filter and retrieve rate limiter configurations + */ +export class RateLimitsDataService { + private readonly requestId: string + + /** + * Creates a new instance of RateLimitsDataService + */ + constructor() { + this.requestId = crypto.randomUUID() + + logger.debug({ + message: "RateLimitsDataService initialized", + requestId: this.requestId, + }) + } + + /** + * Retrieves rate limits data for a specific lane, optionally filtered by tokens, direction, and rate type + * + * @param environment - Network environment (mainnet/testnet) + * @param filters - Filter parameters including source/destination chains, tokens, direction, and rate type + * @returns Filtered rate limits data with metadata + */ + async getFilteredRateLimits( + environment: Environment, + filters: RateLimitsFilterType + ): Promise<RateLimitsServiceResponse> { + logger.debug({ + message: "Processing rate limits request", + requestId: this.requestId, + environment, + filters, + }) + + try { + // Load the appropriate rate limits data based on environment + const rateLimitsData = this.loadRateLimitsData(environment) + + // Extract rate limits for the specified lane + const result = this.extractLaneRateLimits(rateLimitsData, filters) + + const tokenCount = Object.keys(result).length + + logger.info({ + message: "Rate limits data retrieved successfully", + requestId: this.requestId, + tokenCount, + sourceChain: filters.sourceInternalId, + destinationChain: filters.destinationInternalId, + }) + + return { + data: result, + metadata: { + tokenCount, + }, + } + } catch (error) { + logger.error({ + message: "Failed to process rate limits data", + requestId: this.requestId, + error: error instanceof Error ? error.message : "Unknown error", + }) + + throw error + } + } + + /** + * Loads rate limits data for the specified environment + */ + private loadRateLimitsData(environment: Environment): RateLimitsData { + logger.debug({ + message: "Loading rate limits data", + requestId: this.requestId, + environment, + }) + + if (environment === Environment.Mainnet) { + return rateLimitsMainnet as RateLimitsData + } + return rateLimitsTestnet as RateLimitsData + } + + /** + * Extracts rate limits for a specific lane from the token-centric data structure + * + * @param rateLimitsData - Full rate limits data (token -> source -> { minBlockConfirmation?, remote: { dest -> ... } }) + * @param filters - Filter parameters + * @returns Token-centric rate limits for the specified lane + */ + private extractLaneRateLimits( + rateLimitsData: RateLimitsData, + filters: RateLimitsFilterType + ): Record<string, TokenRateLimits> { + const { sourceInternalId, destinationInternalId, tokens, direction, rateType } = filters + const result: Record<string, TokenRateLimits> = {} + + // Parse token filter if provided + const tokenFilter = tokens + ? tokens + .split(",") + .map((t) => t.trim()) + .filter((t) => t.length > 0) + : null + + // Iterate through all tokens in the data + for (const [tokenSymbol, sourceChains] of Object.entries(rateLimitsData)) { + // Skip if token filter is provided and this token is not in the filter + if (tokenFilter && !tokenFilter.includes(tokenSymbol)) { + continue + } + + // Check if this token has data for the requested source chain + const sourceChainData = sourceChains[sourceInternalId] + if (!sourceChainData) { + continue + } + + // Check if destination exists in remote + const laneRateLimits = sourceChainData.remote[destinationInternalId] + if (!laneRateLimits) { + continue + } + + // Apply filters for direction and rate type + const filteredLimits = this.applyFilters(laneRateLimits, direction, rateType) + + if (filteredLimits) { + result[tokenSymbol] = filteredLimits + } + } + + logger.debug({ + message: "Lane rate limits extracted", + requestId: this.requestId, + sourceChain: sourceInternalId, + destinationChain: destinationInternalId, + tokenCount: Object.keys(result).length, + filteredTokens: tokenFilter, + direction, + rateType, + }) + + return result + } + + /** + * Applies direction and rate type filters to rate limits + * + * @param rateLimits - Original rate limits with standard and custom entries + * @param direction - Optional direction filter ("in" or "out") + * @param rateType - Optional rate type filter ("standard" or "custom") + * @returns Filtered rate limits or null if no data matches + */ + private applyFilters( + rateLimits: TokenRateLimits, + direction?: "in" | "out", + rateType?: "standard" | "custom" + ): TokenRateLimits | null { + // Apply direction filter to both standard and custom entries + const filteredStandard = this.applyDirectionFilter(rateLimits.standard, direction) + const filteredCustom = this.applyDirectionFilter(rateLimits.custom, direction) + + // If rate type filter is specified, return only that type + if (rateType === "standard") { + if (!filteredStandard) { + return null + } + return { + standard: filteredStandard, + custom: null, // Indicate custom was filtered out + } + } + + if (rateType === "custom") { + if (!filteredCustom) { + return null + } + return { + standard: null, // Indicate standard was filtered out + custom: filteredCustom, + } + } + + // No rate type filter, return both (if either has data) + if (!filteredStandard && !filteredCustom) { + return null + } + + return { + standard: filteredStandard ?? null, + custom: filteredCustom ?? null, + } + } + + /** + * Applies direction filter to a rate limiter entry + * + * @param entry - Rate limiter entry (directions or unavailable) + * @param direction - Optional direction filter ("in" or "out") + * @returns Filtered entry or null if no data matches + */ + private applyDirectionFilter(entry: RateLimiterEntry, direction?: "in" | "out"): RateLimiterEntry | null { + // If entry is unavailable, return it as-is + if (isRateLimiterUnavailable(entry)) { + return entry + } + + // If no direction filter, return the full entry + if (!direction) { + return entry + } + + // Filter to specific direction + const directionsEntry = entry as RateLimiterDirections + const filteredConfig = directionsEntry[direction] + if (!filteredConfig) { + return null + } + + // Return only the requested direction + return { + [direction]: filteredConfig, + } as RateLimiterDirections + } + + /** + * Validates that a rate limiter config exists and has valid structure + */ + private isValidRateLimiterConfig(config: unknown): config is RateLimiterConfig { + if (!config || typeof config !== "object") { + return false + } + + const c = config as Record<string, unknown> + return typeof c.capacity === "string" && typeof c.isEnabled === "boolean" && typeof c.rate === "string" + } + + /** + * Gets the request ID for this service instance + */ + getRequestId(): string { + return this.requestId + } + + /** + * Retrieves rate limits for a specific lane using path parameters + * + * @param environment - Network environment (mainnet/testnet) + * @param sourceIdentifier - Source chain identifier + * @param destinationIdentifier - Destination chain identifier + * @param inputKeyType - Type of chain identifier (chainId, selector, internalId) + * @param filters - Optional filters for tokens, direction, rate type + * @returns Rate limits data with metadata + */ + async getLaneRateLimits( + environment: Environment, + sourceIdentifier: string, + destinationIdentifier: string, + inputKeyType: LaneInputKeyType, + filters: LaneRateLimitsFilterType = {} + ): Promise<RateLimitsServiceResponse> { + logger.info({ + message: "Processing lane rate limits request", + requestId: this.requestId, + environment, + sourceIdentifier, + destinationIdentifier, + inputKeyType, + filters, + }) + + try { + // Resolve chain identifiers to internal IDs + const { chainsReferenceData } = loadReferenceData({ + environment, + version: Version.V1_2_0, + }) + + const laneDataService = new LaneDataService() + const sourceInternalId = laneDataService.resolveToInternalId( + sourceIdentifier, + inputKeyType, + chainsReferenceData as Record<string, ChainConfig> + ) + const destinationInternalId = laneDataService.resolveToInternalId( + destinationIdentifier, + inputKeyType, + chainsReferenceData as Record<string, ChainConfig> + ) + + if (!sourceInternalId || !destinationInternalId) { + logger.warn({ + message: "Could not resolve chain identifiers for rate limits", + requestId: this.requestId, + sourceIdentifier, + destinationIdentifier, + }) + return { + data: {}, + metadata: { tokenCount: 0 }, + } + } + + // Use existing filter-based method with resolved internal IDs + const fullFilters: RateLimitsFilterType = { + sourceInternalId, + destinationInternalId, + tokens: filters.tokens, + direction: filters.direction, + rateType: filters.rateType, + } + + return this.getFilteredRateLimits(environment, fullFilters) + } catch (error) { + logger.error({ + message: "Failed to get lane rate limits", + requestId: this.requestId, + error: error instanceof Error ? error.message : "Unknown error", + }) + throw error + } + } +} diff --git a/src/lib/ccip/services/realtime-data-instance.ts b/src/lib/ccip/services/realtime-data-instance.ts new file mode 100644 index 00000000000..b1ac8df61bd --- /dev/null +++ b/src/lib/ccip/services/realtime-data-instance.ts @@ -0,0 +1,7 @@ +import { RealtimeDataService } from "./realtime-data.ts" + +/** + * Singleton instance of RealtimeDataService + * Use this shared instance across all components to avoid creating multiple instances + */ +export const realtimeDataService = new RealtimeDataService() diff --git a/src/lib/ccip/services/realtime-data.ts b/src/lib/ccip/services/realtime-data.ts new file mode 100644 index 00000000000..a0b7a84b470 --- /dev/null +++ b/src/lib/ccip/services/realtime-data.ts @@ -0,0 +1,259 @@ +import { Environment } from "~/lib/ccip/types/index.ts" +import type { + TokenRateLimits, + RateLimiterEntry, + RateLimiterConfig, + TokenFinalityData, + OutputKeyType, +} from "~/lib/ccip/types/index.ts" + +export const prerender = false + +/** + * Base URL for CCIP realtime API + * For client-side calls, use relative URLs to hit the local API endpoints + */ +const getApiBaseUrl = () => { + // In browser context, use relative URLs + if (typeof window !== "undefined") { + return "" + } + // In server context, use environment variable or default + return process.env.CCIP_REALTIME_API_BASE_URL || "https://api.ccip.chainlink.com" +} + +/** + * Response structure for lane supported tokens endpoint + */ +export interface LaneSupportedTokensResponse { + metadata: { + environment: Environment + timestamp: string + requestId: string + sourceChain: string + destinationChain: string + tokenCount: number + } + data: Record<string, TokenRateLimits> +} + +/** + * Response structure for token finality endpoint + */ +export interface TokenFinalityResponse { + metadata: { + environment: Environment + timestamp: string + requestId: string + tokenSymbol: string + chainCount: number + } + data: Record<string, TokenFinalityData> +} + +/** + * Service class for handling CCIP realtime data operations + * Provides functionality to fetch live data from the CCIP API + */ +export class RealtimeDataService { + private readonly requestId: string + + /** + * Creates a new instance of RealtimeDataService + */ + constructor() { + // Generate UUID - handle both browser and server environments + if (typeof crypto !== "undefined" && crypto.randomUUID) { + this.requestId = crypto.randomUUID() + } else { + this.requestId = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}` + } + } + + /** + * Fetches supported tokens with rate limits for a specific lane + * + * @param sourceInternalId - Source chain internal ID + * @param destinationInternalId - Destination chain internal ID + * @param environment - Network environment (mainnet/testnet) + * @returns Supported tokens with rate limits + */ + async getLaneSupportedTokens( + sourceInternalId: string, + destinationInternalId: string, + environment: Environment + ): Promise<LaneSupportedTokensResponse | null> { + try { + const baseUrl = getApiBaseUrl() + const url = `${baseUrl}/api/ccip/v1/lanes/by-internal-id/${sourceInternalId}/${destinationInternalId}/supported-tokens?environment=${environment}` + + const response = await fetch(url) + + if (!response.ok) { + return null + } + + const data = await response.json() + return data + } catch (error) { + console.error("Error fetching lane supported tokens:", error) + return null + } + } + + /** + * Fetches token finality details across all chains + * + * @param tokenCanonicalSymbol - Token canonical symbol (e.g., "BETS", "LINK") + * @param environment - Network environment (mainnet/testnet) + * @param outputKey - Format to use for displaying chain keys (optional) + * @returns Token finality data for all chains + */ + async getTokenFinality( + tokenCanonicalSymbol: string, + environment: Environment, + outputKey?: OutputKeyType + ): Promise<TokenFinalityResponse | null> { + try { + const baseUrl = getApiBaseUrl() + let url = `${baseUrl}/api/ccip/v1/tokens/${tokenCanonicalSymbol}/finality?environment=${environment}` + + if (outputKey) { + url += `&output_key=${outputKey}` + } + + const response = await fetch(url) + + if (!response.ok) { + console.error("Failed to fetch token finality:", response.status) + return null + } + + const data = await response.json() + return data + } catch (error) { + console.error("Error fetching token finality:", error) + return null + } + } + + /** + * Checks if rate limiter data is unavailable (null) + * + * @param entry - Rate limiter entry to check + * @returns True if unavailable (null) + */ + isRateLimiterUnavailable(entry: RateLimiterEntry): entry is null { + return entry === null + } + + /** + * Checks if rate limiter is enabled + * + * @param config - Rate limiter configuration + * @returns True if enabled + */ + isRateLimiterEnabled(config: RateLimiterConfig): boolean { + return config.isEnabled + } + + /** + * Gets the request ID for this service instance + */ + getRequestId(): string { + return this.requestId + } + + /** + * Extracts FTF (custom) rate limit data for a specific token and direction + * + * @param tokenRateLimits - Token rate limits containing standard and custom entries + * @param direction - Direction ("in" for inbound, "out" for outbound) + * @returns FTF rate limiter config or null if unavailable + */ + getFTFRateLimit(tokenRateLimits: TokenRateLimits, direction: "in" | "out"): RateLimiterConfig | null { + if (!tokenRateLimits.custom || this.isRateLimiterUnavailable(tokenRateLimits.custom)) { + return null + } + + const customEntry = tokenRateLimits.custom + return customEntry[direction] || null + } + + /** + * Gets FTF capacity for a specific token and direction + * + * @param tokenRateLimits - Token rate limits containing standard and custom entries + * @param direction - Direction ("in" for inbound, "out" for outbound) + * @returns FTF capacity value or null if unavailable + */ + getFTFCapacity(tokenRateLimits: TokenRateLimits, direction: "in" | "out"): string | null { + const ftfLimit = this.getFTFRateLimit(tokenRateLimits, direction) + return ftfLimit?.capacity || null + } + + /** + * Gets FTF refill rate for a specific token and direction + * + * @param tokenRateLimits - Token rate limits containing standard and custom entries + * @param direction - Direction ("in" for inbound, "out" for outbound) + * @returns FTF refill rate value or null if unavailable + */ + getFTFRefillRate(tokenRateLimits: TokenRateLimits, direction: "in" | "out"): string | null { + const ftfLimit = this.getFTFRateLimit(tokenRateLimits, direction) + return ftfLimit?.rate || null + } + + /** + * Checks if FTF rate limiting is enabled for a specific token and direction + * + * @param tokenRateLimits - Token rate limits containing standard and custom entries + * @param direction - Direction ("in" for inbound, "out" for outbound) + * @returns True if FTF is enabled, false otherwise + */ + isFTFEnabled(tokenRateLimits: TokenRateLimits, direction: "in" | "out"): boolean { + const ftfLimit = this.getFTFRateLimit(tokenRateLimits, direction) + return ftfLimit?.isEnabled || false + } + + /** + * Gets both standard and FTF rate limits for a specific token and direction + * + * @param tokenRateLimits - Token rate limits containing standard and custom entries (can be null/undefined) + * @param direction - Direction ("in" for inbound, "out" for outbound) + * @returns Object containing both standard and FTF rate limits + */ + getAllRateLimitsForDirection( + tokenRateLimits: TokenRateLimits | null | undefined, + direction: "in" | "out" + ): { + standard: RateLimiterConfig | null + ftf: RateLimiterConfig | null + } { + if (!tokenRateLimits) { + return { standard: null, ftf: null } + } + + const standardLimit = + tokenRateLimits.standard && !this.isRateLimiterUnavailable(tokenRateLimits.standard) + ? tokenRateLimits.standard[direction] || null + : null + + const ftfLimit = this.getFTFRateLimit(tokenRateLimits, direction) + + return { + standard: standardLimit, + ftf: ftfLimit, + } + } + + /** + * Checks if a token has FTF rate limiting available + * + * @param tokenRateLimits - Token rate limits to check + * @returns True if FTF data is available (not null/unavailable) + */ + hasFTFRateLimits(tokenRateLimits: TokenRateLimits): boolean { + return tokenRateLimits.custom !== null && !this.isRateLimiterUnavailable(tokenRateLimits.custom) + } +} diff --git a/src/pages/api/services/token-data.ts b/src/lib/ccip/services/token-data.ts similarity index 57% rename from src/pages/api/services/token-data.ts rename to src/lib/ccip/services/token-data.ts index d72dca0b9eb..23f850bb1db 100644 --- a/src/pages/api/services/token-data.ts +++ b/src/lib/ccip/services/token-data.ts @@ -6,15 +6,26 @@ import { TokenChainData, TokenDataResponse, TokenServiceResponse, -} from "../ccip/types/index.ts" + TokenDetailChainData, + TokenDetailDataResponse, + TokenDetailServiceResponse, + TokenFinalityData, + TokenFinalityDataResponse, + TokenFinalityServiceResponse, + RateLimitsData, +} from "~/lib/ccip/types/index.ts" import { Version } from "@config/data/ccip/types.ts" import { SupportedChain } from "@config/index.ts" import { getAllSupportedTokens, getAllTokenLanes, getTokenData } from "@config/data/ccip/data.ts" -import { resolveChainOrThrow, generateChainKey } from "@api/ccip/utils.ts" +import { resolveChainOrThrow, generateChainKey } from "~/lib/ccip/utils.ts" import { logger } from "@lib/logging/index.js" import { getChainId, getChainTypeAndFamily, getTitle } from "../../../features/utils/index.ts" import { getSelectorEntry } from "@config/data/ccip/selectors.ts" +// Import rate limits mock data for custom finality info +import rateLimitsMainnet from "~/__mocks__/rate-limits-mainnet.json" with { type: "json" } +import rateLimitsTestnet from "~/__mocks__/rate-limits-testnet.json" with { type: "json" } + export const prerender = false /** @@ -99,11 +110,11 @@ export class TokenDataService { Object.entries(tokenData).forEach(([chainId, chainData]) => { try { - // Only process chains where poolAddress exists - if (!chainData.poolAddress) { + // Only process chains where pool.address exists + if (!chainData.pool?.address) { this.skippedTokensCount++ logger.warn({ - message: "Chain missing poolAddress - skipping only this chain", + message: "Chain missing pool.address - skipping only this chain", requestId: this.requestId, tokenCanonicalId, chainId, @@ -138,12 +149,12 @@ export class TokenDataService { if (!destNumericChainId) return destChainId - if (outputKey === "chainId") { + if (outputKey === "chain_id") { return generateChainKey(destNumericChainId, destChainType, outputKey) } else if (outputKey === "selector") { const selectorEntry = getSelectorEntry(destNumericChainId, destChainType) return selectorEntry?.selector || destChainId - } else if (outputKey === "internalId") { + } else if (outputKey === "internal_id") { const selectorEntry = getSelectorEntry(destNumericChainId, destChainType) return selectorEntry?.name || destChainId } @@ -153,14 +164,14 @@ export class TokenDataService { // Get the appropriate key based on outputKey parameter let chainKey = chainId - if (outputKey === "chainId") { + if (outputKey === "chain_id") { chainKey = generateChainKey(numericChainId, chainType, outputKey) } else if (outputKey === "selector") { const selectorEntry = getSelectorEntry(numericChainId, chainType) if (selectorEntry) { chainKey = selectorEntry.selector } - } else if (outputKey === "internalId") { + } else if (outputKey === "internal_id") { const selectorEntry = getSelectorEntry(numericChainId, chainType) if (selectorEntry) { chainKey = selectorEntry.name @@ -176,8 +187,12 @@ export class TokenDataService { decimals: chainData.decimals, destinations, name: chainData.name || "", - poolAddress: chainData.poolAddress, - poolType: chainData.poolType, + pool: { + address: chainData.pool.address || "", + rawType: chainData.pool.rawType, + type: chainData.pool.type, + version: chainData.pool.version, + }, symbol: chainData.symbol, tokenAddress: chainData.tokenAddress, }, @@ -261,7 +276,7 @@ export class TokenDataService { public async getFilteredTokens( environment: Environment, filters: TokenFilterType, - outputKey: OutputKeyType = "chainId" + outputKey: OutputKeyType = "chain_id" ): Promise<TokenServiceResponse> { logger.info({ message: "Starting token filtering process", @@ -361,4 +376,224 @@ export class TokenDataService { metadata, } } + + /** + * Retrieves detailed token information for a specific token, including custom finality data + * + * @param environment - Network environment (mainnet/testnet) + * @param tokenCanonicalSymbol - Canonical symbol for the token + * @param outputKey - Format to use for displaying chain information + * @returns Token details with custom finality information for each chain + */ + public async getTokenWithFinality( + environment: Environment, + tokenCanonicalSymbol: string, + outputKey: OutputKeyType = "chain_id" + ): Promise<TokenDetailServiceResponse | null> { + logger.info({ + message: "Getting token with finality data", + requestId: this.requestId, + environment, + tokenCanonicalSymbol, + outputKey, + }) + + // Get base token data using existing method + const tokenData = await this.processTokenData(environment, tokenCanonicalSymbol, outputKey) + + if (!tokenData) { + logger.warn({ + message: "Token not found", + requestId: this.requestId, + tokenCanonicalSymbol, + }) + return null + } + + // Load rate limits data for finality info + const rateLimitsData = this.loadRateLimitsData(environment) + + // Get token's rate limits by internal ID + const tokenRateLimits = rateLimitsData[tokenCanonicalSymbol] + + // Merge token data with custom finality information + const result: TokenDetailDataResponse = {} + + for (const [chainKey, chainData] of Object.entries(tokenData)) { + // Look up minBlockConfirmation using internal ID + // We need to map the chainKey back to internal ID for rate limits lookup + const internalId = this.getInternalIdFromChainKey(chainData.chainId, chainData.chainName, outputKey) + + let minBlockConfirmation: number | null = null + let hasCustomFinality: boolean | null = null + + if (tokenRateLimits && internalId && tokenRateLimits[internalId]) { + minBlockConfirmation = tokenRateLimits[internalId].minBlockConfirmation + + // Derive hasCustomFinality from minBlockConfirmation + if (minBlockConfirmation === null) { + hasCustomFinality = null // Unavailable + } else if (minBlockConfirmation > 0) { + hasCustomFinality = true + } else { + hasCustomFinality = false + } + } + + const detailChainData: TokenDetailChainData = { + ...chainData, + hasCustomFinality, + minBlockConfirmation, + } + + result[chainKey] = detailChainData + } + + logger.info({ + message: "Token with finality data retrieved", + requestId: this.requestId, + tokenCanonicalSymbol, + chainCount: Object.keys(result).length, + }) + + return { + data: result, + metadata: { + chainCount: Object.keys(result).length, + }, + } + } + + /** + * Loads rate limits data for the specified environment + */ + private loadRateLimitsData(environment: Environment): RateLimitsData { + if (environment === Environment.Mainnet) { + return rateLimitsMainnet as RateLimitsData + } + return rateLimitsTestnet as RateLimitsData + } + + /** + * Gets the internal ID for a chain based on chainId/chainName + * This is needed to look up rate limits data which uses internal IDs as keys + */ + private getInternalIdFromChainKey( + chainId: number | string, + chainName: string, + outputKey: OutputKeyType + ): string | null { + try { + // If outputKey is internalId, the chainName might already be the internal ID + // We need to look up the selector entry by chainId + const numericChainId = typeof chainId === "string" ? parseInt(chainId, 10) : chainId + + if (isNaN(numericChainId)) { + // chainId is not numeric, might be a non-EVM chain identifier + // Try to find by name pattern + return null + } + + // Get selector entry which has the internal name + const selectorEntry = getSelectorEntry(numericChainId, "evm") + if (selectorEntry) { + return selectorEntry.name + } + + return null + } catch { + logger.debug({ + message: "Could not resolve internal ID for chain", + requestId: this.requestId, + chainId, + chainName, + }) + return null + } + } + + /** + * Retrieves only finality data for a specific token (lightweight endpoint) + * + * @param environment - Network environment (mainnet/testnet) + * @param tokenCanonicalSymbol - Canonical symbol for the token + * @param outputKey - Format to use for displaying chain information + * @returns Finality information (hasCustomFinality, minBlockConfirmation) for each chain + */ + public async getTokenFinality( + environment: Environment, + tokenCanonicalSymbol: string, + outputKey: OutputKeyType = "chain_id" + ): Promise<TokenFinalityServiceResponse | null> { + logger.info({ + message: "Getting token finality data", + requestId: this.requestId, + environment, + tokenCanonicalSymbol, + outputKey, + }) + + // Get base token data to know which chains the token exists on + const tokenData = await this.processTokenData(environment, tokenCanonicalSymbol, outputKey) + + if (!tokenData) { + logger.warn({ + message: "Token not found", + requestId: this.requestId, + tokenCanonicalSymbol, + }) + return null + } + + // Load rate limits data for finality info + const rateLimitsData = this.loadRateLimitsData(environment) + + // Get token's rate limits by internal ID + const tokenRateLimits = rateLimitsData[tokenCanonicalSymbol] + + // Extract only finality data for each chain + const result: TokenFinalityDataResponse = {} + + for (const [chainKey, chainData] of Object.entries(tokenData)) { + // Look up minBlockConfirmation using internal ID + const internalId = this.getInternalIdFromChainKey(chainData.chainId, chainData.chainName, outputKey) + + let minBlockConfirmation: number | null = null + let hasCustomFinality: boolean | null = null + + if (tokenRateLimits && internalId && tokenRateLimits[internalId]) { + minBlockConfirmation = tokenRateLimits[internalId].minBlockConfirmation + + // Derive hasCustomFinality from minBlockConfirmation + if (minBlockConfirmation === null) { + hasCustomFinality = null // Unavailable + } else if (minBlockConfirmation > 0) { + hasCustomFinality = true + } else { + hasCustomFinality = false + } + } + + const finalityData: TokenFinalityData = { + hasCustomFinality, + minBlockConfirmation, + } + + result[chainKey] = finalityData + } + + logger.info({ + message: "Token finality data retrieved", + requestId: this.requestId, + tokenCanonicalSymbol, + chainCount: Object.keys(result).length, + }) + + return { + data: result, + metadata: { + chainCount: Object.keys(result).length, + }, + } + } } diff --git a/src/pages/api/ccip/types/faucet.ts b/src/lib/ccip/types/faucet.ts similarity index 100% rename from src/pages/api/ccip/types/faucet.ts rename to src/lib/ccip/types/faucet.ts diff --git a/src/lib/ccip/types/index.ts b/src/lib/ccip/types/index.ts new file mode 100644 index 00000000000..30232fed61d --- /dev/null +++ b/src/lib/ccip/types/index.ts @@ -0,0 +1,518 @@ +// Chain Data API Types + +import { Environment } from "@config/data/ccip/types.ts" + +export { Environment } + +// Chain type and family declarations +export type ChainType = "evm" | "solana" | "aptos" | "sui" +export type ChainFamily = "evm" | "mvm" | "svm" + +export const prerender = false + +/** + * Enriched fee token information with address and metadata + * Used when enrichFeeTokens=true query parameter is set + */ +export type FeeTokenEnriched = { + symbol: string + name: string + address: string + decimals: number +} + +export type ChainConfigError = { + chainId: number + networkId: string + reason: string + missingFields: string[] +} + +export type ChainMetadata = { + environment: Environment + timestamp: string + requestId: string + ignoredChainCount: number +} + +export interface ChainDetails { + chainId: number | string + displayName: string + selector: string + internalId: string + feeTokens: string[] | FeeTokenEnriched[] + router: string + rmn: string + chainType: ChainType + chainFamily: ChainFamily + registryModule?: string + tokenAdminRegistry?: string + tokenPoolFactory?: string + feeQuoter?: string + mcms?: string +} + +export type ChainApiResponse = { + metadata: ChainMetadata + data: Record<string, Record<string, ChainDetails>> + ignored: { + chainId: number + networkId: string + reason: string + missingFields: string[] + chain_id?: string + }[] +} + +export type OutputKeyType = "chain_id" | "selector" | "internal_id" + +export type ChainApiError = { + error: string + message: string +} + +export interface FilterType { + chainId?: string + selector?: string + internalId?: string +} + +export type SelectorEntry = { + selector: string + name: string +} + +export type SelectorsConfig = { + selectors: Record<string, SelectorEntry> +} + +// Token Data API Types + +export type TokenConfigError = { + symbol: string + reason: string + missingFields: string[] +} + +export type TokenMetadata = { + environment: Environment + timestamp: string + requestId: string + ignoredTokenCount: number + validTokenCount: number +} + +export type TokenPool = { + address: string + rawType: string + type: string + version: string +} + +export type TokenChainData = { + chainId: number | string + chainName: string + decimals: number + destinations: string[] + name: string + pool: TokenPool + symbol: string + tokenAddress: string +} + +export type TokenDataResponse = { + [key: string]: { + [chainKey: string]: TokenChainData + } +} + +export type TokenServiceResponse = { + tokens: TokenDataResponse + errors: TokenConfigError[] + metadata: { + validTokenCount: number + ignoredTokenCount: number + } +} + +export type TokenApiResponse = { + metadata: TokenMetadata + data: TokenDataResponse + ignored: TokenConfigError[] +} + +export interface TokenFilterType { + token_id?: string + chain_id?: string +} + +// Token Detail API Types (for /tokens/{tokenCanonicalSymbol} endpoint) + +/** + * Extended token chain data with custom finality information + */ +export interface TokenDetailChainData extends TokenChainData { + /** Whether custom finality is enabled (derived from minBlockConfirmation > 0) */ + hasCustomFinality: boolean | null + /** Minimum block confirmations required, null if unavailable */ + minBlockConfirmation: number | null +} + +/** + * Token detail response data structure + */ +export type TokenDetailDataResponse = { + [chainKey: string]: TokenDetailChainData +} + +/** + * Metadata for token detail API responses + */ +export interface TokenDetailMetadata { + environment: Environment + timestamp: string + requestId: string + tokenSymbol: string + chainCount: number +} + +/** + * Token detail API response format + */ +export interface TokenDetailApiResponse { + metadata: TokenDetailMetadata + data: TokenDetailDataResponse +} + +/** + * Token detail service response (internal) + */ +export interface TokenDetailServiceResponse { + data: TokenDetailDataResponse + metadata: { + chainCount: number + } +} + +// Token Finality API Types (for /tokens/{tokenCanonicalSymbol}/finality endpoint) + +/** + * Finality data for a token on a specific chain + */ +export interface TokenFinalityData { + /** Whether custom finality is enabled (derived from minBlockConfirmation > 0) */ + hasCustomFinality: boolean | null + /** Minimum block confirmations required, null if unavailable */ + minBlockConfirmation: number | null +} + +/** + * Token finality response data structure + */ +export type TokenFinalityDataResponse = { + [chainKey: string]: TokenFinalityData +} + +/** + * Token finality API response format + */ +export interface TokenFinalityApiResponse { + metadata: TokenDetailMetadata + data: TokenFinalityDataResponse +} + +/** + * Token finality service response (internal) + */ +export interface TokenFinalityServiceResponse { + data: TokenFinalityDataResponse + metadata: { + chainCount: number + } +} + +// Lane Data API Types + +export type LaneConfigError = { + sourceChain: string + destinationChain: string + reason: string + missingFields: string[] +} + +export type LaneMetadata = { + environment: Environment + timestamp: string + requestId: string + ignoredLaneCount: number + validLaneCount: number +} + +// Internal interface with chainType and chainFamily for processing +export interface ChainInfoInternal { + chainId: number | string + displayName: string + selector: string + internalId: string + chainType: ChainType + chainFamily: ChainFamily +} + +// Public interface for API responses without chainType and chainFamily +export interface ChainInfo { + chainId: number | string + displayName: string + selector: string + internalId: string +} + +export interface LaneDetails { + sourceChain: ChainInfo + destinationChain: ChainInfo + onRamp: { + address: string + version: string + enforceOutOfOrder?: boolean + } + offRamp: { + address: string + version: string + } + supportedTokens: string[] +} + +export type LaneDataResponse = Record<string, LaneDetails> + +export type LaneServiceResponse = { + data: LaneDataResponse + errors: LaneConfigError[] + metadata: { + validLaneCount: number + ignoredLaneCount: number + } +} + +export type LaneApiResponse = { + metadata: LaneMetadata + data: LaneDataResponse + ignored: LaneConfigError[] +} + +export interface LaneFilterType { + sourceChainId?: string + destinationChainId?: string + sourceSelector?: string + destinationSelector?: string + sourceInternalId?: string + destinationInternalId?: string + version?: string +} + +// Lane Detail API Types (for /lanes/by-{type}/{source}/{destination} endpoints) + +/** + * Input key type for lane path parameters + */ +export type LaneInputKeyType = "chain_id" | "selector" | "internal_id" + +/** + * Metadata for single lane detail API responses + */ +export interface LaneDetailMetadata { + environment: Environment + timestamp: string + requestId: string + sourceChain: string + destinationChain: string +} + +// Rate Limits API Types + +/** + * Rate limiter configuration for a single direction (in or out) + */ +export interface RateLimiterConfig { + capacity: string + isEnabled: boolean + rate: string +} + +/** + * Rate limiter directions (in and/or out) + */ +export interface RateLimiterDirections { + in?: RateLimiterConfig + out?: RateLimiterConfig +} + +/** + * Rate limiter entry can be directions data or null (unavailable) + */ +export type RateLimiterEntry = RateLimiterDirections | null + +/** + * Rate limits for a single token on a lane with both standard and custom (FTF) limits + */ +export interface TokenRateLimits { + standard: RateLimiterEntry + custom: RateLimiterEntry +} + +/** + * Lane details with rate limits included in supportedTokens + * Used for single lane detail endpoints that merge rate limits + */ +export interface LaneDetailWithRateLimits { + sourceChain: ChainInfo + destinationChain: ChainInfo + onRamp: { + address: string + version: string + enforceOutOfOrder?: boolean + } + offRamp: { + address: string + version: string + } + supportedTokens: Record<string, TokenRateLimits> +} + +/** + * Single lane detail API response format (with rate limits) + */ +export interface LaneDetailApiResponse { + metadata: LaneDetailMetadata + data: LaneDetailWithRateLimits +} + +/** + * Lane detail service response (internal) + */ +export interface LaneDetailServiceResponse { + data: LaneDetailWithRateLimits | null +} + +// Supported Tokens API Types (for /lanes/by-{type}/{source}/{destination}/supported-tokens endpoints) + +/** + * Metadata for supported tokens API responses + */ +export interface SupportedTokensMetadata { + environment: Environment + timestamp: string + requestId: string + sourceChain: string + destinationChain: string + tokenCount: number +} + +/** + * Supported tokens API response format + */ +export interface SupportedTokensApiResponse { + metadata: SupportedTokensMetadata + data: Record<string, TokenRateLimits> +} + +/** + * Supported tokens service response (internal) + */ +export interface SupportedTokensServiceResponse { + data: Record<string, TokenRateLimits> | null + tokenCount: number +} + +/** + * Type guard to check if a RateLimiterEntry is unavailable (null) + */ +export function isRateLimiterUnavailable(entry: RateLimiterEntry): entry is null { + return entry === null +} + +/** + * Metadata for rate limits API responses + */ +export interface RateLimitsMetadata { + environment: Environment + timestamp: string + requestId: string + sourceChain: string + destinationChain: string + tokenCount: number +} + +/** + * Filter parameters for rate limits queries (query-based - deprecated) + */ +export interface RateLimitsFilterType { + sourceInternalId: string + destinationInternalId: string + tokens?: string + direction?: "in" | "out" + rateType?: "standard" | "custom" +} + +/** + * Filter parameters for lane rate limits queries (path-based) + * Source and destination come from URL path parameters + */ +export interface LaneRateLimitsFilterType { + tokens?: string + direction?: "in" | "out" + rateType?: "standard" | "custom" +} + +/** + * Direction type for rate limits + */ +export type RateLimitsDirection = "in" | "out" + +/** + * Rate type for rate limits (standard or custom/FTF) + */ +export type RateLimitsType = "standard" | "custom" + +/** + * Source chain rate limits data with minBlockConfirmation and remote destinations + */ +export interface SourceChainRateLimitsData { + minBlockConfirmation: number | null + remote: Record<string, TokenRateLimits> +} + +/** + * Rate limits data structure in the mock JSON files + * Token -> SourceChain -> { minBlockConfirmation?, remote: { DestChain -> { standard, custom } } } + */ +export type RateLimitsData = Record<string, Record<string, SourceChainRateLimitsData>> + +/** + * Rate limits API response format + */ +export interface RateLimitsApiResponse { + metadata: RateLimitsMetadata + data: Record<string, TokenRateLimits> +} + +/** + * Rate limits service response (internal) + */ +export interface RateLimitsServiceResponse { + data: Record<string, TokenRateLimits> + metadata: { + tokenCount: number + } +} + +// Faucet API Types +export type { + FaucetChainConfig, + ChallengeParams, + ChallengeResponse, + VerifyRequest, + VerifyResponse, + VerifySignatureArgs, + FamilyAdapter, + FaucetApiResponse, + FaucetError, +} from "./faucet.ts" diff --git a/src/pages/api/ccip/utils.ts b/src/lib/ccip/utils.ts similarity index 77% rename from src/pages/api/ccip/utils.ts rename to src/lib/ccip/utils.ts index c10232bc66c..de1326f5ed0 100644 --- a/src/pages/api/ccip/utils.ts +++ b/src/lib/ccip/utils.ts @@ -4,7 +4,16 @@ import { ChainsConfig, Environment, loadReferenceData, Version } from "@config/d import { SupportedChain } from "@config/index.ts" import { directoryToSupportedChain } from "@features/utils/index.ts" import { v4 as uuidv4 } from "uuid" -import type { TokenMetadata, ChainType, OutputKeyType } from "./types/index.ts" +import type { + TokenMetadata, + ChainType, + OutputKeyType, + RateLimitsMetadata, + RateLimitsFilterType, + RateLimitsDirection, + RateLimitsType, +} from "./types/index.ts" +import { commonHeaders } from "@lib/api/cacheHeaders.ts" export const prerender = false @@ -13,23 +22,6 @@ export type { ChainsConfig, Version } export { Environment } export type { SelectorsConfig } from "@config/data/ccip/selectors.ts" -/** - * Common HTTP headers used across all API responses - */ -export const commonHeaders = { - "Content-Type": "application/json", -} - -/** - * Extended headers for successful responses with caching directives - */ -export const successHeaders = { - ...commonHeaders, - "Cache-Control": "s-max-age=300, stale-while-revalidate", - "CDN-Cache-Control": "max-age=300", - "Vercel-CDN-Cache-Control": "max-age=300", -} - /** * Custom error class for CCIP-specific errors */ @@ -224,6 +216,90 @@ export const createTokenMetadata = (environment: Environment): TokenMetadata => } } +/** + * Creates rate-limits-specific metadata object + * @param environment - Current network environment + * @param sourceChain - Source chain internal ID + * @param destinationChain - Destination chain internal ID + * @param tokenCount - Number of tokens in the response + * @returns Metadata object for rate limits API response + */ +export const createRateLimitsMetadata = ( + environment: Environment, + sourceChain: string, + destinationChain: string, + tokenCount: number +): RateLimitsMetadata => { + return { + environment, + timestamp: new Date().toISOString(), + requestId: crypto.randomUUID(), + sourceChain, + destinationChain, + tokenCount, + } +} + +/** + * Validates rate limits filter parameters + * @param filters - Filter parameters to validate + * @throws CCIPError if required parameters are missing or invalid + */ +export const validateRateLimitsFilters = (filters: { + sourceInternalId?: string + destinationInternalId?: string + tokens?: string + direction?: string + rateType?: string +}): RateLimitsFilterType => { + // Validate required parameters + if (!filters.sourceInternalId) { + throw new CCIPError(400, "source_internal_id parameter is required") + } + if (!filters.destinationInternalId) { + throw new CCIPError(400, "destination_internal_id parameter is required") + } + + // Validate direction if provided + let direction: RateLimitsDirection | undefined + if (filters.direction) { + const normalizedDirection = filters.direction.toLowerCase() + if (!["in", "out"].includes(normalizedDirection)) { + throw new CCIPError(400, 'direction parameter must be "in" or "out"') + } + direction = normalizedDirection as RateLimitsDirection + } + + // Validate rate_type if provided + let rateType: RateLimitsType | undefined + if (filters.rateType) { + const normalizedRateType = filters.rateType.toLowerCase() + if (!["standard", "custom"].includes(normalizedRateType)) { + throw new CCIPError(400, 'rate_type parameter must be "standard" or "custom"') + } + rateType = normalizedRateType as RateLimitsType + } + + // Validate tokens if provided (must not be empty after parsing) + if (filters.tokens !== undefined && filters.tokens !== null) { + const tokenList = filters.tokens + .split(",") + .map((t) => t.trim()) + .filter((t) => t.length > 0) + if (filters.tokens.length > 0 && tokenList.length === 0) { + throw new CCIPError(400, "tokens parameter cannot be empty when provided") + } + } + + return { + sourceInternalId: filters.sourceInternalId, + destinationInternalId: filters.destinationInternalId, + tokens: filters.tokens, + direction, + rateType, + } +} + /** * Validates the environment parameter * @param environment - Environment string to validate @@ -251,30 +327,30 @@ export const validateFilters = (filters: FilterType): void => { } /** - * Validates and normalizes the outputKey parameter + * Validates and normalizes the output_key parameter * @param outputKey - Output key to validate * @returns Validated output key * @throws CCIPError if output key is invalid */ -export const validateOutputKey = (outputKey?: string): "chainId" | "selector" | "internalId" => { - if (!outputKey) return "chainId" - if (!["chainId", "selector", "internalId"].includes(outputKey)) { - throw new CCIPError(400, "outputKey must be one of: chainId, selector, or internalId") +export const validateOutputKey = (outputKey?: string): "chain_id" | "selector" | "internal_id" => { + if (!outputKey) return "chain_id" + if (!["chain_id", "selector", "internal_id"].includes(outputKey)) { + throw new CCIPError(400, "output_key must be one of: chain_id, selector, or internal_id") } - return outputKey as "chainId" | "selector" | "internalId" + return outputKey as "chain_id" | "selector" | "internal_id" } /** - * Validates the enrichFeeTokens parameter + * Validates the enrich_fee_tokens parameter * @param enrichFeeTokens - String value to validate * @returns Boolean indicating whether to enrich fee tokens with addresses and metadata - * @throws CCIPError if enrichFeeTokens value is invalid + * @throws CCIPError if enrich_fee_tokens value is invalid */ export const validateEnrichFeeTokens = (enrichFeeTokens?: string): boolean => { if (!enrichFeeTokens) return false const normalizedValue = enrichFeeTokens.toLowerCase() if (!["true", "false"].includes(normalizedValue)) { - throw new CCIPError(400, 'enrichFeeTokens must be "true" or "false"') + throw new CCIPError(400, 'enrich_fee_tokens must be "true" or "false"') } return normalizedValue === "true" } @@ -282,7 +358,7 @@ export const validateEnrichFeeTokens = (enrichFeeTokens?: string): boolean => { export const generateChainKey = (chainId: number | string, chainType: ChainType, outputKey: OutputKeyType): string => { const chainIdStr = chainId.toString() - if (outputKey === "chainId" && chainType !== "evm" && chainType !== "solana") { + if (outputKey === "chain_id" && chainType !== "evm" && chainType !== "solana") { return `${chainType}-${chainIdStr}` } diff --git a/src/lib/ccip/utils/rate-limit-formatter.ts b/src/lib/ccip/utils/rate-limit-formatter.ts new file mode 100644 index 00000000000..d7431f39f31 --- /dev/null +++ b/src/lib/ccip/utils/rate-limit-formatter.ts @@ -0,0 +1,72 @@ +import type { RateLimiterConfig } from "~/lib/ccip/types/index.ts" + +/** + * Formats a rate limit value from wei to tokens + * @param value - Rate limit value in wei (as string) + * @returns Formatted string with proper number formatting + */ +export function formatRateLimit(value: string | null | undefined): string { + if (!value || value === "0") return "0" + + try { + // Convert from wei to tokens (divide by 1e18) + const numValue = BigInt(value) + const formatted = Number(numValue) / 1e18 + return formatted.toLocaleString(undefined, { maximumFractionDigits: 2 }) + } catch (error) { + console.error("Error formatting rate limit:", error) + return "0" + } +} + +/** + * Checks if a token is paused based on rate limit configuration + * A token is considered paused if the capacity is "0" + * @param rateLimit - Rate limiter configuration + * @returns True if token is paused + */ +export function isTokenPaused(rateLimit: RateLimiterConfig | null | undefined): boolean { + return rateLimit?.capacity === "0" +} + +/** + * Gets display value for a rate limit + * @param rateLimit - Rate limiter configuration + * @param isLoading - Whether data is still loading + * @returns Display string for the rate limit + */ +export function getRateLimitDisplay(rateLimit: RateLimiterConfig | null | undefined, isLoading: boolean): string { + if (isLoading) return "Loading..." + if (!rateLimit) return "N/A" + if (!rateLimit.isEnabled) return "Disabled" + return formatRateLimit(rateLimit.capacity) +} + +/** + * Gets display value for a rate limit capacity + * @param rateLimit - Rate limiter configuration + * @param isLoading - Whether data is still loading + * @returns Display string for capacity + */ +export function getRateLimitCapacityDisplay( + rateLimit: RateLimiterConfig | null | undefined, + isLoading: boolean +): string { + if (isLoading) return "Loading..." + if (!rateLimit) return "Unavailable" + if (!rateLimit.isEnabled) return "Disabled" + return formatRateLimit(rateLimit.capacity) +} + +/** + * Gets display value for a rate limit refill rate + * @param rateLimit - Rate limiter configuration + * @param isLoading - Whether data is still loading + * @returns Display string for refill rate + */ +export function getRateLimitRateDisplay(rateLimit: RateLimiterConfig | null | undefined, isLoading: boolean): string { + if (isLoading) return "Loading..." + if (!rateLimit) return "N/A" + if (!rateLimit.isEnabled) return "Disabled" + return formatRateLimit(rateLimit.rate) +} diff --git a/src/lib/codeSample/language.ts b/src/lib/codeSample/language.ts new file mode 100644 index 00000000000..24e4c3b3313 --- /dev/null +++ b/src/lib/codeSample/language.ts @@ -0,0 +1,25 @@ +export function languageBadge(language: string): string { + const l = language.toLowerCase() + if (l === "solidity" || l === "sol") return "SOL" + if (["javascript", "js", "mjs", "cjs"].includes(l)) return "JS" + if (["typescript", "ts", "mts", "cts"].includes(l)) return "TS" + if (["bash", "sh", "shell"].includes(l)) return "SH" + if (l === "go" || l === "golang") return "GO" + if (l === "json" || l === "jsonc") return "JSON" + if (l === "yaml" || l === "yml") return "YAML" + return l.slice(0, 4).toUpperCase() +} + +export function getLanguageIconSrc(language: string): string | undefined { + const l = language.toLowerCase() + // Map language names/aliases to icons in `public/images/language-icons/`. + if (l === "solidity" || l === "sol") return "/images/language-icons/solidity.svg" + if (["typescript", "ts", "mts", "cts"].includes(l)) return "/images/language-icons/typescript.svg" + if (["go", "golang"].includes(l)) return "/images/language-icons/go.svg" + if (["json", "jsonc"].includes(l)) return "/images/language-icons/json.svg" + if (l === "toml") return "/images/language-icons/toml.svg" + if (["python", "py"].includes(l)) return "/images/language-icons/python.svg" + if (["rust", "rs"].includes(l)) return "/images/language-icons/rust.svg" + if (["bash", "sh", "shell", "zsh", "terminal"].includes(l)) return "/images/language-icons/terminal.svg" + return undefined +} diff --git a/src/lib/index.ts b/src/lib/index.ts index 849fff2d239..03aced06021 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1 +1,2 @@ export * from "./clsx/clsx.ts" +export * from "./markdown/index.js" diff --git a/src/lib/languageStore.ts b/src/lib/languageStore.ts index 56ca8b34e26..0fc11a0d972 100644 --- a/src/lib/languageStore.ts +++ b/src/lib/languageStore.ts @@ -5,5 +5,5 @@ export type SupportedLanguage = "go" | "ts" // Store with localStorage persistence export const selectedLanguage = persistentAtom<SupportedLanguage>( "docs-language-preference", - "go" // default value + "ts" // default value ) diff --git a/src/lib/markdown/__tests__/formatters.test.ts b/src/lib/markdown/__tests__/formatters.test.ts new file mode 100644 index 00000000000..71299614d33 --- /dev/null +++ b/src/lib/markdown/__tests__/formatters.test.ts @@ -0,0 +1,359 @@ +/** + * Tests for shared markdown formatting utilities + * These are pure functions used by both build-time (generate-llms.ts) + * and runtime (CopyPageLink) markdown generation + */ + +import { describe, it, expect } from "@jest/globals" +import { + formatHeading, + formatLink, + formatBold, + formatItalic, + formatInlineCode, + formatCodeBlock, + formatBlockquote, + formatTable, + formatImage, + formatHorizontalRule, + formatUnorderedList, + formatOrderedList, + formatFrontmatter, + cleanText, + normalizeMarkdown, + unescapeMarkdown, + stripHighlightComments, + resolveUrl, +} from "../formatters.js" + +describe("Heading Formatters", () => { + it("should format h1 correctly", () => { + expect(formatHeading(1, "Title")).toBe("# Title\n\n") + }) + + it("should format h2 correctly", () => { + expect(formatHeading(2, "Subtitle")).toBe("## Subtitle\n\n") + }) + + it("should format h3-h6 correctly", () => { + expect(formatHeading(3, "Section")).toBe("### Section\n\n") + expect(formatHeading(4, "Subsection")).toBe("#### Subsection\n\n") + expect(formatHeading(5, "Minor")).toBe("##### Minor\n\n") + expect(formatHeading(6, "Smallest")).toBe("###### Smallest\n\n") + }) + + it("should handle empty headings", () => { + expect(formatHeading(1, "")).toBe("# \n\n") + }) +}) + +describe("Inline Formatters", () => { + it("should format links", () => { + expect(formatLink("Click here", "https://example.com")).toBe("[Click here](https://example.com)") + }) + + it("should format bold text", () => { + expect(formatBold("important")).toBe("**important**") + }) + + it("should format italic text", () => { + expect(formatItalic("emphasis")).toBe("*emphasis*") + }) + + it("should format inline code", () => { + expect(formatInlineCode("const x = 1")).toBe("`const x = 1`") + }) +}) + +describe("Code Block Formatter", () => { + it("should format code block with language", () => { + const code = "function test() {\n return true\n}" + const result = formatCodeBlock(code, "javascript") + expect(result).toBe("```javascript\nfunction test() {\n return true\n}\n```\n\n") + }) + + it("should format code block without language", () => { + const code = "plain text" + const result = formatCodeBlock(code) + expect(result).toBe("```\nplain text\n```\n\n") + }) + + it("should handle empty code blocks", () => { + expect(formatCodeBlock("")).toBe("```\n\n```\n\n") + }) +}) + +describe("Table Formatter", () => { + it("should format table with header", () => { + const rows = [ + ["Name", "Age"], + ["Alice", "30"], + ["Bob", "25"], + ] + const result = formatTable(rows) + + expect(result).toContain("| Name | Age |") + expect(result).toContain("| --- | --- |") + expect(result).toContain("| Alice | 30 |") + expect(result).toContain("| Bob | 25 |") + expect(result.endsWith("\n")).toBe(true) + }) + + it("should format table without header", () => { + const rows = [ + ["A", "B"], + ["C", "D"], + ] + const result = formatTable(rows, false) + + expect(result).toContain("| A | B |") + expect(result).toContain("| C | D |") + expect(result).not.toContain("| --- | --- |") + }) + + it("should handle single row table", () => { + const rows = [["Single", "Row"]] + const result = formatTable(rows) + + expect(result).toContain("| Single | Row |") + expect(result).toContain("| --- | --- |") + }) + + it("should handle empty table", () => { + expect(formatTable([])).toBe("") + }) +}) + +describe("List Formatters", () => { + it("should format unordered list", () => { + const items = ["First item", "Second item", "Third item"] + const result = formatUnorderedList(items) + + expect(result).toBe("- First item\n- Second item\n- Third item\n\n") + }) + + it("should format ordered list", () => { + const items = ["First", "Second", "Third"] + const result = formatOrderedList(items) + + expect(result).toBe("1. First\n2. Second\n3. Third\n\n") + }) + + it("should handle empty lists", () => { + expect(formatUnorderedList([])).toBe("\n\n") + expect(formatOrderedList([])).toBe("\n\n") + }) +}) + +describe("Other Formatters", () => { + it("should format blockquote", () => { + const result = formatBlockquote("Important note\nSecond line") + expect(result).toBe("> Important note\n> Second line\n\n") + }) + + it("should format horizontal rule", () => { + expect(formatHorizontalRule()).toBe("---\n\n") + }) + + it("should format image", () => { + expect(formatImage("Alt text", "/path/to/image.png")).toBe("![Alt text](/path/to/image.png)") + }) + + it("should format image with title", () => { + expect(formatImage("Alt", "/img.png", "Title")).toBe('![Alt](/img.png "Title")') + }) +}) + +describe("Frontmatter Formatter", () => { + it("should format frontmatter with simple values", () => { + const data = { + title: "Test Page", + url: "https://example.com", + extracted: "2024-01-01T00:00:00.000Z", + } + const result = formatFrontmatter(data) + + expect(result).toContain("---") + expect(result).toContain("title: Test Page") + // URLs with colons get quoted (correct YAML behavior) + expect(result).toContain('url: "https://example.com"') + expect(result).toContain('extracted: "2024-01-01T00:00:00.000Z"') + expect(result.endsWith("\n\n")).toBe(true) + }) + + it("should quote strings with special YAML characters", () => { + const data = { + title: "Title: With Colon", + description: "Has # hash", + } + const result = formatFrontmatter(data) + + expect(result).toContain('title: "Title: With Colon"') + expect(result).toContain('description: "Has # hash"') + }) + + it("should handle boolean and number values", () => { + const data = { + published: true, + count: 42, + } + const result = formatFrontmatter(data) + + expect(result).toContain("published: true") + expect(result).toContain("count: 42") + }) +}) + +describe("Text Utilities", () => { + it("should clean text with encoding issues", () => { + expect(cleanText("’")).toBe("'") + expect(cleanText("“test â€")).toBe('"test "') + }) + + it("should normalize whitespace", () => { + expect(cleanText(" hello world ")).toBe("hello world") + expect(cleanText("test\n\n\nmore")).toBe("test more") + }) + + it("should remove zero-width characters", () => { + expect(cleanText("test\u200B\u200C\u200Dtext")).toBe("testtext") + // BOM character gets normalized to space by whitespace normalization + expect(cleanText("hello\uFEFFworld")).toBe("hello world") + }) + + it("should handle smart quotes", () => { + // Left/right single quotes → straight apostrophes + expect(cleanText("\u2018test\u2019")).toBe("'test'") + // Left/right double quotes → straight quotes + expect(cleanText("\u201Ctest\u201D")).toBe('"test"') + }) +}) + +describe("Markdown Normalization", () => { + it("should normalize line endings", () => { + const markdown = "Line 1\r\nLine 2\r\nLine 3" + expect(normalizeMarkdown(markdown)).toBe("Line 1\nLine 2\nLine 3") + }) + + it("should normalize multiple blank lines", () => { + const markdown = "Paragraph 1\n\n\n\nParagraph 2" + expect(normalizeMarkdown(markdown)).toBe("Paragraph 1\n\nParagraph 2") + }) + + it("should normalize list markers", () => { + const markdown = "* Item 1\n+ Item 2\n- Item 3" + expect(normalizeMarkdown(markdown)).toBe("- Item 1\n- Item 2\n- Item 3") + }) + + it("should trim trailing whitespace", () => { + const markdown = "Line with spaces \nAnother line " + const result = normalizeMarkdown(markdown) + expect(result).toBe("Line with spaces\nAnother line") + }) +}) + +describe("Unescape Markdown", () => { + it("should unescape markdown characters outside code blocks", () => { + const text = "Test \\_underscore\\_ and \\[brackets\\]" + expect(unescapeMarkdown(text)).toBe("Test _underscore_ and [brackets]") + }) + + it("should preserve escaping inside code blocks", () => { + const text = "```\n\\_code\\_\n```" + expect(unescapeMarkdown(text)).toBe("```\n\\_code\\_\n```") + }) + + it("should remove prettier-ignore comments", () => { + const text = "Line 1\n{/* prettier-ignore */}\nLine 2" + expect(unescapeMarkdown(text)).toBe("Line 1\nLine 2") + }) + + it("should handle multiple code blocks", () => { + const text = "Before\n```\ncode1\n```\nMiddle\n```\ncode2\n```\nAfter" + const result = unescapeMarkdown(text) + expect(result).toContain("code1") + expect(result).toContain("code2") + }) +}) + +describe("Strip Highlight Comments", () => { + it("should remove highlight-line comments", () => { + const code = "const x = 1 // highlight-line\nconst y = 2" + expect(stripHighlightComments(code)).toBe("const x = 1\nconst y = 2") + }) + + it("should remove highlight-start and highlight-end", () => { + const code = "line1 // highlight-start\nline2\nline3 // highlight-end" + expect(stripHighlightComments(code)).toBe("line1\nline2\nline3") + }) + + it("should handle mixed whitespace", () => { + const code = "test // highlight-line \nnext" + // Removes comment but preserves leading whitespace on the line + expect(stripHighlightComments(code)).toBe("test \nnext") + }) + + it("should preserve non-highlight comments", () => { + const code = "const x = 1 // regular comment\nconst y = 2 // highlight-line\nconst z = 3 // another comment" + const result = stripHighlightComments(code) + expect(result).toContain("// regular comment") + expect(result).toContain("// another comment") + expect(result).not.toContain("highlight-line") + }) +}) + +describe("URL Resolution", () => { + it("should preserve absolute URLs", () => { + expect(resolveUrl("https://example.com/path", "https://base.com")).toBe("https://example.com/path") + expect(resolveUrl("http://example.com", "https://base.com")).toBe("http://example.com") + }) + + it("should resolve relative URLs with base", () => { + expect(resolveUrl("/path/to/page", "https://example.com")).toBe("https://example.com/path/to/page") + }) + + it("should handle URLs without base (server-side)", () => { + // When window is not defined (Node.js), base defaults to empty string + const result = resolveUrl("https://example.com") + expect(result).toBe("https://example.com") + }) + + it("should handle invalid URLs gracefully", () => { + // If URL constructor fails, return original + const result = resolveUrl("not-a-valid-url", "") + expect(result).toBe("not-a-valid-url") + }) +}) + +describe("Integration Tests", () => { + it("should format a complete markdown document", () => { + const title = formatHeading(1, "Documentation") + const intro = "This is an introduction.\n\n" + const code = formatCodeBlock('console.log("Hello")', "javascript") + const list = formatUnorderedList(["Feature 1", "Feature 2"]) + + const result = title + intro + code + list + + expect(result).toContain("# Documentation") + expect(result).toContain("introduction") + expect(result).toContain("```javascript") + expect(result).toContain("- Feature 1") + }) + + it("should produce consistent output for same input", () => { + const data = { title: "Test", url: "https://test.com" } + + const result1 = formatFrontmatter(data) + const result2 = formatFrontmatter(data) + + expect(result1).toBe(result2) + }) + + it("should handle text cleaning pipeline", () => { + const dirtyText = " ’test “quotes†with spaces " + const cleaned = cleanText(dirtyText) + const normalized = normalizeMarkdown(cleaned) + + expect(normalized).toBe('\'test "quotes" with spaces') + }) +}) diff --git a/src/lib/markdown/__tests__/transformMarkdown.test.ts b/src/lib/markdown/__tests__/transformMarkdown.test.ts new file mode 100644 index 00000000000..b564bc74200 --- /dev/null +++ b/src/lib/markdown/__tests__/transformMarkdown.test.ts @@ -0,0 +1,112 @@ +/** + * Tests for markdown transformation + */ + +import { describe, it, expect } from "@jest/globals" +import { transformMarkdown } from "@lib/markdown/transformMarkdown.js" +import { extractFrontmatter, titleCase, getPageLanguage } from "@lib/markdown/utils.js" + +describe("transformMarkdown", () => { + it("should transform basic markdown", async () => { + const markdown = `# Hello World + +This is a test. + +\`\`\`javascript +console.log("test") +\`\`\` +` + + const result = await transformMarkdown(markdown, "/fake/path.mdx") + expect(result).toContain("# Hello World") + expect(result).toContain("This is a test") + expect(result).toContain("```javascript") + }) + + it("should handle code blocks", async () => { + const markdown = `\`\`\`solidity +contract Test { + // comment +} +\`\`\` +` + + const result = await transformMarkdown(markdown, "/fake/path.mdx") + expect(result).toContain("```solidity") + expect(result).toContain("contract Test") + }) + + it("should preserve links", async () => { + const markdown = `[Link text](/some/path)` + + const result = await transformMarkdown(markdown, "/fake/path.mdx") + expect(result).toContain("[Link text](/some/path)") + }) + + it("should handle tables", async () => { + const markdown = `| Col1 | Col2 | +|------|------| +| A | B |` + + const result = await transformMarkdown(markdown, "/fake/path.mdx") + expect(result).toContain("Col1") + expect(result).toContain("Col2") + }) +}) + +describe("extractFrontmatter", () => { + it("should extract title from frontmatter", () => { + const raw = `--- +title: "Test Page" +--- + +Content here` + + const result = extractFrontmatter(raw) + expect(result.fmTitle).toBe("Test Page") + expect(result.body).toContain("Content here") + }) + + it("should handle missing frontmatter", () => { + const raw = `Content without frontmatter` + + const result = extractFrontmatter(raw) + expect(result.fmTitle).toBeUndefined() + expect(result.body).toBe(raw) + }) + + it("should extract sdkLang from frontmatter", () => { + const raw = `--- +title: "Test" +sdkLang: "go" +--- + +Content` + + const result = extractFrontmatter(raw) + expect(result.sdkLang).toBe("go") + }) +}) + +describe("titleCase", () => { + it("should convert to title case", () => { + expect(titleCase("hello-world")).toBe("Hello World") + expect(titleCase("test_file")).toBe("Test File") + expect(titleCase("already Title")).toBe("Already Title") + }) +}) + +describe("getPageLanguage", () => { + it("should detect language from filename", () => { + expect(getPageLanguage("/path/to/file-go.mdx")).toBe("go") + expect(getPageLanguage("/path/to/file-ts.mdx")).toBe("ts") + }) + + it("should return frontmatter language if present", () => { + expect(getPageLanguage("/path/to/file.mdx", "typescript")).toBe("typescript") + }) + + it("should return null for common files", () => { + expect(getPageLanguage("/path/to/file.mdx")).toBeNull() + }) +}) diff --git a/src/lib/markdown/componentHandlers.ts b/src/lib/markdown/componentHandlers.ts new file mode 100644 index 00000000000..47cd21c125f --- /dev/null +++ b/src/lib/markdown/componentHandlers.ts @@ -0,0 +1,526 @@ +/** + * Handlers for custom MDX components + */ + +import fs from "fs" +import path from "path" +import type { Parent, Literal, Node } from "unist" +import type { MdxJsxNode, ComponentContext } from "./types.js" +import { + calculateNetworkFeesForTokenMechanismDirect, + calculateMessagingNetworkFeesDirect, + TokenMechanism, +} from "../../config/data/ccip/index.js" + +/** + * Load CcipCommon callout mapping dynamically from CcipCommon.astro + * @returns Mapping of callout names to file paths + */ +export function loadCcipCommonMapping(): Record<string, string> { + try { + const astroFilePath = path.resolve("src/features/ccip/CcipCommon.astro") + const astroContent = fs.readFileSync(astroFilePath, "utf-8") + + // First, build a map of Component names to file paths from imports + const importRegex = /import\s+(\w+)\s+from\s+["'](.+?)["']/g + const componentToFile: Record<string, string> = {} + + for (const match of astroContent.matchAll(importRegex)) { + const [, componentName, filePath] = match + const cleanPath = filePath.replace(/^\.\//, "") + componentToFile[componentName] = cleanPath + } + + // Then, parse the conditional statements to map callout names to component names + const conditionalRegex = /callout\s+===\s+["'](\w+)["']\s+&&\s+<(\w+)/g + const mapping: Record<string, string> = {} + + for (const match of astroContent.matchAll(conditionalRegex)) { + const [, calloutName, componentName] = match + const filePath = componentToFile[componentName] + if (filePath) { + mapping[calloutName] = filePath + } + } + + return mapping + } catch (e) { + console.warn("Failed to load CcipCommon mapping:", e) + return {} + } +} + +/** + * Handle CcipCommon component - inline the referenced markdown content + * @param node - AST node + * @param parent - Parent node + * @param index - Index in parent's children + * @param context - Component context + * @returns New index or void + */ +export function handleCcipCommon( + node: MdxJsxNode, + parent: Parent, + index: number, + context: ComponentContext +): number | void { + try { + const calloutAttr = node.attributes?.find((a) => a.name === "callout") + const calloutValue = typeof calloutAttr?.value === "string" ? calloutAttr.value : undefined + + if (calloutValue) { + // Load mapping dynamically from CcipCommon.astro + const calloutFileMap = loadCcipCommonMapping() + const fileName = calloutFileMap[calloutValue] + + if (fileName) { + const calloutPath = path.resolve("src/features/ccip", fileName) + + if (fs.existsSync(calloutPath)) { + let calloutContent = fs.readFileSync(calloutPath, "utf-8") + + // Strip frontmatter if present + if (calloutContent.trim().startsWith("---")) { + calloutContent = calloutContent.replace(/^---\s*\n[\s\S]*?\n---\s*\n/, "") + } + + // Strip import statements + calloutContent = calloutContent.replace(/^import\s+.+$/gm, "").trim() + + // Parse the callout markdown and insert it + const calloutTree = context.processor.parse(calloutContent) + if (calloutTree && calloutTree.children) { + parent.children.splice(index, 1, ...calloutTree.children) + return index + calloutTree.children.length + } + } + } + } + } catch (e) { + console.warn(`Failed to process CcipCommon in ${context.mdxAbsPath}:`, e) + } +} + +/** + * Handle CodeHighlightBlock component - inline imported code + * @param node - AST node + * @param parent - Parent node + * @param index - Index in parent's children + * @param context - Component context + * @returns New index or void + */ +export function handleCodeHighlightBlock( + node: MdxJsxNode, + parent: Parent, + index: number, + context: ComponentContext +): number | void { + try { + const codeVarAttr = node.attributes?.find((a) => a.name === "code") + const codeVarName = (codeVarAttr?.value as { data?: { estree?: { body?: { expression?: { name?: string } }[] } } }) + ?.data?.estree?.body?.[0]?.expression?.name + + if (codeVarName) { + const importRegex = new RegExp(`import\\s+${codeVarName}\\s+from\\s+['"](.+?)['"]`) + const match = context.markdown.match(importRegex) + + if (match) { + const importPath = match[1].split("?")[0] // Strip "?raw" and other query params + const codeAbsPath = path.resolve(path.dirname(context.mdxAbsPath), importPath) + let codeContent = fs.readFileSync(codeAbsPath, "utf-8") + + // Strip highlighter comments + codeContent = codeContent + .split("\n") + .map((line) => line.replace(/\s*\/\/\s*highlight-(line|start|end)/, "")) + .join("\n") + + const langAttr = node.attributes?.find((a) => a.name === "lang") + const titleAttr = node.attributes?.find((a) => a.name === "title") + + const newNodes: Node[] = [] + + if (titleAttr) { + const title = `Code snippet for ${titleAttr.value}:` + newNodes.push({ type: "paragraph", children: [{ type: "text", value: title } as Literal] } as Parent) + } + + newNodes.push({ + type: "code", + lang: langAttr?.value || "", + value: codeContent.trim(), + } as Literal) + + parent.children.splice(index, 1, ...newNodes) + return index + newNodes.length + } + } + } catch (e) { + console.warn(`Failed to process CodeHighlightBlock in ${context.mdxAbsPath}:`, e) + } +} + +/** + * Handle CodeHighlightBlockMulti component - inline language-specific code + * @param node - AST node + * @param parent - Parent node + * @param index - Index in parent's children + * @param context - Component context + * @returns New index or void + */ +export function handleCodeHighlightBlockMulti( + node: MdxJsxNode, + parent: Parent, + index: number, + context: ComponentContext +): number | void { + try { + const languagesAttr = node.attributes?.find((a) => a.name === "languages") + + if (languagesAttr && context.targetLanguage) { + // Extract the code variable name for the target language + // The structure is: languages={{ go: { code: goVar }, ts: { code: tsVar } }} + const attrValue = languagesAttr.value + const estreeBody = + typeof attrValue === "object" && attrValue && "data" in attrValue + ? attrValue.data?.estree?.body?.[0] + : undefined + const languagesObj = + estreeBody && typeof estreeBody === "object" && "expression" in estreeBody + ? (estreeBody.expression as { properties?: unknown })?.properties + : undefined + + if (languagesObj) { + for (const langProp of languagesObj as Record<string, unknown>[]) { + const langKey = + (langProp.key as { name?: string; value?: string })?.name || + (langProp.key as { name?: string; value?: string })?.value + + if (langKey === context.targetLanguage) { + const codeProperty = (langProp.value as { properties?: Record<string, unknown>[] })?.properties?.find( + (p) => (p.key as { name?: string })?.name === "code" + ) + const codeVarName = (codeProperty?.value as { name?: string })?.name + + if (codeVarName) { + // Find the import statement for this variable + const importRegex = new RegExp(`import\\s+${codeVarName}\\s+from\\s+['"](.+?)['"]`) + const match = context.markdown.match(importRegex) + + if (match) { + const importPath = match[1].split("?")[0] // Strip "?raw" + const codeAbsPath = path.resolve(path.dirname(context.mdxAbsPath), importPath) + let codeContent = fs.readFileSync(codeAbsPath, "utf-8") + + // Strip highlighter comments + codeContent = codeContent + .split("\n") + .map((line) => line.replace(/\s*\/\/\s*highlight-(line|start|end)/, "")) + .join("\n") + + // Infer language from file extension + const fileExt = path.extname(codeAbsPath).slice(1) + const lang = fileExt || context.targetLanguage + + // Create a code block for this language + const newNodes: Node[] = [] + newNodes.push({ + type: "code", + lang, + value: codeContent.trim(), + } as Literal) + + parent.children.splice(index, 1, ...newNodes) + return index + newNodes.length + } + } + break + } + } + } + } + } catch (e) { + console.warn(`Failed to process CodeHighlightBlockMulti in ${context.mdxAbsPath}:`, e) + } +} + +/** + * Handle CopyText component - extract text attribute + * @param node - AST node + * @param parent - Parent node + * @param index - Index in parent's children + * @param context - Component context + * @returns New index or void + */ +export function handleCopyText(node: MdxJsxNode, parent: Parent, index: number): number | void { + const textAttr = node.attributes?.find((a) => a.name === "text") + + if (textAttr?.value) { + const attrValue = textAttr.value + const textValue = + typeof attrValue === "string" + ? attrValue + : typeof attrValue === "object" && attrValue && "value" in attrValue + ? attrValue.value + : "" + + parent.children[index] = { type: "text", value: textValue } as Literal + } +} + +/** + * Handle generic MDX div elements - extract children + * @param node - AST node + * @param parent - Parent node + * @param index - Index in parent's children + * @param context - Component context + * @returns New index or void + */ +export function handleDiv(node: MdxJsxNode, parent: Parent, index: number): number | void { + // Replace the <div> element with just its children + if ((node as Parent).children) { + parent.children.splice(index, 1, ...(node as Parent).children) + return index + } +} + +/** + * Handle Aside component - convert to markdown blockquote + * @param node - AST node + * @param parent - Parent node + * @param index - Index in parent's children + * @param context - Component context + * @returns New index or void + */ +export function handleAside(node: MdxJsxNode, parent: Parent, index: number, context: ComponentContext): number | void { + try { + const typeAttr = node.attributes?.find((a) => a.name === "type") + const titleAttr = node.attributes?.find((a) => a.name === "title") + + const type = typeof typeAttr?.value === "string" ? typeAttr.value.toUpperCase() : "NOTE" + const title = typeof titleAttr?.value === "string" ? titleAttr.value : "" + + // Get children content + const children = (node as Parent).children || [] + + if (children.length === 0) { + return + } + + // Create blockquote header + const header = title ? `**${type}: ${title}**` : `**${type}**` + + // Create new nodes for blockquote + const newNodes: Node[] = [] + + // Add blockquote paragraph with header + newNodes.push({ + type: "blockquote", + children: [ + { + type: "paragraph", + children: [{ type: "text", value: header } as Literal], + } as Parent, + { + type: "paragraph", + children: [{ type: "text", value: "" } as Literal], + } as Parent, + ...children, + ], + } as Parent) + + parent.children.splice(index, 1, ...newNodes) + return index + newNodes.length + } catch (e) { + console.warn(`Failed to process Aside in ${context.mdxAbsPath}:`, e) + } +} + +/** + * Handle ClickToZoom component - convert to markdown image + * @param node - AST node + * @param parent - Parent node + * @param index - Index in parent's children + * @param context - Component context + * @returns New index or void + */ +export function handleClickToZoom( + node: MdxJsxNode, + parent: Parent, + index: number, + context: ComponentContext +): number | void { + try { + const srcAttr = node.attributes?.find((a) => a.name === "src") + const altAttr = node.attributes?.find((a) => a.name === "alt") + + const src = typeof srcAttr?.value === "string" ? srcAttr.value : "" + const alt = typeof altAttr?.value === "string" ? altAttr.value : "Image" + + if (!src) return + + // Create markdown image node + parent.children[index] = { + type: "image", + url: src, + alt, + } as Literal & { url: string; alt: string } + } catch (e) { + console.warn(`Failed to process ClickToZoom in ${context.mdxAbsPath}:`, e) + } +} + +/** + * Handle CodeSample component - generate Remix link or inline code + * @param node - AST node + * @param parent - Parent node + * @param index - Index in parent's children + * @param context - Component context + * @returns New index or void + */ +export function handleCodeSample( + node: MdxJsxNode, + parent: Parent, + index: number, + context: ComponentContext +): number | void { + try { + const srcAttr = node.attributes?.find((a) => a.name === "src") + const showButtonOnlyAttr = node.attributes?.find((a) => a.name === "showButtonOnly") + + const src = typeof srcAttr?.value === "string" ? srcAttr.value : "" + + // showButtonOnly is a boolean attribute - check for its presence or explicit value + let showButtonOnly = false + if (showButtonOnlyAttr) { + if ( + typeof showButtonOnlyAttr.value === "object" && + showButtonOnlyAttr.value && + "value" in showButtonOnlyAttr.value + ) { + showButtonOnly = Boolean(showButtonOnlyAttr.value.value) + } else if (showButtonOnlyAttr.value === undefined || showButtonOnlyAttr.value === null) { + // Attribute present without value means true + showButtonOnly = true + } + } + + if (!src) return + + if (showButtonOnly) { + // Generate Remix link + const fileName = path.basename(src) + const remixUrl = `https://remix.ethereum.org/#url=https://docs.chain.link/${src}` + + parent.children[index] = { + type: "paragraph", + children: [ + { + type: "link", + url: remixUrl, + children: [{ type: "text", value: `Open ${fileName} in Remix` } as Literal], + } as Parent & { url: string }, + ], + } as Parent + } else { + // Try to inline the code + const publicPath = path.join(process.cwd(), "public", src) + const possiblePaths = [publicPath, path.resolve(src), path.join(process.cwd(), "src", src)] + + let codeContent: string | null = null + for (const p of possiblePaths) { + if (fs.existsSync(p)) { + codeContent = fs.readFileSync(p, "utf-8") + break + } + } + + if (codeContent) { + // Detect language from file extension + const ext = path.extname(src).slice(1) + const lang = ext || "text" + + parent.children[index] = { + type: "code", + lang, + value: codeContent.trim(), + } as Literal & { lang: string } + } else { + // Fallback to link if file not found + const fileName = path.basename(src) + parent.children[index] = { + type: "paragraph", + children: [ + { + type: "text", + value: `Code sample: ${fileName} (file not found at build time)`, + } as Literal, + ], + } as Parent + } + } + } catch (e) { + console.warn(`Failed to process CodeSample in ${context.mdxAbsPath}:`, e) + } +} + +/** + * Handle Billing component - generate markdown table with CCIP network fees + * @param node - AST node + * @param parent - Parent node + * @param index - Index in parent's children + * @param context - Component context + * @returns New index or void + */ +export function handleBilling( + node: MdxJsxNode, + parent: Parent, + index: number, + context: ComponentContext +): number | void { + try { + // Calculate fees using the same logic as Billing.astro + const lockAndUnlockAllLanes = calculateNetworkFeesForTokenMechanismDirect(TokenMechanism.LockAndUnlock, "allLanes") + const restFromEthereum = calculateNetworkFeesForTokenMechanismDirect(TokenMechanism.BurnAndMint, "fromEthereum") + const restToEthereum = calculateNetworkFeesForTokenMechanismDirect(TokenMechanism.BurnAndMint, "toEthereum") + const restMechanismNonEthereum = calculateNetworkFeesForTokenMechanismDirect( + TokenMechanism.BurnAndMint, + "nonEthereum" + ) + const messagingFeesFromToEthereum = calculateMessagingNetworkFeesDirect("fromToEthereum") + const messagingFeesNonEthereum = calculateMessagingNetworkFeesDirect("nonEthereum") + + // Generate markdown table + const tableRows = [ + "| Use case | Token Pool Mechanism | Lanes | LINK | Others |", + "|----------|----------------------|-------|------|--------|", + `| Token Transfers / Programmable Token Transfers | Lock and Unlock | All Lanes | ${lockAndUnlockAllLanes.linkFee} | ${lockAndUnlockAllLanes.gasTokenFee} |`, + `| Token Transfers / Programmable Token Transfers | Lock and Mint / Burn and Mint / Burn and Unlock | Non-Ethereum | ${restMechanismNonEthereum.linkFee} | ${restMechanismNonEthereum.gasTokenFee} |`, + `| Token Transfers / Programmable Token Transfers | Lock and Mint / Burn and Mint / Burn and Unlock | From: Ethereum | ${restFromEthereum.linkFee} | ${restFromEthereum.gasTokenFee} |`, + `| Token Transfers / Programmable Token Transfers | Lock and Mint / Burn and Mint / Burn and Unlock | To: Ethereum | ${restToEthereum.linkFee} | ${restToEthereum.gasTokenFee} |`, + `| Messaging | N/A | Non-Ethereum | ${messagingFeesNonEthereum.linkFee} | ${messagingFeesNonEthereum.gasTokenFee} |`, + `| Messaging | N/A | From/To: Ethereum | ${messagingFeesFromToEthereum.linkFee} | ${messagingFeesFromToEthereum.gasTokenFee} |`, + ] + + const markdownTable = tableRows.join("\n") + + // Parse the table markdown and insert it + const tableTree = context.processor.parse(markdownTable) + if (tableTree && tableTree.children) { + parent.children.splice(index, 1, ...tableTree.children) + return index + tableTree.children.length + } + } catch (e) { + console.warn(`Failed to process Billing in ${context.mdxAbsPath}:`, e) + // Fallback: replace with a note about the table + parent.children[index] = { + type: "paragraph", + children: [ + { + type: "text", + value: "(Network fee table - see https://docs.chain.link/ccip/billing for details)", + } as Literal, + ], + } as Parent + } +} diff --git a/src/lib/markdown/formatters.ts b/src/lib/markdown/formatters.ts new file mode 100644 index 00000000000..73161aa8a4b --- /dev/null +++ b/src/lib/markdown/formatters.ts @@ -0,0 +1,240 @@ +/** + * Shared markdown formatting utilities + * Used by both build-time (generate-llms.ts) and runtime (CopyPageLink) markdown generation + */ + +/** + * Format a heading at the specified level + */ +export function formatHeading(level: 1 | 2 | 3 | 4 | 5 | 6, text: string): string { + const hashes = "#".repeat(level) + return `${hashes} ${text}\n\n` +} + +/** + * Format a link + */ +export function formatLink(text: string, url: string): string { + return `[${text}](${url})` +} + +/** + * Format bold text + */ +export function formatBold(text: string): string { + return `**${text}**` +} + +/** + * Format italic text + */ +export function formatItalic(text: string): string { + return `*${text}*` +} + +/** + * Format inline code + */ +export function formatInlineCode(text: string): string { + return `\`${text}\`` +} + +/** + * Format a code block with optional language + */ +export function formatCodeBlock(code: string, language = ""): string { + return `\`\`\`${language}\n${code}\n\`\`\`\n\n` +} + +/** + * Format a blockquote + */ +export function formatBlockquote(text: string): string { + const lines = text.split("\n").filter((line) => line.trim()) + return lines.map((line) => `> ${line}`).join("\n") + "\n\n" +} + +/** + * Format a horizontal rule + */ +export function formatHorizontalRule(): string { + return "---\n\n" +} + +/** + * Format an unordered list + */ +export function formatUnorderedList(items: string[]): string { + return items.map((item) => `- ${item}`).join("\n") + "\n\n" +} + +/** + * Format an ordered list + */ +export function formatOrderedList(items: string[]): string { + return items.map((item, index) => `${index + 1}. ${item}`).join("\n") + "\n\n" +} + +/** + * Format a markdown table + * @param rows - Array of rows, where each row is an array of cell values + * @param hasHeader - Whether the first row should be treated as a header (default: true) + */ +export function formatTable(rows: string[][], hasHeader = true): string { + if (rows.length === 0) return "" + + let markdown = "" + const firstRow = rows[0] + + // Header row + markdown += `| ${firstRow.join(" | ")} |\n` + + // Separator row + if (hasHeader) { + markdown += `| ${firstRow.map(() => "---").join(" | ")} |\n` + } + + // Data rows (skip first if it's a header) + const dataRows = hasHeader ? rows.slice(1) : rows + dataRows.forEach((row) => { + // Pad rows to match header length + const paddedRow = [...row] + while (paddedRow.length < firstRow.length) { + paddedRow.push("") + } + markdown += `| ${paddedRow.join(" | ")} |\n` + }) + + return `${markdown}\n` +} + +/** + * Format an image + */ +export function formatImage(alt: string, src: string, title?: string): string { + const titlePart = title ? ` "${title}"` : "" + return `![${alt}](${src}${titlePart})` +} + +/** + * Format YAML frontmatter + */ +export function formatFrontmatter(data: Record<string, string | number | boolean>): string { + const lines = ["---"] + + for (const [key, value] of Object.entries(data)) { + if (typeof value === "string" && (value.includes(":") || value.includes("#"))) { + // Quote strings that contain special YAML characters + lines.push(`${key}: "${value}"`) + } else if (typeof value === "string") { + lines.push(`${key}: ${value}`) + } else { + lines.push(`${key}: ${value}`) + } + } + + lines.push("---", "", "") + return lines.join("\n") +} + +/** + * Clean and normalize text content + * Fixes common encoding issues and normalizes whitespace + */ +export function cleanText(text: string): string { + return ( + text + // Fix common encoding issues + .replace(/’/g, "'") + .replace(/“/g, '"') + .replace(/â€/g, '"') + .replace(/…/g, "...") + .replace(/â€"/g, "—") + .replace(/â€"/g, "–") + // Also handle actual smart quotes (using Unicode escapes for clarity) + .replace(/[\u2018\u2019]/g, "'") // ' and ' + .replace(/[\u201C\u201D]/g, '"') // " and " + // Normalize whitespace + .replace(/\s+/g, " ") + .replace(/\n\s+\n/g, "\n\n") + // Remove zero-width characters + .replace(/[\u200B-\u200D\uFEFF]/g, "") + .trim() + ) +} + +/** + * Normalize markdown for comparison/consistency + * Useful for testing that different markdown generators produce similar output + */ +export function normalizeMarkdown(markdown: string): string { + return ( + markdown + // Normalize line endings + .replace(/\r\n/g, "\n") + // Normalize multiple blank lines to single blank line + .replace(/\n{3,}/g, "\n\n") + // Normalize whitespace at end of lines + .replace(/[ \t]+$/gm, "") + // Normalize list markers + .replace(/^[*+-]\s+/gm, "- ") + .trim() + ) +} + +/** + * Unescape markdown characters for plain text + * Useful when generating markdown that will be read as plain text + */ +export function unescapeMarkdown(text: string): string { + let inFence = false + return text + .split("\n") + .map((line) => { + const trimmed = line.trim() + if (trimmed.startsWith("```") || trimmed.startsWith("~~~")) { + inFence = !inFence + return line + } + if (inFence) return line + return line + .replace(/\\_/g, "_") + .replace(/\\\[/g, "[") + .replace(/\\\]/g, "]") + .replace(/\\\(/g, "(") + .replace(/\\\)/g, ")") + }) + .filter((line) => line.trim() !== "{/* prettier-ignore */}") + .join("\n") +} + +/** + * Strip highlighter comments from code + * Removes // highlight-line, // highlight-start, // highlight-end + */ +export function stripHighlightComments(code: string): string { + return code + .split("\n") + .map((line) => line.replace(/ *\/\/\s*highlight-(line|start|end)/, "")) + .join("\n") +} + +/** + * Resolve relative URL to absolute URL + */ +export function resolveUrl(url: string, baseUrl = typeof window !== "undefined" ? window.location.origin : ""): string { + if (url.startsWith("http://") || url.startsWith("https://")) { + return url + } + + if (url.startsWith("/")) { + return `${baseUrl}${url}` + } + + // For relative URLs, try to resolve them + try { + return new URL(url, baseUrl).href + } catch { + return url + } +} diff --git a/src/lib/markdown/index.ts b/src/lib/markdown/index.ts new file mode 100644 index 00000000000..f3342c8a4fa --- /dev/null +++ b/src/lib/markdown/index.ts @@ -0,0 +1,6 @@ +/** + * Markdown utilities for Chainlink documentation + * Shared between build-time and runtime markdown generation + */ + +export * from "./formatters.js" diff --git a/src/lib/markdown/rehypeCodeSampleFences.ts b/src/lib/markdown/rehypeCodeSampleFences.ts new file mode 100644 index 00000000000..4d2cc70fa69 --- /dev/null +++ b/src/lib/markdown/rehypeCodeSampleFences.ts @@ -0,0 +1,141 @@ +import { visit } from "unist-util-visit" + +import { getLanguageIconSrc, languageBadge } from "../codeSample/language.js" + +function toCamelCaseDataAttr(attr: string): string { + // "data-filename" -> "dataFilename" + return attr.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase()) +} + +function getProp(node: any, attr: string): unknown { + if (!node?.properties) return undefined + return node.properties[attr] ?? node.properties[toCamelCaseDataAttr(attr)] +} + +function deleteProp(node: any, attr: string): void { + if (!node?.properties) return + delete node.properties[attr] + delete node.properties[toCamelCaseDataAttr(attr)] +} + +function normalizeClassName(className: unknown): string[] { + if (!className) return [] + if (Array.isArray(className)) return className.map(String) + return String(className) + .split(/\s+/) + .map((c) => c.trim()) + .filter(Boolean) +} + +/** + * Convert `.code-sample[data-filename]` wrappers (created in remark) into full + * CodeSample-style blocks by inserting the header markup and adjusting the + * contained `<pre>` for shared styling + copy-button behavior. + */ +export default function rehypeCodeSampleFences() { + return (tree: unknown) => { + visit(tree as any, "element", (node: any, index: number | undefined, parent: any) => { + if (!node || node.tagName !== "div") return + + const classes = normalizeClassName(node.properties?.className) + if (!classes.includes("code-sample")) return + + const filenameRaw = getProp(node, "data-filename") + const filename = typeof filenameRaw === "string" ? filenameRaw.trim() : "" + if (!filename) return + + // Avoid double-inserting if this already has a header. + const hasHeader = + Array.isArray(node.children) && + node.children.some( + (c: any) => + c?.type === "element" && + c?.tagName === "div" && + normalizeClassName(c?.properties?.className).includes("code-sample__header") + ) + if (hasHeader) return + + const preEl = + Array.isArray(node.children) && node.children.find((c: any) => c?.type === "element" && c?.tagName === "pre") + if (!preEl) return + + const languageRaw = getProp(node, "data-language") ?? getProp(preEl, "data-language") + const language = typeof languageRaw === "string" && languageRaw.trim() ? languageRaw.trim() : "text" + const languageKey = language.toLowerCase() + const iconSrc = getLanguageIconSrc(languageKey) + + // Update the <pre> node to match CodeSample behavior + const existing = normalizeClassName(preEl.properties?.className) + preEl.properties = preEl.properties || {} + preEl.properties.className = Array.from( + new Set([...existing, "code-sample__pre", "code-sample__pre--with-header"]) + ) + preEl.properties["data-no-copy-button"] = "" + + const langSpan: any = { + type: "element", + tagName: "span", + properties: { + className: ["code-sample__lang", ...(iconSrc ? ["code-sample__lang--icon"] : [])], + "aria-hidden": "true", + }, + children: iconSrc + ? [ + { + type: "element", + tagName: "img", + properties: { className: ["code-sample__lang-icon"], src: iconSrc, alt: "" }, + children: [], + }, + ] + : [{ type: "text", value: languageBadge(languageKey) }], + } + + const filenameSpan: any = { + type: "element", + tagName: "span", + properties: { className: ["code-sample__filename"], title: filename }, + children: [{ type: "text", value: filename }], + } + + const headerLeft: any = { + type: "element", + tagName: "div", + properties: { className: ["code-sample__header-left"] }, + children: [langSpan, filenameSpan], + } + + const copyButton: any = { + type: "element", + tagName: "button", + properties: { type: "button", className: ["code-sample__copy-button"], "aria-label": "Copy code" }, + children: [ + { + type: "element", + tagName: "img", + properties: { src: "/assets/icons/copyIcon.svg", alt: "Copy code", width: "16", height: "16" }, + children: [], + }, + ], + } + + const header: any = { + type: "element", + tagName: "div", + properties: { className: ["code-sample__header"] }, + children: [headerLeft, copyButton], + } + + const wrapper: any = { + type: "element", + tagName: "div", + properties: { className: ["code-sample"], "data-language": languageKey }, + children: [header, preEl], + } + + // Replace this placeholder wrapper with the full wrapper (keeping only the pre). + // (We intentionally don't preserve `data-filename` in output markup.) + if (parent && typeof index === "number") parent.children[index] = wrapper + }) + } +} diff --git a/src/lib/markdown/remarkCodeFenceFilename.ts b/src/lib/markdown/remarkCodeFenceFilename.ts new file mode 100644 index 00000000000..e1a26b40e93 --- /dev/null +++ b/src/lib/markdown/remarkCodeFenceFilename.ts @@ -0,0 +1,117 @@ +import { visit } from "unist-util-visit" + +import { getLanguageIconSrc, languageBadge } from "../codeSample/language.js" + +const FILENAME_RE = /(?:^|\s)filename\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s]+))/i + +/** + * Wrap fenced code blocks that include `filename="..."` meta in a lightweight + * `.code-sample` container so we can add a CodeSample-like header in rehype + * (after syntax highlighting), while keeping the filename metadata intact. + */ +export default function remarkCodeFenceFilename() { + return (tree: unknown) => { + visit(tree as any, "code", (node: any, index: number | undefined, parent: any) => { + if (!parent || typeof index !== "number") return + + const meta = typeof node?.meta === "string" ? node.meta : "" + if (!meta) return + + const match = meta.match(FILENAME_RE) + if (!match) return + + const filename = String(match[1] || match[2] || match[3] || "").trim() + if (!filename) return + + const language = typeof node.lang === "string" && node.lang.trim() ? node.lang.trim().toLowerCase() : "text" + + const iconSrc = getLanguageIconSrc(language) + const badge = languageBadge(language) + + const langChildren = iconSrc + ? [ + { + type: "mdxJsxFlowElement", + name: "img", + attributes: [ + { type: "mdxJsxAttribute", name: "class", value: "code-sample__lang-icon" }, + { type: "mdxJsxAttribute", name: "src", value: iconSrc }, + { type: "mdxJsxAttribute", name: "alt", value: "" }, + ], + children: [], + }, + ] + : [{ type: "text", value: badge }] + + const header = { + type: "mdxJsxFlowElement", + name: "div", + attributes: [{ type: "mdxJsxAttribute", name: "class", value: "code-sample__header" }], + children: [ + { + type: "mdxJsxFlowElement", + name: "div", + attributes: [{ type: "mdxJsxAttribute", name: "class", value: "code-sample__header-left" }], + children: [ + { + type: "mdxJsxFlowElement", + name: "span", + attributes: [ + { + type: "mdxJsxAttribute", + name: "class", + value: `code-sample__lang${iconSrc ? " code-sample__lang--icon" : ""}`, + }, + { type: "mdxJsxAttribute", name: "aria-hidden", value: "true" }, + ], + children: langChildren, + }, + { + type: "mdxJsxFlowElement", + name: "span", + attributes: [ + { type: "mdxJsxAttribute", name: "class", value: "code-sample__filename" }, + { type: "mdxJsxAttribute", name: "title", value: filename }, + ], + children: [{ type: "text", value: filename }], + }, + ], + }, + { + type: "mdxJsxFlowElement", + name: "button", + attributes: [ + { type: "mdxJsxAttribute", name: "type", value: "button" }, + { type: "mdxJsxAttribute", name: "class", value: "code-sample__copy-button" }, + { type: "mdxJsxAttribute", name: "aria-label", value: "Copy code" }, + ], + children: [ + { + type: "mdxJsxFlowElement", + name: "img", + attributes: [ + { type: "mdxJsxAttribute", name: "src", value: "/assets/icons/copyIcon.svg" }, + { type: "mdxJsxAttribute", name: "alt", value: "Copy code" }, + { type: "mdxJsxAttribute", name: "width", value: "16" }, + { type: "mdxJsxAttribute", name: "height", value: "16" }, + ], + children: [], + }, + ], + }, + ], + } + + parent.children[index] = { + type: "mdxJsxFlowElement", + name: "div", + attributes: [ + { type: "mdxJsxAttribute", name: "class", value: "code-sample" }, + { type: "mdxJsxAttribute", name: "data-language", value: language }, + { type: "mdxJsxAttribute", name: "data-filename", value: filename }, + ], + children: [header, node], + } + }) + } +} diff --git a/src/lib/markdown/transformMarkdown.ts b/src/lib/markdown/transformMarkdown.ts new file mode 100644 index 00000000000..58c20f5da64 --- /dev/null +++ b/src/lib/markdown/transformMarkdown.ts @@ -0,0 +1,285 @@ +/** + * Core markdown transformation using unified/remark pipeline + */ + +import { unified } from "unified" +import remarkParse from "remark-parse" +import remarkMdx from "remark-mdx" +import remarkGfm from "remark-gfm" +import remarkStringify from "remark-stringify" +import { visit } from "unist-util-visit" +import type { Node, Parent, Literal } from "unist" +import type { TransformConfig, MdxJsxNode, ComponentContext } from "./types.js" +import { + handleCcipCommon, + handleCodeHighlightBlock, + handleCodeHighlightBlockMulti, + handleCopyText, + handleDiv, + handleAside, + handleClickToZoom, + handleCodeSample, + handleBilling, + loadCcipCommonMapping, +} from "./componentHandlers.js" +import fs from "fs" +import path from "path" + +/** + * Convert Aside components to markdown blockquotes + * Handles multi-line Aside tags by converting them to blockquote format + * Preserves Asides with nested JSX components (they'll be handled by AST or remain as-is) + * @param content - Markdown content that may contain Aside components + * @returns Content with simple Aside tags converted to blockquotes + */ +function convertAsidesToBlockquotes(content: string): string { + // Match multi-line Aside components + const asideRegex = /<Aside\s+type="(\w+)"(?:\s+title="([^"]*)")?\s*>([\s\S]*?)<\/Aside>/g + + return content.replace(asideRegex, (fullMatch, type, title, children) => { + // Check if the Aside contains other JSX components (like Tabs, CopyText, etc.) + const hasJSXComponents = /<[A-Z]\w+/.test(children) + + if (hasJSXComponents) { + // Keep as-is - these complex nested structures need manual handling + // or will be dropped by the AST handlers + return fullMatch + } + + // Create a blockquote directly in markdown format + // This avoids JSX parsing issues entirely + const cleanChildren = children.trim() + const asideType = type.toUpperCase() + const header = title ? `**${asideType}: ${title}**` : `**${asideType}**` + + // Return as markdown blockquote + return `\n\n> ${header}\n>\n> ${cleanChildren}\n\n` + }) +} + +/** + * Convert ClickToZoom components to markdown images + * Handles self-closing ClickToZoom tags by converting to standard markdown image syntax + * @param content - Markdown content that may contain ClickToZoom components + * @returns Content with ClickToZoom tags converted to markdown images + */ +function convertClickToZoomToImages(content: string): string { + // Match self-closing ClickToZoom tags with any attributes + // Captures src and alt, ignores other attributes like style + const clickToZoomRegex = /<ClickToZoom\s+[^>]*src="([^"]+)"[^>]*(?:alt="([^"]*)")?[^>]*\/>/g + + return content.replace(clickToZoomRegex, (_, src, alt) => { + const altText = alt || "Image" + return `![${altText}](${src})` + }) +} + +/** + * Preprocess CcipCommon components by inlining their content + * This is essential because remarkMdx doesn't always parse self-closing JSX tags properly + * @param markdown - Raw markdown content + * @returns Markdown with CcipCommon components replaced by their content + */ +function preprocessCcipCommon(markdown: string): string { + const ccipCommonRegex = /<CcipCommon\s+callout="(\w+)"\s*\/>/g + let preprocessedMarkdown = markdown + + for (const match of markdown.matchAll(ccipCommonRegex)) { + const [fullMatch, calloutName] = match + const calloutFileMap = loadCcipCommonMapping() + const fileName = calloutFileMap[calloutName] + + if (fileName) { + const calloutPath = path.resolve("src/features/ccip", fileName) + if (fs.existsSync(calloutPath)) { + let calloutContent = fs.readFileSync(calloutPath, "utf-8") + + // Strip frontmatter if present + if (calloutContent.trim().startsWith("---")) { + calloutContent = calloutContent.replace(/^---\s*\n[\s\S]*?\n---\s*\n/, "") + } + + // Strip import statements + calloutContent = calloutContent.replace(/^import\s+.+$/gm, "").trim() + + // Convert Aside components to blockquotes + calloutContent = convertAsidesToBlockquotes(calloutContent) + + // Replace the CcipCommon tag with the processed content + preprocessedMarkdown = preprocessedMarkdown.replace(fullMatch, "\n\n" + calloutContent + "\n\n") + } + } + } + + return preprocessedMarkdown +} + +/** + * Transform markdown content using unified/remark pipeline + * @param markdown - Raw markdown content + * @param mdxAbsPath - Absolute path to the MDX file + * @param config - Transformation configuration + * @returns Transformed markdown string + */ +export async function transformMarkdown( + markdown: string, + mdxAbsPath: string, + config: Partial<TransformConfig> = {} +): Promise<string> { + const { targetLanguage } = config + + // Preprocessing pipeline - apply transformations before AST parsing + // This handles components that remarkMdx struggles to parse (multi-line JSX) + + // Step 1: Preprocess CcipCommon components (inline callout content) + let preprocessedMarkdown = preprocessCcipCommon(markdown) + + // Step 2: Convert Aside components to markdown blockquotes + // Applies to both main content and inlined CcipCommon content + preprocessedMarkdown = convertAsidesToBlockquotes(preprocessedMarkdown) + + // Step 3: Convert ClickToZoom to markdown images + preprocessedMarkdown = convertClickToZoomToImages(preprocessedMarkdown) + + // Create unified processor with remark plugins + const processor = unified() + .use(remarkParse) + .use(remarkMdx) + .use(remarkGfm) + .use(() => (tree: Node) => { + // Create context for component handlers + const context: ComponentContext = { + mdxAbsPath, + markdown, + targetLanguage, + processor, + } + + visit(tree, (node: Node, index: number | undefined, parent: Parent | undefined) => { + if (!parent || typeof index !== "number") return + + // Handle CodeHighlightBlockMulti + if (node.type === "mdxJsxFlowElement" && (node as MdxJsxNode).name === "CodeHighlightBlockMulti") { + return handleCodeHighlightBlockMulti(node as MdxJsxNode, parent, index, context) + } + + // Handle CodeHighlightBlock + if (node.type === "mdxJsxFlowElement" && (node as MdxJsxNode).name === "CodeHighlightBlock") { + return handleCodeHighlightBlock(node as MdxJsxNode, parent, index, context) + } + + // Handle CcipCommon + if (node.type === "mdxJsxFlowElement" && (node as MdxJsxNode).name === "CcipCommon") { + return handleCcipCommon(node as MdxJsxNode, parent, index, context) + } + + // Handle Aside + if (node.type === "mdxJsxFlowElement" && (node as MdxJsxNode).name === "Aside") { + return handleAside(node as MdxJsxNode, parent, index, context) + } + + // Handle ClickToZoom + if (node.type === "mdxJsxFlowElement" && (node as MdxJsxNode).name === "ClickToZoom") { + return handleClickToZoom(node as MdxJsxNode, parent, index, context) + } + + // Handle CodeSample + if (node.type === "mdxJsxFlowElement" && (node as MdxJsxNode).name === "CodeSample") { + return handleCodeSample(node as MdxJsxNode, parent, index, context) + } + + // Handle Billing + if (node.type === "mdxJsxFlowElement" && (node as MdxJsxNode).name === "Billing") { + return handleBilling(node as MdxJsxNode, parent, index, context) + } + + // Handle MDX JSX text elements + if (node.type === "mdxJsxTextElement") { + const nodeName = (node as MdxJsxNode).name + + // Handle CopyText + if (nodeName === "CopyText") { + return handleCopyText(node as MdxJsxNode, parent, index) + } + + // Handle <div> tags (often used for styling in tables) + if (nodeName === "div" && (node as Parent).children) { + return handleDiv(node as MdxJsxNode, parent, index) + } + } + + // Drop MDX/import/export nodes (except handled components) + if ( + (node.type === "mdxJsxFlowElement" && + (node as MdxJsxNode).name !== "Aside" && + (node as MdxJsxNode).name !== "CcipCommon" && + (node as MdxJsxNode).name !== "ClickToZoom" && + (node as MdxJsxNode).name !== "CodeSample" && + (node as MdxJsxNode).name !== "Billing") || + node.type === "mdxjsEsm" || + node.type === "import" || + node.type === "export" + ) { + parent.children.splice(index, 1) + return + } + + // Handle HTML nodes - drop them + if (node.type === "html") { + parent.children.splice(index, 1) + return + } + + // Handle JSX comments - drop them + if ( + (node.type === "mdxFlowExpression" || node.type === "mdxTextExpression") && + typeof (node as { value?: string }).value === "string" && + (node as { value?: string }).value?.trim().match(/^\/\*[\s\S]*?\*\/$/) + ) { + parent.children.splice(index, 1) + return + } + + // Replace images with their alt text + if (node.type === "image") { + const alt = (node as { alt?: string }).alt ? String((node as { alt?: string }).alt) : "Image" + parent.children[index] = { type: "text", value: `(Image: ${alt})` } as Literal + } + + // Note: We preserve link nodes as-is so they're rendered as markdown links [text](url) + }) + }) + .use(remarkStringify, { + fences: true, + bullet: "-", + }) + + const file = await processor.process(preprocessedMarkdown) + let result = String(file) + + // Remove any JSX comments that might have slipped through as text + result = result + .split("\n") + .filter((line) => !line.trim().match(/^{\/\*.*?\*\/}$/)) + .join("\n") + + return result +} + +/** + * Transform a single page to markdown with metadata + * @param mdxContent - Raw MDX content + * @param mdxAbsPath - Absolute path to MDX file + * @param config - Transformation configuration + * @returns Transformed markdown with frontmatter + */ +export async function transformPageToMarkdown( + mdxContent: string, + mdxAbsPath: string, + config: Partial<TransformConfig> = {} +): Promise<string> { + // Transform the markdown + const transformed = await transformMarkdown(mdxContent, mdxAbsPath, config) + + return transformed +} diff --git a/src/lib/markdown/types.ts b/src/lib/markdown/types.ts new file mode 100644 index 00000000000..5362f96a33f --- /dev/null +++ b/src/lib/markdown/types.ts @@ -0,0 +1,112 @@ +/** + * Type definitions for markdown transformation library + */ + +import type { Node, Parent } from "unist" + +/** + * Metadata about a documentation page + */ +export interface PageMetadata { + /** Page title */ + title: string + /** Canonical URL */ + sourceUrl: string + /** Last modified date (ISO string) */ + lastModified?: string + /** Section (e.g., 'ccip', 'vrf') */ + section?: string + /** SDK language (for language-specific pages) */ + sdkLang?: string +} + +/** + * Frontmatter extracted from MDX files + */ +export interface Frontmatter { + /** Raw body content (without frontmatter) */ + body: string + /** Page title from frontmatter */ + fmTitle?: string + /** Last modified date from metadata */ + fmLastModified?: string + /** SDK language */ + sdkLang?: string +} + +/** + * MDX JSX attribute + */ +export interface MdxJsxAttribute { + name: string + value?: string | { value: string } | { data?: { estree?: { body?: unknown[] } } } +} + +/** + * MDX JSX node in the AST + */ +export interface MdxJsxNode extends Node { + name?: string + attributes?: MdxJsxAttribute[] +} + +/** + * Context passed to component handlers + */ +export interface ComponentContext { + /** Absolute path to the MDX file being processed */ + mdxAbsPath: string + /** Original markdown content */ + markdown: string + /** Target language (if any) */ + targetLanguage?: string + /** Unified processor instance */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + processor: any +} + +/** + * Handler function for custom components + */ +export type ComponentHandler = ( + node: MdxJsxNode, + parent: Parent, + index: number, + context: ComponentContext +) => number | void + +/** + * Configuration for markdown transformation + */ +export interface TransformConfig { + /** Base URL for the documentation site */ + siteBase: string + /** Target language for language-specific content */ + targetLanguage?: string + /** Whether to include frontmatter in output */ + includeFrontmatter?: boolean + /** Custom component handlers */ + componentHandlers?: Record<string, ComponentHandler> +} + +/** + * Result of markdown transformation + */ +export interface TransformResult { + /** The transformed markdown content */ + markdown: string + /** Metadata extracted from the page */ + metadata: PageMetadata +} + +/** + * Code block with metadata + */ +export interface CodeBlock { + /** Programming language */ + lang: string + /** Code content */ + value: string + /** Optional title */ + title?: string +} diff --git a/src/lib/markdown/utils.ts b/src/lib/markdown/utils.ts new file mode 100644 index 00000000000..1fad5aaa9d5 --- /dev/null +++ b/src/lib/markdown/utils.ts @@ -0,0 +1,154 @@ +/** + * Utility functions for markdown transformation + */ + +import path from "path" +import type { Frontmatter } from "./types.js" + +/** + * Extract frontmatter from raw MDX content + * @param raw - Raw MDX file content + * @returns Frontmatter data and body content + */ +export function extractFrontmatter(raw: string): Frontmatter { + // Lightweight frontmatter extractor to avoid extra deps + // Supports triple-dash YAML frontmatter at the start of the file + if (raw.startsWith("---")) { + const end = raw.indexOf("\n---", 3) + if (end > 0) { + const fm = raw.slice(3, end).trim() + const body = raw.slice(end + 4) + // Very minimal parsing for title, metadata.lastModified, and sdkLang + const fmTitleMatch = fm.match(/^\s*title:\s*"?(.+?)"?\s*$/m) + const lastModMatch = fm.match(/^\s*metadata:\s*[\s\S]*?lastModified:\s*"?(.+?)"?\s*$/m) + const sdkLangMatch = fm.match(/^\s*sdkLang:\s*"?(.+?)"?\s*$/m) + const fmTitle = fmTitleMatch ? fmTitleMatch[1] : undefined + const fmLastModified = lastModMatch ? lastModMatch[1] : undefined + const sdkLang = sdkLangMatch ? sdkLangMatch[1] : undefined + return { body, fmTitle, fmLastModified, sdkLang } + } + } + return { body: raw } +} + +/** + * Convert absolute file path to content-relative path + * @param absFile - Absolute file path + * @returns Path relative to src/content/ + */ +export function toContentRelative(absFile: string): string { + const idx = absFile.indexOf(path.normalize("src/content/")) + return idx >= 0 ? absFile.slice(idx + "src/content/".length) : absFile +} + +/** + * Convert content-relative path to canonical URL + * @param section - Section name (e.g., 'ccip') + * @param relFromContent - Path relative to src/content/ + * @param siteBase - Base URL for the site + * @returns Full canonical URL + */ +export function toCanonicalUrl(section: string, relFromContent: string, siteBase: string): string { + // relFromContent like "ccip/index.mdx" or "ccip/foo/bar.mdx" + const withoutExt = relFromContent.replace(/\.(md|mdx)$/i, "") + let slug = withoutExt + if (slug.endsWith("/index")) slug = slug.slice(0, -"/index".length) + if (!slug.startsWith(section)) slug = `${section}/${slug}` + if (!slug.startsWith("/")) slug = `/${slug}` + return `${siteBase}${slug}` +} + +/** + * Infer page title from file path + * @param relFromContent - Path relative to src/content/ + * @returns Inferred title + */ +export function inferTitleFromPath(relFromContent: string): string { + const base = path.basename(relFromContent, path.extname(relFromContent)) + if (base.toLowerCase() === "index") { + const parts = relFromContent.split(path.sep).filter(Boolean) + return parts.length >= 2 ? titleCase(parts[parts.length - 2]) : "Documentation" + } + return titleCase(base) +} + +/** + * Convert string to title case + * @param s - Input string + * @returns Title-cased string + */ +export function titleCase(s: string): string { + return s + .replace(/[-_]/g, " ") + .replace(/\s+/g, " ") + .trim() + .replace(/\b\w/g, (m) => m.toUpperCase()) +} + +/** + * Get page language from filename or frontmatter + * @param absFile - Absolute file path + * @param sdkLang - SDK language from frontmatter + * @returns Language code or null if not language-specific + */ +export function getPageLanguage(absFile: string, sdkLang?: string): string | null { + // Return the language if specified in frontmatter + if (sdkLang) return sdkLang.toLowerCase() + + // Check filename suffix (e.g., "page-go.mdx" -> "go", "page-ts.mdx" -> "ts") + const basename = path.basename(absFile, path.extname(absFile)) + const match = basename.match(/-(go|ts)$/) + if (match) return match[1] + + // No language specified = common to all languages + return null +} + +/** + * Check if page should be included in language-specific file + * @param pageLanguage - Language of the page + * @param targetLanguage - Target language for the file + * @returns True if page should be included + */ +export function shouldIncludeInLanguageFile(pageLanguage: string | null, targetLanguage: string): boolean { + // Include if page is common (no language) or matches target language + return pageLanguage === null || pageLanguage === targetLanguage +} + +/** + * Convert value to ISO date string + * @param val - Date value (string or Date) + * @returns ISO date string (YYYY-MM-DD) or undefined + */ +export function getIsoStringOrUndefined(val: unknown): string | undefined { + if (typeof val !== "string") return undefined + const d = new Date(val) + return isNaN(d.getTime()) ? undefined : d.toISOString().slice(0, 10) +} + +/** + * Unescape markdown for plain text output + * @param s - Markdown string + * @returns Unescaped string + */ +export function unescapeForPlainText(s: string): string { + let inFence = false + return s + .split("\n") + .map((line) => { + const trimmed = line.trim() + if (trimmed.startsWith("```") || trimmed.startsWith("~~~")) { + inFence = !inFence + return line + } + if (inFence) return line + return line + .replace(/\\_/g, "_") + .replace(/\\\[/g, "[") + .replace(/\\\]/g, "]") + .replace(/\\\(/g, "(") + .replace(/\\\)/g, ")") + }) + .filter((line) => line.trim() !== "{/* prettier-ignore */}") + .join("\n") +} diff --git a/src/lib/solana/index.ts b/src/lib/solana/index.ts index ab6c225c01c..a4f53569577 100644 --- a/src/lib/solana/index.ts +++ b/src/lib/solana/index.ts @@ -10,7 +10,7 @@ * 4. Wallet - Browser wallet integration * * Migration Complete: All legacy code has been removed. - * Use DripOrchestrator from @api/ccip/services/faucet/drip-orchestrator for business logic. + * Use DripOrchestrator from ~/lib/ccip/services-api/faucet/drip-orchestrator for business logic. */ // Core layer - Pure utilities with no dependencies diff --git a/src/pages/api/ccip/types/index.ts b/src/pages/api/ccip/types/index.ts deleted file mode 100644 index f2a74d933ff..00000000000 --- a/src/pages/api/ccip/types/index.ts +++ /dev/null @@ -1,231 +0,0 @@ -// Chain Data API Types - -import { Environment } from "@config/data/ccip/types.ts" - -export { Environment } - -// Chain type and family declarations -export type ChainType = "evm" | "solana" | "aptos" | "sui" -export type ChainFamily = "evm" | "mvm" | "svm" - -export const prerender = false - -/** - * Enriched fee token information with address and metadata - * Used when enrichFeeTokens=true query parameter is set - */ -export type FeeTokenEnriched = { - symbol: string - name: string - address: string - decimals: number -} - -export type ChainConfigError = { - chainId: number - networkId: string - reason: string - missingFields: string[] -} - -export type ChainMetadata = { - environment: Environment - timestamp: string - requestId: string - ignoredChainCount: number -} - -export interface ChainDetails { - chainId: number | string - displayName: string - selector: string - internalId: string - feeTokens: string[] | FeeTokenEnriched[] - router: string - rmn: string - chainType: ChainType - chainFamily: ChainFamily - registryModule?: string - tokenAdminRegistry?: string - tokenPoolFactory?: string - feeQuoter?: string - mcms?: string -} - -export type ChainApiResponse = { - metadata: ChainMetadata - data: Record<string, Record<string, ChainDetails>> - ignored: { - chainId: number - networkId: string - reason: string - missingFields: string[] - chain_id?: string - }[] -} - -export type OutputKeyType = "chainId" | "selector" | "internalId" - -export type ChainApiError = { - error: string - message: string -} - -export interface FilterType { - chainId?: string - selector?: string - internalId?: string -} - -export type SelectorEntry = { - selector: string - name: string -} - -export type SelectorsConfig = { - selectors: Record<string, SelectorEntry> -} - -// Token Data API Types - -export type TokenConfigError = { - symbol: string - reason: string - missingFields: string[] -} - -export type TokenMetadata = { - environment: Environment - timestamp: string - requestId: string - ignoredTokenCount: number - validTokenCount: number -} - -export type TokenChainData = { - chainId: number | string - chainName: string - decimals: number - destinations: string[] - name: string - poolAddress: string - poolType: string - symbol: string - tokenAddress: string -} - -export type TokenDataResponse = { - [key: string]: { - [chainKey: string]: TokenChainData - } -} - -export type TokenServiceResponse = { - tokens: TokenDataResponse - errors: TokenConfigError[] - metadata: { - validTokenCount: number - ignoredTokenCount: number - } -} - -export type TokenApiResponse = { - metadata: TokenMetadata - data: TokenDataResponse - ignored: TokenConfigError[] -} - -export interface TokenFilterType { - token_id?: string - chain_id?: string -} - -// Lane Data API Types - -export type LaneConfigError = { - sourceChain: string - destinationChain: string - reason: string - missingFields: string[] -} - -export type LaneMetadata = { - environment: Environment - timestamp: string - requestId: string - ignoredLaneCount: number - validLaneCount: number -} - -// Internal interface with chainType and chainFamily for processing -export interface ChainInfoInternal { - chainId: number | string - displayName: string - selector: string - internalId: string - chainType: ChainType - chainFamily: ChainFamily -} - -// Public interface for API responses without chainType and chainFamily -export interface ChainInfo { - chainId: number | string - displayName: string - selector: string - internalId: string -} - -export interface LaneDetails { - sourceChain: ChainInfo - destinationChain: ChainInfo - onRamp: { - address: string - version: string - enforceOutOfOrder?: boolean - } - offRamp: { - address: string - version: string - } - supportedTokens: string[] -} - -export type LaneDataResponse = Record<string, LaneDetails> - -export type LaneServiceResponse = { - data: LaneDataResponse - errors: LaneConfigError[] - metadata: { - validLaneCount: number - ignoredLaneCount: number - } -} - -export type LaneApiResponse = { - metadata: LaneMetadata - data: LaneDataResponse - ignored: LaneConfigError[] -} - -export interface LaneFilterType { - sourceChainId?: string - destinationChainId?: string - sourceSelector?: string - destinationSelector?: string - sourceInternalId?: string - destinationInternalId?: string - version?: string -} - -// Faucet API Types -export type { - FaucetChainConfig, - ChallengeParams, - ChallengeResponse, - VerifyRequest, - VerifyResponse, - VerifySignatureArgs, - FamilyAdapter, - FaucetApiResponse, - FaucetError, -} from "./faucet.ts" diff --git a/src/pages/api/ccip/v1/chains.ts b/src/pages/api/ccip/v1/chains.ts index 64413aa9d68..98933605e8e 100644 --- a/src/pages/api/ccip/v1/chains.ts +++ b/src/pages/api/ccip/v1/chains.ts @@ -7,18 +7,17 @@ import { generateChainKey, createMetadata, handleApiError, - successHeaders, - commonHeaders, loadChainConfiguration, FilterType, APIErrorType, createErrorResponse, CCIPError, -} from "../utils.ts" +} from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" import { logger } from "@lib/logging/index.js" -import type { ChainDetails, ChainApiResponse } from "../types/index.ts" -import { ChainDataService } from "../../services/chain-data.ts" +import type { ChainDetails, ChainApiResponse } from "~/lib/ccip/types/index.ts" +import { ChainDataService } from "~/lib/ccip/services/chain-data.ts" export const prerender = false @@ -45,7 +44,7 @@ export const GET: APIRoute = async ({ request }) => { // Validate filters const filters: FilterType = { - chainId: params.get("chainId") || undefined, + chainId: params.get("chain_id") || undefined, selector: params.get("selector") || undefined, internalId: params.get("internalId") || undefined, } @@ -57,15 +56,15 @@ export const GET: APIRoute = async ({ request }) => { }) // Validate output key - const outputKey = validateOutputKey(params.get("outputKey") || undefined) + const outputKey = validateOutputKey(params.get("output_key") || undefined) logger.debug({ message: "Output key validated", requestId, outputKey, }) - // Validate enrichFeeTokens parameter - const enrichFeeTokens = validateEnrichFeeTokens(params.get("enrichFeeTokens") || undefined) + // Validate enrich_fee_tokens parameter + const enrichFeeTokens = validateEnrichFeeTokens(params.get("enrich_fee_tokens") || undefined) logger.debug({ message: "EnrichFeeTokens parameter validated", requestId, @@ -105,7 +104,7 @@ export const GET: APIRoute = async ({ request }) => { acc[family] = chainList.reduce( (familyAcc, chain) => { const key = - outputKey === "chainId" + outputKey === "chain_id" ? generateChainKey(chain.chainId, chain.chainType, outputKey) : outputKey ? chain[outputKey].toString() @@ -133,7 +132,7 @@ export const GET: APIRoute = async ({ request }) => { }) return new Response(JSON.stringify(response), { - headers: { ...commonHeaders, ...successHeaders }, + headers: jsonHeaders, }) } catch (error) { logger.error({ diff --git a/src/pages/api/ccip/v1/drips/[chainName]/challenge.ts b/src/pages/api/ccip/v1/drips/[chainName]/challenge.ts index 9c578ededb1..c6d7405c9cb 100644 --- a/src/pages/api/ccip/v1/drips/[chainName]/challenge.ts +++ b/src/pages/api/ccip/v1/drips/[chainName]/challenge.ts @@ -1,8 +1,9 @@ import type { APIRoute } from "astro" -import { APIErrorType, createErrorResponse, commonHeaders, CCIPError } from "@api/ccip/utils.ts" +import { APIErrorType, createErrorResponse, CCIPError } from "~/lib/ccip/utils.ts" +import { commonHeaders } from "@lib/api/cacheHeaders.ts" import { logger } from "@lib/logging/index.js" import { getFaucetConfig } from "@lib/core/config/index.ts" -import { FaucetService } from "../../../../services/faucet-service.ts" +import { FaucetService } from "~/lib/ccip/services/faucet-service.ts" export const prerender = false export const runtime = "nodejs" // Required for crypto operations diff --git a/src/pages/api/ccip/v1/drips/[chainName]/execute.ts b/src/pages/api/ccip/v1/drips/[chainName]/execute.ts index 4d88f178c45..23ef79769f7 100644 --- a/src/pages/api/ccip/v1/drips/[chainName]/execute.ts +++ b/src/pages/api/ccip/v1/drips/[chainName]/execute.ts @@ -1,11 +1,12 @@ import type { APIRoute } from "astro" -import { APIErrorType, createErrorResponse, commonHeaders, CCIPError } from "@api/ccip/utils.ts" +import { APIErrorType, createErrorResponse, CCIPError } from "~/lib/ccip/utils.ts" +import { commonHeaders } from "@lib/api/cacheHeaders.ts" import { logger } from "@lib/logging/index.js" -import { FaucetService } from "../../../../services/faucet-service.ts" -import { SvmDripAdapter } from "@api/ccip/faucet/adapters/svm-drip.ts" -import { resolveFaucetChain } from "@api/ccip/faucet/chain-resolver.ts" -import { handleFaucetError } from "@api/ccip/services/faucet/error-handler.ts" -import { ChainConfigurationService } from "@api/ccip/services/chain-config.ts" +import { FaucetService } from "~/lib/ccip/services/faucet-service.ts" +import { SvmDripAdapter } from "~/lib/ccip/faucet/adapters/svm-drip.ts" +import { resolveFaucetChain } from "~/lib/ccip/faucet/chain-resolver.ts" +import { handleFaucetError } from "~/lib/ccip/services-api/faucet/error-handler.ts" +import { ChainConfigurationService } from "~/lib/ccip/services-api/chain-config.ts" export const prerender = false export const runtime = "nodejs" diff --git a/src/pages/api/ccip/v1/drips/[chainName]/index.ts b/src/pages/api/ccip/v1/drips/[chainName]/index.ts index b89cee85286..323a6466fad 100644 --- a/src/pages/api/ccip/v1/drips/[chainName]/index.ts +++ b/src/pages/api/ccip/v1/drips/[chainName]/index.ts @@ -1,7 +1,8 @@ import type { APIRoute } from "astro" -import { APIErrorType, createErrorResponse, commonHeaders, CCIPError } from "@api/ccip/utils.ts" +import { APIErrorType, createErrorResponse, CCIPError } from "~/lib/ccip/utils.ts" +import { commonHeaders } from "@lib/api/cacheHeaders.ts" import { logger } from "@lib/logging/index.js" -import { FaucetService } from "../../../../services/faucet-service.ts" +import { FaucetService } from "~/lib/ccip/services/faucet-service.ts" export const prerender = false export const runtime = "nodejs" // Required for crypto operations diff --git a/src/pages/api/ccip/v1/lanes.ts b/src/pages/api/ccip/v1/lanes.ts index d0936224e3f..64788866101 100644 --- a/src/pages/api/ccip/v1/lanes.ts +++ b/src/pages/api/ccip/v1/lanes.ts @@ -3,16 +3,15 @@ import { validateEnvironment, validateOutputKey, handleApiError, - successHeaders, - commonHeaders, APIErrorType, createErrorResponse, CCIPError, -} from "../utils.ts" +} from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" import { logger } from "@lib/logging/index.js" -import type { LaneFilterType, LaneApiResponse, LaneMetadata } from "../types/index.ts" -import { LaneDataService } from "../../services/lane-data.ts" +import type { LaneFilterType, LaneApiResponse, LaneMetadata } from "~/lib/ccip/types/index.ts" +import { LaneDataService } from "~/lib/ccip/services/lane-data.ts" export const prerender = false @@ -39,12 +38,12 @@ export const GET: APIRoute = async ({ request }) => { // Get filters for lanes const filters: LaneFilterType = { - sourceChainId: params.get("sourceChainId") || undefined, - destinationChainId: params.get("destinationChainId") || undefined, - sourceSelector: params.get("sourceSelector") || undefined, - destinationSelector: params.get("destinationSelector") || undefined, - sourceInternalId: params.get("sourceInternalId") || undefined, - destinationInternalId: params.get("destinationInternalId") || undefined, + sourceChainId: params.get("source_chain_id") || undefined, + destinationChainId: params.get("destination_chain_id") || undefined, + sourceSelector: params.get("source_selector") || undefined, + destinationSelector: params.get("destination_selector") || undefined, + sourceInternalId: params.get("source_internal_id") || undefined, + destinationInternalId: params.get("destination_internal_id") || undefined, version: params.get("version") || undefined, } @@ -55,7 +54,7 @@ export const GET: APIRoute = async ({ request }) => { }) // Validate output key - const outputKey = validateOutputKey(params.get("outputKey") || undefined) + const outputKey = validateOutputKey(params.get("output_key") || undefined) logger.debug({ message: "Output key validated", requestId, @@ -117,7 +116,7 @@ export const GET: APIRoute = async ({ request }) => { }) return new Response(JSON.stringify(response), { - headers: { ...commonHeaders, ...successHeaders }, + headers: jsonHeaders, }) } catch (error) { logger.error({ diff --git a/src/pages/api/ccip/v1/lanes/by-chain-id/[source]/[destination]/index.ts b/src/pages/api/ccip/v1/lanes/by-chain-id/[source]/[destination]/index.ts new file mode 100644 index 00000000000..afbdf413edd --- /dev/null +++ b/src/pages/api/ccip/v1/lanes/by-chain-id/[source]/[destination]/index.ts @@ -0,0 +1,111 @@ +import type { APIRoute } from "astro" +import { validateEnvironment, handleApiError, APIErrorType, createErrorResponse, CCIPError } from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" +import { logger } from "@lib/logging/index.js" + +import type { LaneDetailApiResponse, LaneDetailMetadata } from "~/lib/ccip/types/index.ts" +import { LaneDataService } from "~/lib/ccip/services/lane-data.ts" + +export const prerender = false + +export const GET: APIRoute = async ({ params, request }) => { + const requestId = crypto.randomUUID() + + try { + const { source, destination } = params + + logger.info({ + message: "Processing CCIP lane detail request (by-chain-id)", + requestId, + url: request.url, + source, + destination, + }) + + // Validate path parameters + if (!source) { + throw new CCIPError(400, "source chain ID is required in path") + } + if (!destination) { + throw new CCIPError(400, "destination chain ID is required in path") + } + + const url = new URL(request.url) + const queryParams = url.searchParams + + // Validate environment + const environment = validateEnvironment(queryParams.get("environment") || undefined) + logger.debug({ + message: "Environment validated", + requestId, + environment, + }) + + const laneDataService = new LaneDataService() + const result = await laneDataService.getLaneDetails(environment, source, destination, "chain_id") + + if (!result.data) { + throw new CCIPError(404, `Lane from chain '${source}' to chain '${destination}' not found`) + } + + logger.info({ + message: "Lane detail data retrieved successfully", + requestId, + source, + destination, + }) + + // Create lane detail metadata + const metadata: LaneDetailMetadata = { + environment, + timestamp: new Date().toISOString(), + requestId, + sourceChain: source, + destinationChain: destination, + } + + const response: LaneDetailApiResponse = { + metadata, + data: result.data, + } + + logger.info({ + message: "Sending successful response", + requestId, + metadata, + }) + + return new Response(JSON.stringify(response), { + headers: jsonHeaders, + }) + } catch (error) { + logger.error({ + message: "Error processing lane detail request", + requestId, + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }) + + // Handle CCIPError specifically, preserving its status code + if (error instanceof CCIPError) { + return createErrorResponse( + error.statusCode === 400 + ? APIErrorType.VALIDATION_ERROR + : error.statusCode === 404 + ? APIErrorType.NOT_FOUND + : APIErrorType.SERVER_ERROR, + error.message, + error.statusCode, + {} + ) + } + + // Handle other errors + if (error instanceof Error) { + return createErrorResponse(APIErrorType.SERVER_ERROR, "Failed to process lane detail request", 500, { + message: error.message, + }) + } + return handleApiError(error) + } +} diff --git a/src/pages/api/ccip/v1/lanes/by-chain-id/[source]/[destination]/supported-tokens.ts b/src/pages/api/ccip/v1/lanes/by-chain-id/[source]/[destination]/supported-tokens.ts new file mode 100644 index 00000000000..555dec2a5db --- /dev/null +++ b/src/pages/api/ccip/v1/lanes/by-chain-id/[source]/[destination]/supported-tokens.ts @@ -0,0 +1,111 @@ +import type { APIRoute } from "astro" +import { validateEnvironment, handleApiError, APIErrorType, createErrorResponse, CCIPError } from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" +import { logger } from "@lib/logging/index.js" + +import type { SupportedTokensApiResponse, SupportedTokensMetadata } from "~/lib/ccip/types/index.ts" +import { LaneDataService } from "~/lib/ccip/services/lane-data.ts" + +export const prerender = false + +export const GET: APIRoute = async ({ params, request }) => { + const requestId = crypto.randomUUID() + + try { + const { source, destination } = params + + logger.info({ + message: "Processing CCIP supported tokens request (by-chain-id)", + requestId, + url: request.url, + source, + destination, + }) + + // Validate path parameters + if (!source) { + throw new CCIPError(400, "source chain ID is required in path") + } + if (!destination) { + throw new CCIPError(400, "destination chain ID is required in path") + } + + const url = new URL(request.url) + const queryParams = url.searchParams + + // Validate environment + const environment = validateEnvironment(queryParams.get("environment") || undefined) + logger.debug({ + message: "Environment validated", + requestId, + environment, + }) + + const laneDataService = new LaneDataService() + const result = await laneDataService.getSupportedTokensWithRateLimits(environment, source, destination, "chain_id") + + if (!result.data) { + throw new CCIPError(404, `Lane from chain '${source}' to chain '${destination}' not found`) + } + + logger.info({ + message: "Supported tokens data retrieved successfully", + requestId, + source, + destination, + tokenCount: result.tokenCount, + }) + + // Create metadata + const metadata: SupportedTokensMetadata = { + environment, + timestamp: new Date().toISOString(), + requestId, + sourceChain: source, + destinationChain: destination, + tokenCount: result.tokenCount, + } + + const response: SupportedTokensApiResponse = { + metadata, + data: result.data, + } + + logger.info({ + message: "Sending successful response", + requestId, + metadata, + }) + + return new Response(JSON.stringify(response), { + headers: jsonHeaders, + }) + } catch (error) { + logger.error({ + message: "Error processing supported tokens request", + requestId, + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }) + + if (error instanceof CCIPError) { + return createErrorResponse( + error.statusCode === 400 + ? APIErrorType.VALIDATION_ERROR + : error.statusCode === 404 + ? APIErrorType.NOT_FOUND + : APIErrorType.SERVER_ERROR, + error.message, + error.statusCode, + {} + ) + } + + if (error instanceof Error) { + return createErrorResponse(APIErrorType.SERVER_ERROR, "Failed to process supported tokens request", 500, { + message: error.message, + }) + } + return handleApiError(error) + } +} diff --git a/src/pages/api/ccip/v1/lanes/by-internal-id/[source]/[destination]/index.ts b/src/pages/api/ccip/v1/lanes/by-internal-id/[source]/[destination]/index.ts new file mode 100644 index 00000000000..9d0a9ca98ff --- /dev/null +++ b/src/pages/api/ccip/v1/lanes/by-internal-id/[source]/[destination]/index.ts @@ -0,0 +1,111 @@ +import type { APIRoute } from "astro" +import { validateEnvironment, handleApiError, APIErrorType, createErrorResponse, CCIPError } from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" +import { logger } from "@lib/logging/index.js" + +import type { LaneDetailApiResponse, LaneDetailMetadata } from "~/lib/ccip/types/index.ts" +import { LaneDataService } from "~/lib/ccip/services/lane-data.ts" + +export const prerender = false + +export const GET: APIRoute = async ({ params, request }) => { + const requestId = crypto.randomUUID() + + try { + const { source, destination } = params + + logger.info({ + message: "Processing CCIP lane detail request (by-internal-id)", + requestId, + url: request.url, + source, + destination, + }) + + // Validate path parameters + if (!source) { + throw new CCIPError(400, "source internal ID is required in path") + } + if (!destination) { + throw new CCIPError(400, "destination internal ID is required in path") + } + + const url = new URL(request.url) + const queryParams = url.searchParams + + // Validate environment + const environment = validateEnvironment(queryParams.get("environment") || undefined) + logger.debug({ + message: "Environment validated", + requestId, + environment, + }) + + const laneDataService = new LaneDataService() + const result = await laneDataService.getLaneDetails(environment, source, destination, "internal_id") + + if (!result.data) { + throw new CCIPError(404, `Lane from '${source}' to '${destination}' not found`) + } + + logger.info({ + message: "Lane detail data retrieved successfully", + requestId, + source, + destination, + }) + + // Create lane detail metadata + const metadata: LaneDetailMetadata = { + environment, + timestamp: new Date().toISOString(), + requestId, + sourceChain: source, + destinationChain: destination, + } + + const response: LaneDetailApiResponse = { + metadata, + data: result.data, + } + + logger.info({ + message: "Sending successful response", + requestId, + metadata, + }) + + return new Response(JSON.stringify(response), { + headers: jsonHeaders, + }) + } catch (error) { + logger.error({ + message: "Error processing lane detail request", + requestId, + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }) + + // Handle CCIPError specifically, preserving its status code + if (error instanceof CCIPError) { + return createErrorResponse( + error.statusCode === 400 + ? APIErrorType.VALIDATION_ERROR + : error.statusCode === 404 + ? APIErrorType.NOT_FOUND + : APIErrorType.SERVER_ERROR, + error.message, + error.statusCode, + {} + ) + } + + // Handle other errors + if (error instanceof Error) { + return createErrorResponse(APIErrorType.SERVER_ERROR, "Failed to process lane detail request", 500, { + message: error.message, + }) + } + return handleApiError(error) + } +} diff --git a/src/pages/api/ccip/v1/lanes/by-internal-id/[source]/[destination]/supported-tokens.ts b/src/pages/api/ccip/v1/lanes/by-internal-id/[source]/[destination]/supported-tokens.ts new file mode 100644 index 00000000000..93fc939158e --- /dev/null +++ b/src/pages/api/ccip/v1/lanes/by-internal-id/[source]/[destination]/supported-tokens.ts @@ -0,0 +1,116 @@ +import type { APIRoute } from "astro" +import { validateEnvironment, handleApiError, APIErrorType, createErrorResponse, CCIPError } from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" +import { logger } from "@lib/logging/index.js" + +import type { SupportedTokensApiResponse, SupportedTokensMetadata } from "~/lib/ccip/types/index.ts" +import { LaneDataService } from "~/lib/ccip/services/lane-data.ts" + +export const prerender = false + +export const GET: APIRoute = async ({ params, request }) => { + const requestId = crypto.randomUUID() + + try { + const { source, destination } = params + + logger.info({ + message: "Processing CCIP supported tokens request (by-internal-id)", + requestId, + url: request.url, + source, + destination, + }) + + // Validate path parameters + if (!source) { + throw new CCIPError(400, "source internal ID is required in path") + } + if (!destination) { + throw new CCIPError(400, "destination internal ID is required in path") + } + + const url = new URL(request.url) + const queryParams = url.searchParams + + // Validate environment + const environment = validateEnvironment(queryParams.get("environment") || undefined) + logger.debug({ + message: "Environment validated", + requestId, + environment, + }) + + const laneDataService = new LaneDataService() + const result = await laneDataService.getSupportedTokensWithRateLimits( + environment, + source, + destination, + "internal_id" + ) + + if (!result.data) { + throw new CCIPError(404, `Lane from '${source}' to '${destination}' not found`) + } + + logger.info({ + message: "Supported tokens data retrieved successfully", + requestId, + source, + destination, + tokenCount: result.tokenCount, + }) + + // Create metadata + const metadata: SupportedTokensMetadata = { + environment, + timestamp: new Date().toISOString(), + requestId, + sourceChain: source, + destinationChain: destination, + tokenCount: result.tokenCount, + } + + const response: SupportedTokensApiResponse = { + metadata, + data: result.data, + } + + logger.info({ + message: "Sending successful response", + requestId, + metadata, + }) + + return new Response(JSON.stringify(response), { + headers: jsonHeaders, + }) + } catch (error) { + logger.error({ + message: "Error processing supported tokens request", + requestId, + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }) + + if (error instanceof CCIPError) { + return createErrorResponse( + error.statusCode === 400 + ? APIErrorType.VALIDATION_ERROR + : error.statusCode === 404 + ? APIErrorType.NOT_FOUND + : APIErrorType.SERVER_ERROR, + error.message, + error.statusCode, + {} + ) + } + + if (error instanceof Error) { + return createErrorResponse(APIErrorType.SERVER_ERROR, "Failed to process supported tokens request", 500, { + message: error.message, + }) + } + return handleApiError(error) + } +} diff --git a/src/pages/api/ccip/v1/lanes/by-selector/[source]/[destination]/index.ts b/src/pages/api/ccip/v1/lanes/by-selector/[source]/[destination]/index.ts new file mode 100644 index 00000000000..2a39109fd82 --- /dev/null +++ b/src/pages/api/ccip/v1/lanes/by-selector/[source]/[destination]/index.ts @@ -0,0 +1,111 @@ +import type { APIRoute } from "astro" +import { validateEnvironment, handleApiError, APIErrorType, createErrorResponse, CCIPError } from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" +import { logger } from "@lib/logging/index.js" + +import type { LaneDetailApiResponse, LaneDetailMetadata } from "~/lib/ccip/types/index.ts" +import { LaneDataService } from "~/lib/ccip/services/lane-data.ts" + +export const prerender = false + +export const GET: APIRoute = async ({ params, request }) => { + const requestId = crypto.randomUUID() + + try { + const { source, destination } = params + + logger.info({ + message: "Processing CCIP lane detail request (by-selector)", + requestId, + url: request.url, + source, + destination, + }) + + // Validate path parameters + if (!source) { + throw new CCIPError(400, "source selector is required in path") + } + if (!destination) { + throw new CCIPError(400, "destination selector is required in path") + } + + const url = new URL(request.url) + const queryParams = url.searchParams + + // Validate environment + const environment = validateEnvironment(queryParams.get("environment") || undefined) + logger.debug({ + message: "Environment validated", + requestId, + environment, + }) + + const laneDataService = new LaneDataService() + const result = await laneDataService.getLaneDetails(environment, source, destination, "selector") + + if (!result.data) { + throw new CCIPError(404, `Lane from selector '${source}' to selector '${destination}' not found`) + } + + logger.info({ + message: "Lane detail data retrieved successfully", + requestId, + source, + destination, + }) + + // Create lane detail metadata + const metadata: LaneDetailMetadata = { + environment, + timestamp: new Date().toISOString(), + requestId, + sourceChain: source, + destinationChain: destination, + } + + const response: LaneDetailApiResponse = { + metadata, + data: result.data, + } + + logger.info({ + message: "Sending successful response", + requestId, + metadata, + }) + + return new Response(JSON.stringify(response), { + headers: jsonHeaders, + }) + } catch (error) { + logger.error({ + message: "Error processing lane detail request", + requestId, + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }) + + // Handle CCIPError specifically, preserving its status code + if (error instanceof CCIPError) { + return createErrorResponse( + error.statusCode === 400 + ? APIErrorType.VALIDATION_ERROR + : error.statusCode === 404 + ? APIErrorType.NOT_FOUND + : APIErrorType.SERVER_ERROR, + error.message, + error.statusCode, + {} + ) + } + + // Handle other errors + if (error instanceof Error) { + return createErrorResponse(APIErrorType.SERVER_ERROR, "Failed to process lane detail request", 500, { + message: error.message, + }) + } + return handleApiError(error) + } +} diff --git a/src/pages/api/ccip/v1/lanes/by-selector/[source]/[destination]/supported-tokens.ts b/src/pages/api/ccip/v1/lanes/by-selector/[source]/[destination]/supported-tokens.ts new file mode 100644 index 00000000000..8b5ab782a39 --- /dev/null +++ b/src/pages/api/ccip/v1/lanes/by-selector/[source]/[destination]/supported-tokens.ts @@ -0,0 +1,111 @@ +import type { APIRoute } from "astro" +import { validateEnvironment, handleApiError, APIErrorType, createErrorResponse, CCIPError } from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" +import { logger } from "@lib/logging/index.js" + +import type { SupportedTokensApiResponse, SupportedTokensMetadata } from "~/lib/ccip/types/index.ts" +import { LaneDataService } from "~/lib/ccip/services/lane-data.ts" + +export const prerender = false + +export const GET: APIRoute = async ({ params, request }) => { + const requestId = crypto.randomUUID() + + try { + const { source, destination } = params + + logger.info({ + message: "Processing CCIP supported tokens request (by-selector)", + requestId, + url: request.url, + source, + destination, + }) + + // Validate path parameters + if (!source) { + throw new CCIPError(400, "source selector is required in path") + } + if (!destination) { + throw new CCIPError(400, "destination selector is required in path") + } + + const url = new URL(request.url) + const queryParams = url.searchParams + + // Validate environment + const environment = validateEnvironment(queryParams.get("environment") || undefined) + logger.debug({ + message: "Environment validated", + requestId, + environment, + }) + + const laneDataService = new LaneDataService() + const result = await laneDataService.getSupportedTokensWithRateLimits(environment, source, destination, "selector") + + if (!result.data) { + throw new CCIPError(404, `Lane from selector '${source}' to selector '${destination}' not found`) + } + + logger.info({ + message: "Supported tokens data retrieved successfully", + requestId, + source, + destination, + tokenCount: result.tokenCount, + }) + + // Create metadata + const metadata: SupportedTokensMetadata = { + environment, + timestamp: new Date().toISOString(), + requestId, + sourceChain: source, + destinationChain: destination, + tokenCount: result.tokenCount, + } + + const response: SupportedTokensApiResponse = { + metadata, + data: result.data, + } + + logger.info({ + message: "Sending successful response", + requestId, + metadata, + }) + + return new Response(JSON.stringify(response), { + headers: jsonHeaders, + }) + } catch (error) { + logger.error({ + message: "Error processing supported tokens request", + requestId, + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }) + + if (error instanceof CCIPError) { + return createErrorResponse( + error.statusCode === 400 + ? APIErrorType.VALIDATION_ERROR + : error.statusCode === 404 + ? APIErrorType.NOT_FOUND + : APIErrorType.SERVER_ERROR, + error.message, + error.statusCode, + {} + ) + } + + if (error instanceof Error) { + return createErrorResponse(APIErrorType.SERVER_ERROR, "Failed to process supported tokens request", 500, { + message: error.message, + }) + } + return handleApiError(error) + } +} diff --git a/src/pages/api/ccip/v1/rate-limits.ts b/src/pages/api/ccip/v1/rate-limits.ts new file mode 100644 index 00000000000..57644869eb8 --- /dev/null +++ b/src/pages/api/ccip/v1/rate-limits.ts @@ -0,0 +1,114 @@ +import type { APIRoute } from "astro" +import { + validateEnvironment, + validateRateLimitsFilters, + createRateLimitsMetadata, + handleApiError, + APIErrorType, + createErrorResponse, + CCIPError, +} from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" +import { logger } from "@lib/logging/index.js" + +import type { RateLimitsApiResponse } from "~/lib/ccip/types/index.ts" +import { RateLimitsDataService } from "~/lib/ccip/services/rate-limits-data.ts" + +export const prerender = false + +export const GET: APIRoute = async ({ request }) => { + const requestId = crypto.randomUUID() + + try { + logger.info({ + message: "Processing CCIP rate-limits request", + requestId, + url: request.url, + }) + + const url = new URL(request.url) + const params = url.searchParams + + // Validate environment + const environment = validateEnvironment(params.get("environment") || undefined) + logger.debug({ + message: "Environment validated", + requestId, + environment, + }) + + // Validate and parse rate limits filters + const filters = validateRateLimitsFilters({ + sourceInternalId: params.get("source_internal_id") || undefined, + destinationInternalId: params.get("destination_internal_id") || undefined, + tokens: params.get("tokens") || undefined, + direction: params.get("direction") || undefined, + rateType: params.get("rate_type") || undefined, + }) + + logger.debug({ + message: "Filter parameters validated", + requestId, + filters, + }) + + const rateLimitsService = new RateLimitsDataService() + const { data, metadata: serviceMetadata } = await rateLimitsService.getFilteredRateLimits(environment, filters) + + logger.info({ + message: "Rate limits data retrieved successfully", + requestId, + tokenCount: serviceMetadata.tokenCount, + sourceChain: filters.sourceInternalId, + destinationChain: filters.destinationInternalId, + }) + + // Create rate-limits-specific metadata + const metadata = createRateLimitsMetadata( + environment, + filters.sourceInternalId, + filters.destinationInternalId, + serviceMetadata.tokenCount + ) + + const response: RateLimitsApiResponse = { + metadata, + data, + } + + logger.info({ + message: "Sending successful response", + requestId, + metadata, + }) + + return new Response(JSON.stringify(response), { + headers: jsonHeaders, + }) + } catch (error) { + logger.error({ + message: "Error processing rate-limits request", + requestId, + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }) + + // Handle CCIPError specifically, preserving its status code + if (error instanceof CCIPError) { + return createErrorResponse( + error.statusCode === 400 ? APIErrorType.VALIDATION_ERROR : APIErrorType.SERVER_ERROR, + error.message, + error.statusCode, + {} + ) + } + + // Handle other errors + if (error instanceof Error) { + return createErrorResponse(APIErrorType.SERVER_ERROR, "Failed to process rate-limits request", 500, { + message: error.message, + }) + } + return handleApiError(error) + } +} diff --git a/src/pages/api/ccip/v1/tokens.ts b/src/pages/api/ccip/v1/tokens.ts index c11a39d77e5..ad40a3a149c 100644 --- a/src/pages/api/ccip/v1/tokens.ts +++ b/src/pages/api/ccip/v1/tokens.ts @@ -4,17 +4,16 @@ import { validateOutputKey, createTokenMetadata, handleApiError, - successHeaders, - commonHeaders, APIErrorType, createErrorResponse, CCIPError, loadChainConfiguration, -} from "../utils.ts" +} from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" import { logger } from "@lib/logging/index.js" -import type { TokenFilterType, TokenApiResponse } from "../types/index.ts" -import { TokenDataService } from "../../services/token-data.ts" +import type { TokenFilterType, TokenApiResponse } from "~/lib/ccip/types/index.ts" +import { TokenDataService } from "~/lib/ccip/services/token-data.ts" export const prerender = false @@ -52,7 +51,7 @@ export const GET: APIRoute = async ({ request }) => { }) // Validate output key - we'll still use this for formatting display options - const outputKey = validateOutputKey(params.get("outputKey") || undefined) + const outputKey = validateOutputKey(params.get("output_key") || undefined) logger.debug({ message: "Output key validated", requestId, @@ -100,7 +99,7 @@ export const GET: APIRoute = async ({ request }) => { }) return new Response(JSON.stringify(response), { - headers: { ...commonHeaders, ...successHeaders }, + headers: jsonHeaders, }) } catch (error) { logger.error({ diff --git a/src/pages/api/ccip/v1/tokens/[tokenCanonicalSymbol].ts b/src/pages/api/ccip/v1/tokens/[tokenCanonicalSymbol].ts new file mode 100644 index 00000000000..630c2ab3419 --- /dev/null +++ b/src/pages/api/ccip/v1/tokens/[tokenCanonicalSymbol].ts @@ -0,0 +1,122 @@ +import type { APIRoute } from "astro" +import { + validateEnvironment, + validateOutputKey, + handleApiError, + APIErrorType, + createErrorResponse, + CCIPError, +} from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" +import { logger } from "@lib/logging/index.js" + +import type { TokenDetailApiResponse, TokenDetailMetadata } from "~/lib/ccip/types/index.ts" +import { TokenDataService } from "~/lib/ccip/services/token-data.ts" + +export const prerender = false + +export const GET: APIRoute = async ({ params, request }) => { + const requestId = crypto.randomUUID() + + try { + const { tokenCanonicalSymbol } = params + + logger.info({ + message: "Processing CCIP token detail request", + requestId, + url: request.url, + tokenCanonicalSymbol, + }) + + // Validate token symbol is provided + if (!tokenCanonicalSymbol) { + throw new CCIPError(400, "tokenCanonicalSymbol parameter is required") + } + + const url = new URL(request.url) + const queryParams = url.searchParams + + // Validate environment + const environment = validateEnvironment(queryParams.get("environment") || undefined) + logger.debug({ + message: "Environment validated", + requestId, + environment, + }) + + // Validate output key for chain representation + const outputKey = validateOutputKey(queryParams.get("output_key") || undefined) + logger.debug({ + message: "Output key validated", + requestId, + outputKey, + }) + + const tokenDataService = new TokenDataService() + const result = await tokenDataService.getTokenWithFinality(environment, tokenCanonicalSymbol, outputKey) + + if (!result) { + throw new CCIPError(404, `Token '${tokenCanonicalSymbol}' not found`) + } + + logger.info({ + message: "Token detail data retrieved successfully", + requestId, + tokenCanonicalSymbol, + chainCount: result.metadata.chainCount, + }) + + // Create token detail metadata + const metadata: TokenDetailMetadata = { + environment, + timestamp: new Date().toISOString(), + requestId, + tokenSymbol: tokenCanonicalSymbol, + chainCount: result.metadata.chainCount, + } + + const response: TokenDetailApiResponse = { + metadata, + data: result.data, + } + + logger.info({ + message: "Sending successful response", + requestId, + metadata, + }) + + return new Response(JSON.stringify(response), { + headers: jsonHeaders, + }) + } catch (error) { + logger.error({ + message: "Error processing token detail request", + requestId, + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }) + + // Handle CCIPError specifically, preserving its status code + if (error instanceof CCIPError) { + return createErrorResponse( + error.statusCode === 400 + ? APIErrorType.VALIDATION_ERROR + : error.statusCode === 404 + ? APIErrorType.NOT_FOUND + : APIErrorType.SERVER_ERROR, + error.message, + error.statusCode, + {} + ) + } + + // Handle other errors + if (error instanceof Error) { + return createErrorResponse(APIErrorType.SERVER_ERROR, "Failed to process token detail request", 500, { + message: error.message, + }) + } + return handleApiError(error) + } +} diff --git a/src/pages/api/ccip/v1/tokens/[tokenCanonicalSymbol]/finality.ts b/src/pages/api/ccip/v1/tokens/[tokenCanonicalSymbol]/finality.ts new file mode 100644 index 00000000000..236414283cd --- /dev/null +++ b/src/pages/api/ccip/v1/tokens/[tokenCanonicalSymbol]/finality.ts @@ -0,0 +1,122 @@ +import type { APIRoute } from "astro" +import { + validateEnvironment, + validateOutputKey, + handleApiError, + APIErrorType, + createErrorResponse, + CCIPError, +} from "~/lib/ccip/utils.ts" +import { jsonHeaders } from "@lib/api/cacheHeaders.ts" +import { logger } from "@lib/logging/index.js" + +import type { TokenFinalityApiResponse, TokenDetailMetadata } from "~/lib/ccip/types/index.ts" +import { TokenDataService } from "~/lib/ccip/services/token-data.ts" + +export const prerender = false + +export const GET: APIRoute = async ({ params, request }) => { + const requestId = crypto.randomUUID() + + try { + const { tokenCanonicalSymbol } = params + + logger.info({ + message: "Processing CCIP token finality request", + requestId, + url: request.url, + tokenCanonicalSymbol, + }) + + // Validate token symbol is provided + if (!tokenCanonicalSymbol) { + throw new CCIPError(400, "tokenCanonicalSymbol parameter is required") + } + + const url = new URL(request.url) + const queryParams = url.searchParams + + // Validate environment + const environment = validateEnvironment(queryParams.get("environment") || undefined) + logger.debug({ + message: "Environment validated", + requestId, + environment, + }) + + // Validate output key for chain representation + const outputKey = validateOutputKey(queryParams.get("output_key") || undefined) + logger.debug({ + message: "Output key validated", + requestId, + outputKey, + }) + + const tokenDataService = new TokenDataService() + const result = await tokenDataService.getTokenFinality(environment, tokenCanonicalSymbol, outputKey) + + if (!result) { + throw new CCIPError(404, `Token '${tokenCanonicalSymbol}' not found`) + } + + logger.info({ + message: "Token finality data retrieved successfully", + requestId, + tokenCanonicalSymbol, + chainCount: result.metadata.chainCount, + }) + + // Create token finality metadata + const metadata: TokenDetailMetadata = { + environment, + timestamp: new Date().toISOString(), + requestId, + tokenSymbol: tokenCanonicalSymbol, + chainCount: result.metadata.chainCount, + } + + const response: TokenFinalityApiResponse = { + metadata, + data: result.data, + } + + logger.info({ + message: "Sending successful response", + requestId, + metadata, + }) + + return new Response(JSON.stringify(response), { + headers: jsonHeaders, + }) + } catch (error) { + logger.error({ + message: "Error processing token finality request", + requestId, + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }) + + // Handle CCIPError specifically, preserving its status code + if (error instanceof CCIPError) { + return createErrorResponse( + error.statusCode === 400 + ? APIErrorType.VALIDATION_ERROR + : error.statusCode === 404 + ? APIErrorType.NOT_FOUND + : APIErrorType.SERVER_ERROR, + error.message, + error.statusCode, + {} + ) + } + + // Handle other errors + if (error instanceof Error) { + return createErrorResponse(APIErrorType.SERVER_ERROR, "Failed to process token finality request", 500, { + message: error.message, + }) + } + return handleApiError(error) + } +} diff --git a/src/pages/api/page-markdown.ts b/src/pages/api/page-markdown.ts new file mode 100644 index 00000000000..d48e412ca57 --- /dev/null +++ b/src/pages/api/page-markdown.ts @@ -0,0 +1,139 @@ +/** + * API endpoint to generate markdown for a single page + * GET /api/page-markdown?path=/ccip/getting-started + */ + +import type { APIRoute } from "astro" +import fs from "fs/promises" +import path from "path" +import { transformPageToMarkdown } from "@lib/markdown/transformMarkdown.js" +import { extractFrontmatter, toCanonicalUrl, toContentRelative, getIsoStringOrUndefined } from "@lib/markdown/utils.js" +import { textPlainHeaders } from "@lib/api/cacheHeaders.js" + +const SITE_BASE = "https://docs.chain.link" + +// In-memory cache for transformed markdown +// TTL: 5 minutes (matches CDN cache duration) +const markdownCache = new Map<string, { markdown: string; timestamp: number }>() +const CACHE_TTL = 300_000 // 5 minutes in milliseconds + +export const prerender = false + +export const GET: APIRoute = async ({ request }) => { + const startTime = Date.now() + + try { + const url = new URL(request.url) + const requestedPath = url.searchParams.get("path") + const targetLanguage = url.searchParams.get("lang") || undefined + + if (!requestedPath) { + return new Response(JSON.stringify({ error: "Missing 'path' parameter" }), { + status: 400, + headers: { "Content-Type": "application/json" }, + }) + } + + // Check in-memory cache first (cache key includes language for multi-lang pages) + const cacheKey = targetLanguage ? `${requestedPath}:${targetLanguage}` : requestedPath + const cached = markdownCache.get(cacheKey) + if (cached && Date.now() - cached.timestamp < CACHE_TTL) { + const processingTime = Date.now() - startTime + return new Response(cached.markdown, { + status: 200, + headers: { + ...textPlainHeaders, + "X-Cache": "HIT", + "X-Processing-Time": `${processingTime}ms`, + }, + }) + } + + // Convert URL path to file path + // e.g., "/ccip/getting-started" -> "src/content/ccip/getting-started.mdx" + const cleanPath = requestedPath.startsWith("/") ? requestedPath.slice(1) : requestedPath + const possiblePaths = [ + path.resolve(`src/content/${cleanPath}.mdx`), + path.resolve(`src/content/${cleanPath}/index.mdx`), + path.resolve(`src/content/${cleanPath}.md`), + path.resolve(`src/content/${cleanPath}/index.md`), + ] + + let mdxAbsPath: string | null = null + for (const p of possiblePaths) { + try { + await fs.access(p) + mdxAbsPath = p + break + } catch { + // File doesn't exist, try next + } + } + + if (!mdxAbsPath) { + return new Response(JSON.stringify({ error: `Page not found: ${requestedPath}` }), { + status: 404, + headers: { "Content-Type": "application/json" }, + }) + } + + // Read the MDX file + const raw = await fs.readFile(mdxAbsPath, "utf-8") + const { body, fmTitle, fmLastModified } = extractFrontmatter(raw) + + // Extract section from path (first segment) + const section = cleanPath.split("/")[0] + + // Transform to markdown + const transformed = await transformPageToMarkdown(body, mdxAbsPath, { + siteBase: SITE_BASE, + targetLanguage, + }) + + // Generate metadata + const relFromContent = toContentRelative(mdxAbsPath) + const sourceUrl = toCanonicalUrl(section, relFromContent, SITE_BASE) + const title = fmTitle || path.basename(mdxAbsPath, path.extname(mdxAbsPath)) + const lastModified = getIsoStringOrUndefined(fmLastModified) + + // Format output with frontmatter + const headerLines = [ + `# ${title}`, + `Source: ${sourceUrl}`, + ...(lastModified ? [`Last Updated: ${lastModified}`] : []), + "", + "", + ] + + const finalMarkdown = [...headerLines, transformed.trim()].join("\n") + + // Store in cache (cache key includes language for multi-lang pages) + markdownCache.set(cacheKey, { + markdown: finalMarkdown, + timestamp: Date.now(), + }) + + const processingTime = Date.now() - startTime + + return new Response(finalMarkdown, { + status: 200, + headers: { + ...textPlainHeaders, + "X-Cache": "MISS", + "X-Processing-Time": `${processingTime}ms`, + }, + }) + } catch (error) { + console.error("Error generating markdown:", error) + return new Response( + JSON.stringify({ + error: "Internal server error", + message: error instanceof Error ? error.message : "Unknown error", + }), + { + status: 500, + headers: { "Content-Type": "application/json" }, + } + ) + } +} diff --git a/src/pages/api/services/lane-data.ts b/src/pages/api/services/lane-data.ts deleted file mode 100644 index 211bb888393..00000000000 --- a/src/pages/api/services/lane-data.ts +++ /dev/null @@ -1,392 +0,0 @@ -import { - Environment, - LaneDetails, - LaneFilterType, - LaneConfigError, - LaneServiceResponse, - ChainInfo, - ChainInfoInternal, - OutputKeyType, - ChainType, - ChainFamily, -} from "../ccip/types/index.ts" -import { loadReferenceData, Version } from "@config/data/ccip/index.ts" -import type { LaneConfig, ChainConfig } from "@config/data/ccip/types.ts" -import { generateChainKey, normalizeVersion } from "@api/ccip/utils.ts" -import { logger } from "@lib/logging/index.js" -import { - getChainId, - getTitle, - getChainTypeAndFamily, - directoryToSupportedChain, -} from "../../../features/utils/index.ts" - -export const prerender = false - -/** - * Service class for handling CCIP lane data operations - * Provides functionality to validate and filter lane configurations - */ -export class LaneDataService { - private errors: LaneConfigError[] = [] - private readonly requestId: string - private skippedLanesCount = 0 - - /** - * Creates a new instance of LaneDataService - */ - constructor() { - this.requestId = crypto.randomUUID() - - logger.debug({ - message: "LaneDataService initialized", - requestId: this.requestId, - }) - } - - /** - * Retrieves and filters lane data based on environment and filters - * - * @param environment - Network environment (mainnet/testnet) - * @param filters - Filter parameters for lanes - * @param outputKey - Format to use for displaying lane keys - * @returns Filtered lane data with metadata - */ - async getFilteredLanes( - environment: Environment, - filters: LaneFilterType, - outputKey: OutputKeyType - ): Promise<LaneServiceResponse> { - logger.debug({ - message: "Processing lane data", - requestId: this.requestId, - environment, - filters, - outputKey, - }) - - try { - // Load reference data - const { lanesReferenceData, chainsReferenceData } = loadReferenceData({ - environment, - version: Version.V1_2_0, - }) - - const result: Record<string, LaneDetails> = {} - this.errors = [] - this.skippedLanesCount = 0 - - // Process all lanes - for (const [sourceChainKey, destinations] of Object.entries(lanesReferenceData)) { - for (const [destChainKey, laneConfig] of Object.entries(destinations)) { - try { - // Get chain information - const sourceChain = this.resolveChainInfo(sourceChainKey, chainsReferenceData) - const destChain = this.resolveChainInfo(destChainKey, chainsReferenceData) - - if (!sourceChain || !destChain) { - this.addError(sourceChainKey, destChainKey, "Failed to resolve chain information", [ - "sourceChain", - "destinationChain", - ]) - continue - } - - // Apply filters - if (!this.passesFilters(sourceChain, destChain, filters)) { - this.skippedLanesCount++ - continue - } - - // Generate lane key - const laneKey = this.generateLaneKey(sourceChain, destChain, outputKey) - - // Build lane details - const laneDetails = this.buildLaneDetails(sourceChain, destChain, laneConfig) - - // Check for version mismatch - if (laneDetails.onRamp.version !== laneDetails.offRamp.version) { - this.addError( - sourceChainKey, - destChainKey, - `Version mismatch: onRamp v${laneDetails.onRamp.version} != offRamp v${laneDetails.offRamp.version}`, - ["version"] - ) - continue - } - - // Apply version filter if provided - if (filters.version) { - // Both onRamp and offRamp must match the specified version - if (laneDetails.onRamp.version !== filters.version || laneDetails.offRamp.version !== filters.version) { - this.skippedLanesCount++ - continue - } - } - - result[laneKey] = laneDetails - - logger.debug({ - message: "Lane processed successfully", - requestId: this.requestId, - laneKey, - sourceChain: sourceChainKey, - destinationChain: destChainKey, - }) - } catch (error) { - this.addError( - sourceChainKey, - destChainKey, - `Lane processing failed: ${error instanceof Error ? error.message : "Unknown error"}`, - ["laneConfig"] - ) - } - } - } - - const validLaneCount = Object.keys(result).length - const ignoredLaneCount = this.errors.length - - logger.info({ - message: "Lane data processing completed", - requestId: this.requestId, - validLaneCount, - ignoredLaneCount, - skippedLanesCount: this.skippedLanesCount, - }) - - return { - data: result, - errors: this.errors, - metadata: { - validLaneCount, - ignoredLaneCount, - }, - } - } catch (error) { - logger.error({ - message: "Failed to process lane data", - requestId: this.requestId, - error: error instanceof Error ? error.message : "Unknown error", - }) - - throw error - } - } - - /** - * Resolves chain information from chain key - */ - private resolveChainInfo(chainKey: string, chainsReferenceData: Record<string, unknown>): ChainInfoInternal | null { - try { - const chainConfig = chainsReferenceData[chainKey] - - if (!chainConfig) { - return null - } - - // Try to get supported chain for additional info, but don't fail if not found - let chainId: string | number = chainKey // fallback to chainKey - let displayName: string = chainKey // fallback to chainKey - let chainType: ChainType = "evm" // default to evm - let chainFamily: ChainFamily = "evm" // default to evm - - try { - const supportedChain = directoryToSupportedChain(chainKey) - const resolvedChainId = getChainId(supportedChain) - const resolvedDisplayName = getTitle(supportedChain) - const { chainType: resolvedChainType, chainFamily: resolvedChainFamily } = getChainTypeAndFamily(supportedChain) - - if (resolvedChainId) chainId = resolvedChainId - if (resolvedDisplayName) displayName = resolvedDisplayName - chainType = resolvedChainType - chainFamily = resolvedChainFamily - } catch { - // If directoryToSupportedChain fails, continue with fallback values - // This allows processing of chains not yet in the mapping - } - - // Get selector from chain configuration - const configData = chainConfig as ChainConfig - const selector = configData.chainSelector - - if (!selector) { - return null - } - - return { - chainId, - displayName, - selector, - internalId: chainKey, - chainType, - chainFamily, - } - } catch (error) { - logger.warn({ - message: "Failed to resolve chain info", - requestId: this.requestId, - chainKey, - error: error instanceof Error ? error.message : "Unknown error", - }) - return null - } - } - - /** - * Checks if a lane passes the given filters - */ - private passesFilters( - sourceChain: ChainInfoInternal, - destChain: ChainInfoInternal, - filters: LaneFilterType - ): boolean { - // Check source chain filters - if (filters.sourceChainId && !this.matchesChainFilter(sourceChain, filters.sourceChainId, "chainId")) { - return false - } - if (filters.sourceSelector && !this.matchesChainFilter(sourceChain, filters.sourceSelector, "selector")) { - return false - } - if (filters.sourceInternalId && !this.matchesChainFilter(sourceChain, filters.sourceInternalId, "internalId")) { - return false - } - - // Check destination chain filters - if (filters.destinationChainId && !this.matchesChainFilter(destChain, filters.destinationChainId, "chainId")) { - return false - } - if (filters.destinationSelector && !this.matchesChainFilter(destChain, filters.destinationSelector, "selector")) { - return false - } - if ( - filters.destinationInternalId && - !this.matchesChainFilter(destChain, filters.destinationInternalId, "internalId") - ) { - return false - } - - return true - } - - /** - * Checks if a chain matches a specific filter value - */ - private matchesChainFilter( - chain: ChainInfoInternal, - filterValue: string, - filterType: "chainId" | "selector" | "internalId" - ): boolean { - const filterValues = filterValue.split(",").map((v) => v.trim()) - const chainValue = chain[filterType].toString() - - // For chainId, also check generated chain key format - if (filterType === "chainId") { - const generatedKey = generateChainKey(chain.chainId, chain.chainType, "chainId") - return filterValues.includes(chainValue) || filterValues.includes(generatedKey) - } - - return filterValues.includes(chainValue) - } - - /** - * Generates a lane key based on source and destination chains - */ - private generateLaneKey( - sourceChain: ChainInfoInternal, - destChain: ChainInfoInternal, - outputKey: OutputKeyType - ): string { - const sourceKey = - outputKey === "chainId" - ? generateChainKey(sourceChain.chainId, sourceChain.chainType, outputKey) - : sourceChain[outputKey].toString() - - const destKey = - outputKey === "chainId" - ? generateChainKey(destChain.chainId, destChain.chainType, outputKey) - : destChain[outputKey].toString() - - return `${sourceKey}_to_${destKey}` - } - - /** - * Builds lane details from chain info and lane config - */ - private buildLaneDetails( - sourceChain: ChainInfoInternal, - destChain: ChainInfoInternal, - laneConfig: LaneConfig - ): LaneDetails { - // Convert internal chain info to public interface (remove chainType and chainFamily) - const publicSourceChain: ChainInfo = { - chainId: sourceChain.chainId, - displayName: sourceChain.displayName, - selector: sourceChain.selector, - internalId: sourceChain.internalId, - } - - const publicDestChain: ChainInfo = { - chainId: destChain.chainId, - displayName: destChain.displayName, - selector: destChain.selector, - internalId: destChain.internalId, - } - - return { - sourceChain: publicSourceChain, - destinationChain: publicDestChain, - onRamp: { - address: laneConfig.onRamp.address, - version: normalizeVersion(laneConfig.onRamp.version), - enforceOutOfOrder: laneConfig.onRamp.enforceOutOfOrder, - }, - offRamp: { - address: laneConfig.offRamp.address, - version: normalizeVersion(laneConfig.offRamp.version), - }, - supportedTokens: this.extractSupportedTokens(laneConfig), - } - } - - /** - * Extracts supported token keys from lane configuration - */ - private extractSupportedTokens(laneConfig: LaneConfig): string[] { - if (!laneConfig.supportedTokens) { - return [] - } - - // Extract token keys from supportedTokens object - // lanes.json structure: "supportedTokens": { "LINK": {...}, "CCIP-BnM": {...} } - return Object.keys(laneConfig.supportedTokens) - } - - /** - * Adds an error to the error collection - */ - private addError(sourceChain: string, destinationChain: string, reason: string, missingFields: string[]): void { - this.errors.push({ - sourceChain, - destinationChain, - reason, - missingFields, - }) - - logger.warn({ - message: "Lane validation error", - requestId: this.requestId, - sourceChain, - destinationChain, - reason, - missingFields, - }) - } - - /** - * Gets the request ID for this service instance - */ - getRequestId(): string { - return this.requestId - } -} diff --git a/src/pages/ccip/directory/mainnet/verifiers/index.astro b/src/pages/ccip/directory/mainnet/verifiers/index.astro new file mode 100644 index 00000000000..07aad33d482 --- /dev/null +++ b/src/pages/ccip/directory/mainnet/verifiers/index.astro @@ -0,0 +1,8 @@ +--- +import Verifiers from "~/components/CCIP/Verifiers/Verifiers.astro" +import { Environment } from "~/config/data/ccip" + +export const prerender = true +--- + +<Verifiers environment={Environment.Mainnet} /> diff --git a/src/pages/ccip/directory/testnet/verifiers/index.astro b/src/pages/ccip/directory/testnet/verifiers/index.astro new file mode 100644 index 00000000000..a6101109fd7 --- /dev/null +++ b/src/pages/ccip/directory/testnet/verifiers/index.astro @@ -0,0 +1,8 @@ +--- +import Verifiers from "~/components/CCIP/Verifiers/Verifiers.astro" +import { Environment } from "~/config/data/ccip" + +export const prerender = true +--- + +<Verifiers environment={Environment.Testnet} /> diff --git a/src/pages/ccip/index.astro b/src/pages/ccip/index.astro index 816caada5a7..cc8738a8ca7 100644 --- a/src/pages/ccip/index.astro +++ b/src/pages/ccip/index.astro @@ -1,6 +1,6 @@ --- -import DocsLayout from "~/layouts/DocsLayout.astro" import { getEntry, render } from "astro:content" +import DocsV3Layout from "~/layouts/DocsV3Layout/DocsV3Layout.astro" const entry = await getEntry("ccip", "index") if (!entry) { @@ -11,6 +11,6 @@ if (!entry) { const { Content, headings } = await render(entry) --- -<DocsLayout frontmatter={entry.data} {headings}> +<DocsV3Layout frontmatter={entry.data} {headings}> <Content /> -</DocsLayout> +</DocsV3Layout> diff --git a/src/pages/certification.astro b/src/pages/certification.astro new file mode 100644 index 00000000000..81d22dc18ea --- /dev/null +++ b/src/pages/certification.astro @@ -0,0 +1,928 @@ +--- +import BaseLayout from "~/layouts/BaseLayout.astro" +import { clsx } from "~/lib/clsx/clsx" +import { typographyVariants } from "@chainlink/blocks" + +const formattedContentTitle = `Courses | Chainlink Certifications` +--- + +<!-- NOTE: This page's HTML structure and styling are sourced from Webflow --> +<BaseLayout title={formattedContentTitle}> + <div class="overflow-hidden"> + <section id="demo" data-scroll="mid" class="sec-big sec-big--dark sec-big--light"> + <div class="w-layout-blockcontainer cont cont--cert w-container"> + <div class="demo-h-wrap"></div> + <div class="col col-cert"> + <div class="div-block-107"> + <h2 + class={clsx( + "display-500 display-500--dark", + typographyVariants({ + variant: "h2", + }) + )} + > + Supercharge your career with blockchain developer courses + </h2> + <p class="paragraph paragraph-certified"> + Get Chainlink certified on Cyfrin, with hands-on learning in Web3, blockchain, tokenization, and smart + contracts. Prove your skills and readiness to lead Chainlink-powered projects.<br /><br />Learn to build + secure dApps using Chainlink's core services—Data Feeds, VRF, Automation, and CCIP—through a + developer-focused certification course.<br />‍<br /> + </p> + <a + rel="noopener" + href="https://updraft.cyfrin.io/courses/chainlink-fundamentals" + target="_blank" + class="btn btn-primary btn-small btn-cert w-button">Start learning</a + > + </div> + <div class="margin-bottom space-4x"></div> + <div class="margin-bottom space-6x"></div> + <div> + <img src="/images/certification/image-certificate.svg" loading="lazy" alt="" class="image-22" /> + </div> + </div> + </div> + </section> + </div> + <div class="w-layout-blockcontainer cont w-container"> + <div class="sec-divider"></div> + </div> + <section class="sec-big sec-big--dark"> + <div class="w-layout-blockcontainer cont w-container"> + <div class="section-top"> + <div class="sec-tag sec-tag--blue">THE PLATFORM</div> + </div> + <h2 + class={clsx( + "display-500 display-500--white", + typographyVariants({ + variant: "h2", + }) + )} + > + The Learning Environment + </h2> + <div class="platform-tabs"> + <div class="plat-wrapper"> + <div class="plat-placeholder"></div><img + src="/images/certification/image-200.png" + loading="lazy" + width="Auto" + height="Auto" + alt="" + sizes="(max-width: 606px) 100vw, 606px" + class="plat-absolute plat-absolute--1" + /><img + src="/images/certification/image-201.png" + loading="lazy" + sizes="(max-width: 607px) 100vw, 607px" + alt="" + class="plat-absolute plat-absolute--2" + /><img + src="/images/certification/image-1.png" + loading="lazy" + sizes="(max-width: 607px) 100vw, 607px" + alt="" + class="plat-absolute plat-absolute--3" + /> + </div> + <div class="academy-accordion"> + <div class="acad-acc-item acad-acc-item--active"> + <div class="acad-acc-item__top"> + <h3 class="acad-acc-item__h">Hands-on learning built by experts</h3><img + src="/images/certification/Tailless--Arrow-Down.svg" + loading="lazy" + alt="" + class="acad-acc-item__arr" + /> + </div> + <p class="acad-acc-item__desc"> + Experience interactive learning where you'll engage in experiential learning through practical use + cases and coding exercises. Dive deep into real-world applications and build your skills with guided + practice. + </p> + </div> + <div class="acard-acc-item__divider"></div> + <div class="acad-acc-item"> + <div class="acad-acc-item__top"> + <h3 class="acad-acc-item__h">Practice your skills</h3><img + src="/images/certification/Tailless--Arrow-Down.svg" + loading="lazy" + width="16" + alt="" + class="acad-acc-item__arr" + /> + </div> + <p class="acad-acc-item__desc"> + Hands-on, high feedback quizzes and tests to grow your blockchain learning and challenge your smart + contract development. + </p> + </div> + <div class="acard-acc-item__divider"></div> + <div class="acad-acc-item"> + <div class="acad-acc-item__top"> + <h3 class="acad-acc-item__h">Become a certified Chainlink developer</h3><img + src="/images/certification/Tailless--Arrow-Down.svg" + loading="lazy" + alt="" + class="acad-acc-item__arr" + /> + </div> + <p class="acad-acc-item__desc"> + Achieve a prestigious certification that is highly regarded in the blockchain industry. This certification + not only validates your expertise but also significantly enhances your professional credibility and career + prospects. + </p> + </div> + <div class="acard-acc-item__divider"></div> + </div> + </div> + </div> + </section> + <section class="section-2"> + <section class="sec-big sec-big--light-bg"> + <div class="w-layout-blockcontainer cont w-container"> + <div class="section-top section-top__align-center"> + <div class="sec-tag">OTHER LEARNINGS</div> + </div> + <div class="center-wrap"> + <h2 + class={clsx( + "display-500 display-500--dark", + typographyVariants({ + variant: "h2", + }) + )} + > + Access free learning resources + </h2> + </div> + <div class="courses-wrap"> + <div class="course-row"> + <div class="course-col"> + <div class="course-card"> + <img src="/images/certification/image-learnings.svg" loading="lazy" alt="" class="cover-image" /> + <div class="course-card__content"> + <div class="course-card_top"> + <h3 class="course-card_h">Chainlink Developer Bootcamps</h3> + <p class="course-card__details"> + Chainlink gives blockchain developers an easy-to-use framework for writing onchain applications. + Join a bootcamp to learn how. + </p> + </div> + </div> + <div class="course-card_btn-wr"> + <a href="https://chain.link/bootcamp" class="btn btn-secondary btn-secondary--academy w-button" + >Explore</a + > + </div> + </div> + </div> + <div class="course-col"> + <div class="course-card"> + <img + src="/images/certification/Imagedevhubvideo.png" + loading="lazy" + sizes="(max-width: 560px) 100vw, 560px" + alt="" + class="cover-image" + /> + <div class="course-card__content"> + <div class="course-card_top"> + <h3 class="course-card_h">DevHub Videos</h3> + <p class="course-card__details"> + Start learning the basics of smart contracts with these step-by-step video tutorials made by + expert Chainlink Labs developers. + </p> + </div> + </div> + <div class="course-card_btn-wr"> + <a + href="https://dev.chain.link/resources/videos" + class="btn btn-secondary btn-secondary--academy w-button">Explore</a + > + </div> + </div> + </div> + <div class="course-col"> + <div class="course-card"> + <img + src="/images/certification/Imagedevhubresources.png" + loading="lazy" + sizes="(max-width: 560px) 100vw, 560px" + alt="" + class="cover-image" + /> + <div class="course-card__content"> + <div class="course-card_top"> + <h3 class="course-card_h">DevHub Resources</h3> + <p class="course-card__details"> + Understand Chainlink's mission and platform by exploring tutorials, docs, blogs, and more, and + learn how Chainlink services underpin the blockchain industry. + </p> + </div> + </div> + <div class="course-card_btn-wr"> + <a href="https://dev.chain.link/resources" class="btn btn-secondary btn-secondary--academy w-button" + >Explore</a + > + </div> + </div> + </div> + </div> + </div> + </div> + </section> + </section> +</BaseLayout> + +<style> + /* CSS Variables */ + :root { + --mirage: #0c162c; + --biscay: #1a2b6b; + --foreground--link: #2e7bff; + --grey-600: #6d7380; + --grey-800: #3d4556; + --grey-500: #858a95; + --grey-700: #555c6c; + --mirage-10-11: #e7e8ea; + --chainlink-blue: #0847f7; + --white: white; + --grey200: #e4e8ed; + --zircon: #f5f7fd; + --perano: #a0b3f2; + --lavender: #dfe7fb; + --grey-300: #ced0d5; + --mirage-90: #252e42; + --mirage-40: #9ea2ab; + --grey-400: #9fa7b2; + --blue-400: #8ca5e1; + --blue-100: #f5f7fd; + --green--400: #38b562; + --grey-900: #191c21; + } + + /* Base container */ + .cont { + grid-column-gap: 16px; + grid-row-gap: 16px; + flex-flow: row; + grid-template-rows: auto auto; + grid-template-columns: 1fr 1fr; + grid-auto-columns: 1fr; + width: 100%; + max-width: 1290px; + margin-left: auto; + margin-right: auto; + padding-left: 32px; + padding-right: 32px; + display: block; + } + + .cont.cont--cert { + grid-column-gap: 16px; + grid-row-gap: 16px; + grid-template-rows: auto auto; + grid-template-columns: 1fr 1fr; + grid-auto-columns: 1fr; + display: block; + } + + /* Column layouts */ + .col.col-cert { + grid-column-gap: 16px; + grid-row-gap: 16px; + vertical-align: baseline; + flex-flow: row; + grid-template-rows: auto auto; + grid-template-columns: 1fr 1fr; + grid-auto-columns: 1fr; + justify-content: space-between; + align-self: auto; + align-items: flex-start; + width: auto; + height: auto; + margin-top: -58px; + padding-left: 0; + padding-right: 0; + display: flex; + } + + .div-block-107 { + width: 624px; + } + + .image-22 { + display: block; + } + + /* Typography */ + .display-500 { + color: var(--biscay); + letter-spacing: -0.02em; + margin-top: 0; + margin-bottom: 0; + font-size: 3rem; + font-weight: 500; + line-height: 1.2em; + } + + .display-500.display-500--dark { + color: var(--mirage); + } + + .display-500.display-500--white { + color: #fff; + } + + .paragraph { + color: var(--grey-600); + margin-bottom: 0; + } + + .paragraph.paragraph-certified { + flex: 0 auto; + width: 624px; + height: 144px; + margin-top: 24px; + margin-bottom: 24px; + padding-top: 0; + padding-left: 0; + position: static; + } + + /* Buttons */ + .btn { + border: 1px solid var(--mirage-10-11); + background-color: var(--mirage-10-11); + box-shadow: none; + color: var(--grey-600); + border-radius: 4px; + padding: 16px 32px; + line-height: 20px; + text-decoration: none; + display: inline-block; + } + + .btn.btn-primary { + border-color: var(--chainlink-blue); + background-color: var(--chainlink-blue); + color: var(--white); + transition: + border-color 0.2s, + background-color 0.2s; + } + + .btn.btn-primary:hover { + background-color: #0036c9; + border-color: #0036c9; + } + + .btn.btn-primary.btn-small { + margin-left: 24px; + padding: 8px 24px; + font-size: 14px; + line-height: 24px; + } + + .btn.btn-primary.btn-small.btn-cert { + float: none; + clear: none; + text-align: center; + vertical-align: baseline; + width: 156px; + margin-bottom: 8px; + margin-left: 0; + padding-left: 24px; + display: inline-block; + position: static; + inset: auto auto 0% 0%; + } + + .btn.btn-secondary { + color: #0847f7; + background-color: #fff; + border: 1px solid #639cff; + transition: + background-color 0.3s, + border-color 0.3s, + color 0.3s; + } + + .btn.btn-secondary:hover { + border-color: #0d5dff; + } + + .btn.btn-secondary.btn-secondary--academy { + justify-content: center; + align-items: flex-start; + width: 100%; + padding-top: 12px; + padding-bottom: 12px; + display: flex; + } + + /* Sections */ + .sec-big { + padding-top: 100px; + padding-bottom: 100px; + overflow: visible; + } + + .sec-big.sec-big--dark { + background-color: var(--mirage); + color: var(--mirage); + } + + .sec-big.sec-big--dark.sec-big--light { + background-color: var(--white); + } + + .sec-big.sec-big--light-bg { + background-color: var(--white); + padding-bottom: 140px; + } + + .sec-tag { + color: var(--grey-600); + letter-spacing: 1.28px; + text-transform: uppercase; + font-weight: 500; + } + + .sec-tag.sec-tag--blue { + color: var(--perano); + } + + .section-top { + justify-content: space-between; + margin-bottom: 16px; + display: flex; + } + + .section-top.section-top__align-center { + justify-content: center; + } + + .sec-divider { + background-color: var(--lavender); + width: 100%; + height: 1px; + } + + /* Course cards */ + .course-card { + grid-column-gap: 24px; + grid-row-gap: 24px; + border: 1px solid var(--grey-400); + border-radius: 8px; + flex-flow: column; + flex: 1; + height: 96%; + padding: 0 0 24px; + transition: + box-shadow 0.2s, + border-color 0.2s; + display: flex; + position: relative; + overflow: hidden; + } + + .course-card:hover { + border-color: var(--chainlink-blue); + box-shadow: 0 8px 40px #0c162c1f; + } + + .course-card__img-wrap { + flex: 0 auto; + align-self: auto; + width: 100%; + height: 100%; + display: block; + position: relative; + } + + .course-card__content { + grid-column-gap: 12px; + grid-row-gap: 12px; + background-color: #fff; + flex-flow: column; + flex: 1; + + padding: 16px; + display: flex; + } + + .course-card_top { + margin-top: 0; + } + + .course-card_h { + color: var(--biscay); + width: 325.33px; + margin-top: 0; + margin-bottom: 10px; + font-size: 22px; + font-weight: 500; + line-height: 28px; + } + + .course-card__details { + color: var(--mirage); + flex-flow: wrap; + justify-content: flex-start; + align-items: center; + margin-bottom: 12px; + display: flex; + } + + .course-card_btn-wr { + height: 40px; + margin-left: auto; + margin-right: auto; + width: 90%; + } + + .course-col { + box-sizing: border-box; + grid-column-gap: 24px; + grid-row-gap: 24px; + flex-flow: row; + order: 1; + grid-template-rows: auto auto; + grid-template-columns: 1fr 1fr; + grid-auto-columns: 1fr; + justify-content: space-between; + align-items: stretch; + width: 373.33px; + max-width: none; + height: 573px; + margin: 0 auto; + padding: 20px 0; + display: flex; + } + + .course-row { + grid-column-gap: 16px; + grid-row-gap: 16px; + flex-flow: wrap; + grid-template: ". . Area" / 1fr 1fr 1fr; + grid-auto-columns: 1fr; + justify-content: space-between; + align-items: stretch; + width: 1200px; + height: 473px; + margin: -20px; + display: flex; + } + + .courses-wrap { + grid-column-gap: 16px; + grid-row-gap: 16px; + flex-flow: row; + grid-template: ". Area" ". ." / 1fr 1fr 1fr; + grid-auto-columns: 1fr; + justify-content: space-between; + align-items: stretch; + width: 1200px; + max-width: 1200px; + margin-top: 48px; + margin-left: auto; + margin-right: auto; + display: flex; + overflow: visible; + } + + .cover-image { + box-sizing: border-box; + object-fit: cover; + width: 100%; + height: auto; + aspect-ratio: 16/9; + margin-top: 0; + padding-bottom: 0; + padding-right: 0; + } + + /* Accordion */ + .acad-acc-item__h { + color: var(--grey-600); + flex: 1; + margin-top: 0; + margin-bottom: 0; + margin-right: 24px; + font-size: 28px; + font-weight: 700; + line-height: 32px; + } + + .acad-acc-item__desc { + color: var(--grey-600); + height: 0; + margin-bottom: 0; + transition: all 0.2s; + overflow: hidden; + } + + .acad-acc-item__top { + cursor: pointer; + justify-content: flex-start; + align-items: center; + padding-top: 24px; + padding-bottom: 24px; + display: flex; + } + + .acard-acc-item__divider { + background-color: var(--grey-800); + width: 100%; + height: 1px; + } + + .acad-acc-item__arr { + display: block; + overflow: clip; + } + + .academy-accordion { + flex: 1; + width: 100%; + max-width: 460px; + min-height: 460px; + } + + .platform-tabs { + justify-content: space-between; + align-items: center; + margin-top: 64px; + display: flex; + } + + .plat-absolute { + aspect-ratio: 16 / 9; + border-radius: 16px; + width: 95%; + transition: transform 0.2s; + position: absolute; + bottom: 0; + right: 0; + overflow: hidden; + } + + .plat-absolute.plat-absolute--1 { + z-index: 3; + transform: translate(0, 0); + } + + .plat-absolute.plat-absolute--2 { + z-index: 2; + transform: translate(-16px, -16px); + } + + .plat-absolute.plat-absolute--3 { + z-index: 1; + transform: translate(-32px, -32px); + } + + .plat-wrapper { + width: 50%; + max-width: 600px; + margin-left: 32px; + margin-right: 40px; + position: relative; + } + + .plat-placeholder { + aspect-ratio: 16 / 9; + } + + /* Layout helpers */ + .center-wrap { + grid-column-gap: 8px; + grid-row-gap: 8px; + text-align: center; + flex-flow: column; + justify-content: flex-start; + align-items: center; + display: flex; + } + + .course-left-shape { + z-index: -1; + position: absolute; + inset: 0% auto auto 0%; + } + + .relative-div { + position: relative; + } + + .relative-div.relative-div--overflow-hidden, + .overflow-hidden { + overflow: hidden; + } + + .margin-bottom.space-4x { + margin-top: 0; + margin-bottom: 16px; + padding: 0; + } + + .margin-bottom.space-6x { + margin-top: 0; + margin-bottom: 24px; + padding: 0; + } + + .demo-h-wrap { + width: 60%; + margin-bottom: 64px; + } + + .section-2 { + background-color: #f5f7fd; + } + + .w-container:before, + .w-container:after { + content: " "; + display: table; + grid-column-start: 1; + grid-row-start: 1; + grid-column-end: 2; + grid-row-end: 2; + } + + .w-container:after { + clear: both; + } + + .w-button { + display: inline-block; + padding: 9px 15px; + background-color: #3898ec; + color: white; + border: 0; + line-height: inherit; + text-decoration: none; + cursor: pointer; + } + + /* Responsive styles */ + @media screen and (max-width: 991px) { + .w-container { + max-width: 728px; + } + + .cont { + padding-left: 24px; + padding-right: 24px; + } + + .demo-h-wrap { + width: 80%; + } + + .col.col-cert { + flex-flow: column; + margin-top: 0; + } + + .div-block-107 { + width: 100%; + } + + .paragraph.paragraph-certified { + width: 100%; + height: auto; + } + + .platform-tabs { + flex-direction: column; + } + + .plat-wrapper { + width: 90%; + margin-left: 0; + margin-right: 0; + margin-bottom: 40px; + } + + .academy-accordion { + max-width: 100%; + min-height: auto; + } + + .course-row { + width: 100%; + height: auto; + flex-direction: column; + margin: 0; + } + + .course-col { + width: 100%; + height: auto; + padding: 0; + margin-bottom: 20px; + } + + .courses-wrap { + width: 100%; + height: auto; + flex-direction: column; + } + + .display-500 { + font-size: 2rem; + } + + .sec-big { + padding-top: 60px; + padding-bottom: 60px; + } + } + + @media screen and (max-width: 767px) { + .w-container { + max-width: none; + } + + .demo-h-wrap { + width: 100%; + margin-bottom: 40px; + } + + .display-500 { + font-size: 2rem; + } + + .acad-acc-item__h { + font-size: 20px; + line-height: 28px; + } + } +</style> + +<style> + .acad-acc-item.acad-acc-item--active .acad-acc-item__desc { + height: auto; + padding-bottom: 24px; + } + .acad-acc-item.acad-acc-item--active .acad-acc-item__h { + color: white; + } + .acad-acc-item.acad-acc-item--active .acad-acc-item__arr { + transform: rotate(-180deg); + } + .acad-acc-item__top:hover .acad-acc-item__h { + color: white; + transition: 200ms ease; + } +</style> + +<script> + // Accordion functionality + document.addEventListener("DOMContentLoaded", function () { + var popularResCols = document.querySelectorAll(".acad-acc-item") + popularResCols.forEach(function (popularResCol) { + popularResCol.addEventListener("click", function () { + if (!this.classList.contains("acad-acc-item--active")) { + // Remove 'acad-acc-item--active' class from all elements + popularResCols.forEach(function (col) { + col.classList.remove("acad-acc-item--active") + }) + // Add 'acad-acc-item--active' class to the clicked element + this.classList.add("acad-acc-item--active") + } + }) + }) + }) + + // Image stack rotation + const items = document.querySelectorAll(".acad-acc-item") + const absoluteItems = document.querySelectorAll(".plat-absolute") + + // Define the z-index and transform pairs + const zIndexValues = [3, 2, 1] + const transformValues = [ + "translate(0, 0)", // For z-index 3 + "translate(-16px, -16px)", // For z-index 2 + "translate(-32px, -32px)", // For z-index 1 + ] + + items.forEach((item, index) => { + item.addEventListener("click", function () { + // Apply z-index and transform based on the clicked index + absoluteItems.forEach((el, i) => { + const htmlEl = el as HTMLElement + const newIndex = (i - index + absoluteItems.length) % absoluteItems.length + htmlEl.style.zIndex = zIndexValues[newIndex].toString() + htmlEl.style.transform = transformValues[newIndex] + }) + }) + }) +</script> diff --git a/src/pages/changelog.astro b/src/pages/changelog.astro new file mode 100644 index 00000000000..dd94e3cc890 --- /dev/null +++ b/src/pages/changelog.astro @@ -0,0 +1,239 @@ +--- +import BaseLayout from "~/layouts/BaseLayout.astro" +import * as CONFIG from "../config" +import { Typography } from "@chainlink/blocks" +import { ChangelogFilters } from "~/components/ChangelogFilters/ChangelogFilters.tsx" +import { getSecret } from "astro:env/server" +import { searchClient, SearchClient } from "@algolia/client-search" +import { ChangelogItem } from "~/components/ChangelogSnippet/types" +import ChangelogCard from "~/components/ChangelogSnippet/ChangelogCard.astro" +import { getUniqueNetworks, getUniqueTopics, getUniqueTypes } from "~/utils/changelogFilters" +const formattedContentTitle = `${CONFIG.PAGE.titleFallback} | ${CONFIG.SITE.title}` + +const appId = getSecret("ALGOLIA_APP_ID") +const apiKey = getSecret("PUBLIC_ALGOLIA_SEARCH_PUBLIC_API_KEY") + +let client: SearchClient +let logs: ChangelogItem[] | undefined = undefined + +if (appId && apiKey) { + client = searchClient(appId, apiKey) + + const firstReq = await client.search({ + requests: [ + { + indexName: "Changelog", + page: 0, + hitsPerPage: 1000, + }, + ], + }) + + const firstResult = firstReq.results[0] + let allHits = "hits" in firstResult ? (firstResult.hits as ChangelogItem[]) : [] + const nbPages = "nbPages" in firstResult ? firstResult.nbPages : 1 + + if (nbPages && nbPages > 1) { + const remainingRequests = Array.from({ length: nbPages - 1 }, (_, i) => ({ + indexName: "Changelog", + page: i + 1, + hitsPerPage: 1000, + })) + + const remainingResults = await client.search({ requests: remainingRequests }) + + remainingResults.results.forEach((result) => { + if ("hits" in result) { + allHits = [...allHits, ...(result.hits as ChangelogItem[])] + } + }) + } + + logs = allHits +} + +// Extract unique filter values +const products = logs ? getUniqueTopics(logs) : [] +const networks = logs ? getUniqueNetworks(logs) : [] +const types = logs ? getUniqueTypes(logs) : [] +--- + +<BaseLayout title={formattedContentTitle}> + <main class="wrapper"> + <header class="header"> + <Typography className="tag">Changelog</Typography> + <Typography variant="h1" className="title">Never miss an update</Typography> + </header> + + <section class="changelog-list"> + { + logs?.map((log, index) => ( + <div class="changelog-item" data-index={index} style={index >= 25 ? "display: none;" : ""}> + <ChangelogCard showNetworksAndTopic showBorder={false} item={log} /> + </div> + )) + } + </section> + + <section class="empty-state" style="display: none;"> + <Typography variant="h3" className="empty-state-title">No updates found</Typography> + <Typography variant="body-l" color="muted" className="empty-state-text"> + We couldn't find anything matching your filters. + </Typography> + <img src="/images/not-found.svg" alt="No updates found" class="empty-state-image" /> + </section> + + { + logs && logs.length > 25 && ( + <div class="load-more-section"> + <button id="load-more-btn" class="load-more-button"> + Load more + </button> + <p class="count-text"> + Showing <span id="visible-count">25</span> of <span id="total-count">{logs.length}</span> updates + </p> + </div> + ) + } + + <ChangelogFilters client:load products={products} networks={networks} types={types} items={logs || []} /> + </main> +</BaseLayout> + +<script> + const loadMoreBtn = document.getElementById("load-more-btn") + const visibleCountSpan = document.getElementById("visible-count") + const totalCountSpan = document.getElementById("total-count") + + if (loadMoreBtn && visibleCountSpan && totalCountSpan) { + let visibleCount = 25 + const totalCount = parseInt(totalCountSpan.textContent || "0") + const items = document.querySelectorAll(".changelog-item") + + loadMoreBtn.addEventListener("click", () => { + // Show next 25 items + const newVisibleCount = Math.min(visibleCount + 25, totalCount) + + for (let i = visibleCount; i < newVisibleCount; i++) { + if (items[i]) { + ;(items[i] as HTMLElement).style.display = "" + } + } + + visibleCount = newVisibleCount + visibleCountSpan.textContent = visibleCount.toString() + + // Hide button if all items are visible + if (visibleCount >= totalCount) { + const loadMoreSection = document.querySelector(".load-more-section") + if (loadMoreSection) { + ;(loadMoreSection as HTMLElement).style.display = "none" + } + } + }) + } +</script> + +<style is:global> + .wrapper { + max-width: 1064px; + width: 100%; + margin: 0 auto; + padding: 100px var(--space-6x); + } + + .tag { + font-weight: 500; + letter-spacing: 1.28px; + color: var(--grey-600); + margin-bottom: var(--space-4x); + text-transform: uppercase; + } + + .header { + margin-bottom: var(--space-16x); + } + + .changelog-list { + display: flex; + flex-direction: column; + gap: 60px; + } + + .empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: var(--space-16x) var(--space-6x); + margin-top: var(--space-10x); + } + + .empty-state-image { + max-width: 400px; + width: 100%; + height: auto; + margin-top: var(--space-6x); + } + + .empty-state-title { + margin-bottom: var(--space-2x); + } + + .empty-state-text { + max-width: 400px; + } + + .load-more-section { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--space-4x); + margin-top: var(--space-10x); + } + + .load-more-button { + padding: var(--space-2x) var(--space-6x); + background: transparent; + border: 1px solid var(--link); + border-radius: var(--space-1x); + color: var(--link); + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + } + + .load-more-button:hover { + border: 1px solid var(--brand); + } + + .count-text { + font-size: 14px; + color: var(--grey-600); + margin: 0; + margin-top: 84px; + } + + @media screen and (max-width: 768px) { + .tag { + font-size: 12px; + margin-bottom: var(--space-3x); + } + .title { + font-size: 2rem; + } + .header { + margin-bottom: var(--space-10x); + } + + .wrapper { + padding: 60px var(--space-6x); + } + + .changelog-list { + gap: 40px; + } + } +</style> diff --git a/src/pages/changelog/[...id].astro b/src/pages/changelog/[...id].astro new file mode 100644 index 00000000000..5ce2f8ddd24 --- /dev/null +++ b/src/pages/changelog/[...id].astro @@ -0,0 +1,153 @@ +--- +import BaseLayout from "~/layouts/BaseLayout.astro" +import * as CONFIG from "../../config" +import { getSecret } from "astro:env/server" +import { searchClient } from "@algolia/client-search" +import { ChangelogItem } from "~/components/ChangelogSnippet/types" +import ChangelogCard from "~/components/ChangelogSnippet/ChangelogCard.astro" +import { SvgArrowLeft2, Typography } from "@chainlink/blocks" + +export async function getStaticPaths() { + const appId = getSecret("ALGOLIA_APP_ID") + const apiKey = getSecret("PUBLIC_ALGOLIA_SEARCH_PUBLIC_API_KEY") + + // Return empty array if credentials are not available (CI/CD environments) + if (!appId || !apiKey) { + console.warn("Algolia credentials not available, skipping changelog static generation") + return [] + } + + const client = searchClient(appId, apiKey) + + try { + const records: ChangelogItem[] = [] + let currentPage = 0 + let nbPages = 1 + const hitsPerPage = 1000 // Maximum allowed by Algolia + + // Fetch all changelog items from Algolia with pagination + while (currentPage < nbPages) { + const req = await client.search({ + requests: [ + { + indexName: "Changelog", + hitsPerPage, + page: currentPage, + }, + ], + }) + + const firstResult = req.results[0] + + if ("hits" in firstResult) { + // Add hits from current page to records + const hits = firstResult.hits as ChangelogItem[] + records.push(...hits) + + // Update nbPages from the response + if ("nbPages" in firstResult) { + nbPages = firstResult.nbPages as number + } + } + + currentPage++ + } + + // Generate static paths for each changelog item + return records.map((log) => ({ + params: { id: log.slug }, + props: { log }, + })) + } catch (error) { + console.error("Error fetching changelog items:", error) + return [] + } +} + +interface Props { + log: ChangelogItem +} + +const { log } = Astro.props + +const pageTitle = `Changelog and Releases | ${CONFIG.SITE.title}` +--- + +<BaseLayout title={pageTitle}> + <main class="wrapper changelog-page"> + <div class="changelog-header"> + <a href="/changelog" class="back-link"> + <SvgArrowLeft2 color="link" /> + <span>Back to Changelog</span> + </a> + + <Typography variant="h1" className="header-title">Integration</Typography> + </div> + + <div class="changelog-content"> + <ChangelogCard + showNetworksAndTopic + item={log} + showBorder={false} + autoExpand={true} + showCopyButton={false} + disableHover={true} + /> + </div> + </main> +</BaseLayout> + +<style> + .changelog-page { + max-width: 1264px; + width: 100%; + margin: 0 auto; + padding: 100px var(--space-6x); + } + + .changelog-header { + margin-bottom: var(--space-16x); + } + + .back-link { + display: inline-flex; + align-items: center; + gap: var(--space-2x); + color: var(--link); + text-decoration: none; + + font-weight: 500; + transition: color 0.2s ease; + + & span { + font-size: 16px !important; + } + } + + .header-title { + margin-top: var(--space-4x); + font-size: 2.5rem; + font-weight: 500; + } + + @media screen and (max-width: 425px) { + .header-title { + font-size: 1.75rem !important; + } + } + + @media screen and (max-width: 768px) { + .header-title { + font-size: 2rem; + } + + .changelog-page { + padding: 60px 0; + } + + .changelog-header { + padding: 0 var(--space-6x); + margin-bottom: 0; + } + } +</style> diff --git a/src/pages/cre/[...id].astro b/src/pages/cre/[...id].astro index 7c2b40919ba..9f7ef425b52 100644 --- a/src/pages/cre/[...id].astro +++ b/src/pages/cre/[...id].astro @@ -107,24 +107,28 @@ if (isCanonical) { --- <DocsLayout frontmatter={currentEntry.data} {headings}> + {/* noindex for redirect pages */} + {isCanonical && <meta name="robots" content="noindex, follow" slot="head-scripts" />} + { - isCanonical ? ( + isCanonical && ( <script is:inline slot="head-scripts" define:vars={{ goUrl: `/cre/${goEntry!.id}`, tsUrl: `/cre/${tsEntry!.id}` }} set:html={`(function(){try{var s=localStorage.getItem("docs-language-preference"),l=s==="go"||s==='"go"'?"go":"ts",u=l==="go"?goUrl:tsUrl;u&&window.location.replace(u)}catch(e){tsUrl&&window.location.replace(tsUrl)}})();`} /> - ) : ( - goEntry && - tsEntry && ( - <script - is:inline - slot="head-scripts" - define:vars={{ goUrl: `/cre/${goEntry.id}`, tsUrl: `/cre/${tsEntry.id}`, currentLang: entry!.data.sdkLang }} - set:html={`(function(){try{var s=localStorage.getItem("docs-language-preference");if(s){var l=s==="go"||s==='"go"'?"go":"ts";if(l!==currentLang){var u=l==="go"?goUrl:tsUrl;u&&window.location.replace(u)}}else{try{localStorage.setItem("docs-language-preference",currentLang)}catch(e){}}}catch(e){}})();`} - /> - ) + ) + } + + { + !isCanonical && goEntry && tsEntry && ( + <script + is:inline + slot="head-scripts" + define:vars={{ currentLang: entry!.data.sdkLang }} + set:html={`(function(){try{localStorage.setItem("docs-language-preference",currentLang)}catch(e){}})();`} + /> ) } diff --git a/src/pages/index.astro b/src/pages/index.astro index 0c08784a072..3acfe1b9141 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,35 +1,99 @@ --- -import ProductTabs from "../features/landing/sections/ProductTabs.astro" -import LandingLayout from "../layouts/LandingLayout.astro" -import HeroCTA from "../features/landing/sections/HeroCTA.astro" +import JourneyCards from "~/components/JourneyCards/JourneyCards.astro" +import TechnicalStandards from "~/components/TechnicalStandards/TechnicalStandards.astro" import BaseLayout from "~/layouts/BaseLayout.astro" import * as CONFIG from "../config" +import Demos from "~/components/Demos.astro" +import { Typography } from "@chainlink/blocks" +import LandingHero from "~/components/LandingHero/LandingHero.astro" +import TryItOut from "~/components/TryItOut/TryItOut.astro" +import CommunityEvents from "~/components/CommunityEvents/CommunityEvents.astro" const formattedContentTitle = `${CONFIG.PAGE.titleFallback} | ${CONFIG.SITE.title}` --- <BaseLayout title={formattedContentTitle}> <main> - <div class="heroContainer"> - <div class="hero"> - <h1>Chainlink Developer Docs</h1> - <h2>What are you building?</h2> - <ProductTabs /> - </div> + <LandingHero /> + + <div class="wrapper"> + <JourneyCards /> + </div> + + <TryItOut + accordionTabs={[ + { + title: "Build an Orchestrated Workflow", + text: "Use Chainlink CRE to build, test, and deploy advanced workflows for institutional-grade smart contracts without needing to manage new infrastructure or complex onchain logic.", + codeSampleSrc: "/samples/CRE/basic-functionality.ts", + ctas: [ + { text: "Get started with CRE", href: "/cre/getting-started/overview", variant: "primary" }, + { text: "Create CRE account", href: "https://cre.chain.link/signup", variant: "secondary" }, + ], + }, + { + title: "Transfer Tokens Between Chains", + text: "Use Chainlink CCIP to transfer CCIP-BnM tokens from a contract on Avalanche Fuji to an account on Ethereum Sepolia", + codeSampleSrc: "/samples/CCIP/TokenTransferor.sol", + ctas: [ + { + text: "Open in Remix", + href: "https://remix.ethereum.org/#url=https://docs.chain.link/samples/CCIP/TokenTransferor.sol&autoCompile=true", + variant: "primary", + }, + { text: "Read Tutorial", href: "/ccip/tutorials/evm/transfer-tokens-from-contract", variant: "secondary" }, + ], + }, + { + title: "Recapture Oracle Extractable Value", + text: "Use Chainlink Smart Value Recapture (SVR) Feeds to backrun new prices with liquidation transactions and compete for profit.", + codeSampleSrc: "/samples/DataFeeds/SVR/import-aggregatorV3.sol", + ctas: [ + { text: "Integrate SVR Feeds", href: "/data-feeds/svr-feeds", variant: "primary" }, + { + text: "Find SVR-enabled Feeds", + href: "/data-feeds/price-feeds/addresses", + variant: "secondary", + }, + ], + }, + { + title: "Access Real-Time Data for Traditional Financial Markets", + text: "Use the Data Streams SDK in TypeScript/Go/Rust to fetch and decode reports from the Data Streams Aggregation Network.", + codeSampleSrc: "/samples/DataStreams/FetchSingleStream.ts", + ctas: [ + { + text: "Download the SDK", + href: "https://github.com/smartcontractkit/data-streams-sdk", + variant: "primary", + }, + { text: "Read Tutorial", href: "/data-streams/tutorials/ts-sdk-fetch", variant: "secondary" }, + ], + }, + ]} + /> + + <div class="wrapper"> + <Demos /> </div> - <div class="recommended"> - <h4>Recommended reading</h4> - <h2>We think you'd love to explore</h2> - <div> - <a href="/getting-started/conceptual-overview">General</a> - <a href="/resources/link-token-contracts">Link Token Contracts</a> - <a href="/ccip/getting-started">Getting Started with CCIP</a> - <a href="/ccip/directory">CCIP Directory</a> - <a href="/data-feeds/price-feeds/addresses">Data Feed Addresses</a> - <a href="/data-feeds/smartdata/addresses">SmartData Feed Addresses</a> - <a href="/data-streams/getting-started-hardhat">Getting Started with Data Streams</a> - <a href="/data-streams/crypto-streams">Data Streams Addresses</a> + + <CommunityEvents /> + + <div class="wrapper"> + <div class="recommended"> + <h4>Recommended reading</h4> + <h2>We think you'd love to explore</h2> + <div> + <a href="/getting-started/conceptual-overview">General</a> + <a href="/resources/link-token-contracts">Link Token Contracts</a> + <a href="/ccip/getting-started">Getting Started with CCIP</a> + <a href="/ccip/directory">CCIP Directory</a> + <a href="/data-feeds/price-feeds/addresses">Data Feed Addresses</a> + <a href="/data-feeds/smartdata/addresses">SmartData Feed Addresses</a> + <a href="/data-streams/getting-started-hardhat">Getting Started with Data Streams</a> + <a href="/data-streams/crypto-streams">Data Streams Addresses</a> + </div> </div> </div> </main> @@ -134,6 +198,15 @@ const formattedContentTitle = `${CONFIG.PAGE.titleFallback} | ${CONFIG.SITE.titl background-color: var(--blue-100); } + .wrapper { + display: flex; + flex-direction: column; + max-width: var(--fullwidth-max-width); + padding: 0 var(--space-10x); + gap: 36px; + } + + /*800px*/ @media (min-width: 50em) { .hero { max-width: var(--fullwidth-max-width); @@ -159,11 +232,6 @@ const formattedContentTitle = `${CONFIG.PAGE.titleFallback} | ${CONFIG.SITE.titl font-weight: 600; } - .recommended { - margin: var(--space-16x) auto; - max-width: var(--fullwidth-max-width); - } - .heroContainer { background: linear-gradient(180deg, #f1f5fe 0%, white 100%); } @@ -178,8 +246,14 @@ const formattedContentTitle = `${CONFIG.PAGE.titleFallback} | ${CONFIG.SITE.titl line-height: var(--space-6x); margin-bottom: var(--space-2x); } + + .wrapper { + gap: 82px; + } } - @media (min-width: 72em) { + + /* 992px */ + @media (min-width: 62em) { .hero { max-width: min(1200px, calc(100% - 2 * var(--space-16x))); padding: 0; @@ -189,5 +263,10 @@ const formattedContentTitle = `${CONFIG.PAGE.titleFallback} | ${CONFIG.SITE.titl max-width: min(1200px, calc(100% - 2 * var(--space-16x))); padding: 0; } + + .wrapper { + margin: 0 auto; + margin-top: 60px; + } } </style> diff --git a/src/scripts/ccip/detect-new-tokens.ts b/src/scripts/ccip/detect-new-tokens.ts index 85ea71ccb04..a0178595853 100644 --- a/src/scripts/ccip/detect-new-tokens.ts +++ b/src/scripts/ccip/detect-new-tokens.ts @@ -1189,13 +1189,15 @@ function buildTokenSupportMap(tokensData: TokensConfig, lanesData: LanesConfig): Object.keys(lanesData).forEach((sourceChain) => { Object.keys(lanesData[sourceChain]).forEach((destChain) => { const lane = `${sourceChain}-to-${destChain}` - const supportedTokens = lanesData[sourceChain][destChain].supportedTokens || {} + const supportedTokens = lanesData[sourceChain][destChain].supportedTokens || [] - Object.keys(supportedTokens).forEach((tokenSymbol) => { - if (tokenSupport[tokenSymbol]) { - tokenSupport[tokenSymbol].lanes.push(lane) - } - }) + if (Array.isArray(supportedTokens)) { + supportedTokens.forEach((tokenSymbol) => { + if (tokenSupport[tokenSymbol]) { + tokenSupport[tokenSymbol].lanes.push(lane) + } + }) + } }) }) diff --git a/src/scripts/ccip/generate-token-report.ts b/src/scripts/ccip/generate-token-report.ts index 471cf5b35d1..6072f03d42d 100644 --- a/src/scripts/ccip/generate-token-report.ts +++ b/src/scripts/ccip/generate-token-report.ts @@ -87,12 +87,14 @@ function buildTokenSupportMap(tokensData: TokensConfig, lanesData: LanesConfig): Object.keys(lanesData).forEach((sourceChain) => { Object.keys(lanesData[sourceChain]).forEach((destChain) => { const lane = `${sourceChain}-to-${destChain}` - const supportedTokens = lanesData[sourceChain][destChain].supportedTokens || {} - Object.keys(supportedTokens).forEach((tokenSymbol) => { - if (tokenSupport[tokenSymbol]) { - tokenSupport[tokenSymbol].lanes.push(lane) - } - }) + const supportedTokens = lanesData[sourceChain][destChain].supportedTokens || [] + if (Array.isArray(supportedTokens)) { + supportedTokens.forEach((tokenSymbol) => { + if (tokenSupport[tokenSymbol]) { + tokenSupport[tokenSymbol].lanes.push(lane) + } + }) + } }) }) diff --git a/src/scripts/codeSampleCopy.ts b/src/scripts/codeSampleCopy.ts new file mode 100644 index 00000000000..0f82e113132 --- /dev/null +++ b/src/scripts/codeSampleCopy.ts @@ -0,0 +1,39 @@ +function copyText(text: string): Promise<void> { + if (navigator.clipboard && window.isSecureContext) { + return navigator.clipboard.writeText(text) + } + + // Fallback for non-secure contexts (e.g. http://localhost) + const textarea = document.createElement("textarea") + textarea.value = text + textarea.setAttribute("readonly", "") + textarea.style.position = "absolute" + textarea.style.left = "-9999px" + document.body.appendChild(textarea) + textarea.select() + const ok = document.execCommand("copy") + document.body.removeChild(textarea) + return ok ? Promise.resolve() : Promise.reject(new Error("Copy failed")) +} + +document.addEventListener("click", async (e) => { + const target = e.target as HTMLElement | null + const button = (target?.closest?.(".code-sample__copy-button") as HTMLButtonElement | null) ?? null + if (!button) return + + const root = button.closest(".code-sample") + const codeEl = (root?.querySelector("pre code") as HTMLElement | null) ?? null + const text = codeEl ? codeEl.innerText : "" + if (!text) return + + const oldHtml = button.innerHTML + try { + await copyText(text) + button.innerHTML = '<img src="/assets/icons/checkCircleIconGrey.svg" alt="Copied" width="16" height="16" />' + window.setTimeout(() => { + button.innerHTML = oldHtml + }, 1500) + } catch (_err) { + // no-op; keep original UI + } +}) diff --git a/src/scripts/copyToClipboard/copyToClipboard.ts b/src/scripts/copyToClipboard/copyToClipboard.ts index 99201d6a5a5..6a640eae21c 100644 --- a/src/scripts/copyToClipboard/copyToClipboard.ts +++ b/src/scripts/copyToClipboard/copyToClipboard.ts @@ -47,6 +47,16 @@ document.addEventListener("DOMContentLoaded", () => { return // Skip if already initialized } + // Skip if element has data-no-copy-button attribute + if (codeBlock.hasAttribute("data-no-copy-button")) { + return + } + + // Skip CodeSample-style blocks (they have their own header copy button) + if (codeBlock.closest(".code-sample")) { + return + } + const copyButtonContainer = document.createElement("div") copyButtonContainer.className = styles.copyCodeButtonWrapper diff --git a/src/scripts/data/detect-new-data.ts b/src/scripts/data/detect-new-data.ts index d1b0549c3ec..62db69be5b5 100644 --- a/src/scripts/data/detect-new-data.ts +++ b/src/scripts/data/detect-new-data.ts @@ -12,6 +12,7 @@ import fs from "fs" import path from "path" import fetch from "node-fetch" import prettier from "prettier" +import { TOKEN_ICONS_PATH } from "../../config/cdn.js" // Network endpoints mapping for different blockchain networks // Each endpoint provides a JSON file containing feed definitions for that network @@ -49,6 +50,7 @@ const NETWORK_ENDPOINTS: Record<string, string> = { bob: "https://reference-data-directory.vercel.app/feeds-bitcoin-mainnet-bob-1.json", plasma: "https://reference-data-directory.vercel.app/feeds-plasma-mainnet.json", hyperevm: "https://reference-data-directory.vercel.app/feeds-hyperliquid-mainnet.json", + megaeth: "https://reference-data-directory.vercel.app/feeds-megaeth-mainnet.json", } // Path to the baseline JSON file that contains known feed IDs @@ -79,7 +81,7 @@ interface DataItem { * @returns URL to the asset's icon image */ function buildIconUrl(baseAsset: string): string { - return `https://d2f70xi62kby8n.cloudfront.net/tokens/${baseAsset.toLowerCase()}.webp` + return `${TOKEN_ICONS_PATH}/${baseAsset.toLowerCase()}.webp` } /** diff --git a/src/scripts/generate-llms.ts b/src/scripts/generate-llms.ts index 83e2104c634..33221c5d5b4 100644 --- a/src/scripts/generate-llms.ts +++ b/src/scripts/generate-llms.ts @@ -12,6 +12,7 @@ import { LLM_SECTIONS_CONFIG, SUPPORTED_LLM_SECTIONS, type LlmsSectionConfig } f import { SIDEBAR } from "../config/sidebar.js" import type { SectionEntry, SectionContent } from "../config/sidebar.js" import fsSync from "fs" +import { stripHighlightComments, unescapeMarkdown } from "../lib/markdown/index.js" interface MdxJsxAttribute { name: string @@ -85,7 +86,7 @@ async function main() { const lastModified = getIsoStringOrUndefined(fmLastModified) const cleaned = await transformMarkdown(body, absFile, lang) - const cleanedPlain = unescapeForPlainText(cleaned) + const cleanedPlain = unescapeMarkdown(cleaned) const headerLines = [ `# ${title}`, @@ -138,7 +139,7 @@ async function main() { const lastModified = getIsoStringOrUndefined(fmLastModified) const cleaned = await transformMarkdown(body, absFile) - const cleanedPlain = unescapeForPlainText(cleaned) + const cleanedPlain = unescapeMarkdown(cleaned) const headerLines = [ `# ${title}`, @@ -455,10 +456,7 @@ async function transformMarkdown(markdown: string, mdxAbsPath: string, targetLan let codeContent = fsSync.readFileSync(codeAbsPath, "utf-8") // Strip highlighter comments - codeContent = codeContent - .split("\n") - .map((line) => line.replace(/\s*\/\/\s*highlight-(line|start|end)/, "")) - .join("\n") + codeContent = stripHighlightComments(codeContent) // Infer language from file extension const fileExt = path.extname(codeAbsPath).slice(1) @@ -506,10 +504,7 @@ async function transformMarkdown(markdown: string, mdxAbsPath: string, targetLan const codeAbsPath = path.resolve(path.dirname(mdxAbsPath), importPath) let codeContent = fsSync.readFileSync(codeAbsPath, "utf-8") // Strip highlighter comments - codeContent = codeContent - .split("\n") - .map((line) => line.replace(/\s*\/\/\s*highlight-(line|start|end)/, "")) - .join("\n") + codeContent = stripHighlightComments(codeContent) const langAttr = (node as MdxJsxNode).attributes?.find((a) => a.name === "lang") const titleAttr = (node as MdxJsxNode).attributes?.find((a) => a.name === "title") const newNodes: Node[] = [] @@ -583,6 +578,53 @@ async function transformMarkdown(markdown: string, mdxAbsPath: string, targetLan } } + // Handle CodeSample component - inline the code from public/{src} + if ( + parent && + typeof index === "number" && + node.type === "mdxJsxFlowElement" && + (node as MdxJsxNode).name === "CodeSample" + ) { + try { + const srcAttr = (node as MdxJsxNode).attributes?.find((a) => a.name === "src") + const langAttr = (node as MdxJsxNode).attributes?.find((a) => a.name === "lang") + + if (srcAttr?.value) { + const srcValue = typeof srcAttr.value === "string" ? srcAttr.value : undefined + + if (srcValue) { + const publicDir = path.resolve(process.cwd(), "public") + const codePath = path.join(publicDir, srcValue) + + if (fsSync.existsSync(codePath)) { + let codeContent = fsSync.readFileSync(codePath, "utf-8") + + // Strip highlighter comments + codeContent = stripHighlightComments(codeContent) + + // Determine language from lang attribute or file extension + let lang = typeof langAttr?.value === "string" ? langAttr.value : undefined + if (!lang) { + const ext = path.extname(codePath).slice(1) + lang = ext || "text" + } + + // Replace with code block + parent.children[index] = { + type: "code", + lang, + value: codeContent.trim(), + } as Literal + + return + } + } + } + } catch (e) { + console.warn(`Failed to process CodeSample in ${mdxAbsPath}:`, e) + } + } + // Handle CopyText inline component - extract the text attribute if ( parent && @@ -644,28 +686,6 @@ async function transformMarkdown(markdown: string, mdxAbsPath: string, targetLan return String(file) } -function unescapeForPlainText(s: string): string { - let inFence = false - return s - .split("\n") - .map((line) => { - const trimmed = line.trim() - if (trimmed.startsWith("```") || trimmed.startsWith("~~~")) { - inFence = !inFence - return line - } - if (inFence) return line - return line - .replace(/\\_/g, "_") - .replace(/\\\[/g, "[") - .replace(/\\\]/g, "]") - .replace(/\\\(/g, "(") - .replace(/\\\)/g, ")") - }) - .filter((line) => line.trim() !== "{/* prettier-ignore */}") - .join("\n") -} - async function writeReports(report: Report) { const reportsDir = path.resolve("reports") await fs.mkdir(reportsDir, { recursive: true }) diff --git a/src/scripts/index.ts b/src/scripts/index.ts index 2b912568f04..7bb969536c7 100644 --- a/src/scripts/index.ts +++ b/src/scripts/index.ts @@ -1,4 +1,5 @@ import "./fix-remix-urls" import "./fix-external-links" +import "./codeSampleCopy" import "./copyToClipboard/copyToClipboard" import "./scroll-to-search" diff --git a/src/scripts/reference/chains.json b/src/scripts/reference/chains.json index bcec1605b9d..2e4b776e53d 100644 --- a/src/scripts/reference/chains.json +++ b/src/scripts/reference/chains.json @@ -351,32 +351,6 @@ "slip44": 1, "explorers": [{ "name": "monadvision", "url": "https://monadvision.com/", "standard": "EIP3091" }] }, - { - "name": "Nexon Henesys Mainnet", - "chain": "nexon", - "icon": "nexon", - "rpc": ["https://henesys-rpc.msu.io/"], - "faucets": [], - "nativeCurrency": { "name": "NXPC", "symbol": "NXPC", "decimals": 18 }, - "infoURL": "https://henesysstudio.com/", - "shortName": "nexon", - "chainId": 68414, - "networkId": 68414, - "explorers": [{ "name": "avax", "url": "https://subnets.avax.network/henesys", "standard": "EIP3091" }] - }, - { - "name": "Pharos Atlantic Testnet", - "chain": "pharos", - "icon": "pharos", - "rpc": ["https://atlantic.dplabs-internal.com/"], - "faucets": [], - "nativeCurrency": { "name": "PHRS", "symbol": "PHRS", "decimals": 18 }, - "infoURL": "https://www.pharos.xyz/", - "shortName": "pharos", - "chainId": 688689, - "networkId": 688689, - "explorers": [{ "name": "pharosscan", "url": "https://atlantic.pharosscan.xyz/", "standard": "EIP3091" }] - }, { "name": "Sonic Mainnet", "chain": "sonic", @@ -436,22 +410,6 @@ { "name": "blockscout", "url": "https://explorer.mintchain.io", "icon": "mint", "standard": "EIP3091" } ] }, - { - "name": "X Layer Testnet", - "chain": "X Layer", - "rpc": ["https://testrpc.xlayer.tech", "https://xlayertestrpc.okx.com"], - "faucets": ["https://www.okx.com/xlayer/faucet"], - "nativeCurrency": { "name": "X Layer Global Utility Token in testnet", "symbol": "OKB", "decimals": 18 }, - "features": [], - "infoURL": "https://www.okx.com/xlayer", - "shortName": "tokb", - "chainId": 195, - "networkId": 195, - "slip44": 1, - "icon": "xlayerTestnet", - "explorers": [{ "name": "OKLink", "url": "https://www.oklink.com/xlayer-test", "standard": "EIP3091" }], - "status": "active" - }, { "name": "X Layer Mainnet", "chain": "X Layer", @@ -882,7 +840,20 @@ "chainId": 964, "networkId": 964, "slip44": 1005, - "icon": "bittensor" + "icon": "bittensor", + "explorers": [{ "name": "Bittensor EVM Explorer", "url": "https://evm.taostats.io/", "standard": "EIP3091" }] + }, + { + "name": "Stable Mainnet", + "chain": "ETH", + "rpc": ["https://rpc.stable.xyz"], + "faucets": [], + "nativeCurrency": { "name": "gasUSDT", "symbol": "gUSDT", "decimals": 18 }, + "infoURL": "https://docs.stable.xyz/", + "shortName": "Stable", + "chainId": 988, + "networkId": 988, + "explorers": [{ "name": "Stable Mainnet Explorer", "url": "https://stablescan.xyz/", "standard": "EIP3091" }] }, { "name": "HyperEVM Testnet", @@ -1294,6 +1265,21 @@ ], "parent": { "type": "L2", "chain": "eip155-11155111", "bridges": [{ "url": "https://bridge.soneium.org/testnet" }] } }, + { + "name": "X Layer Testnet", + "chain": "X Layer", + "rpc": ["https://testrpc.xlayer.tech/terigon", "https://xlayertestrpc.okx.com/terigon"], + "faucets": ["https://www.okx.com/xlayer/faucet"], + "nativeCurrency": { "name": "X Layer Global Utility Token in testnet", "symbol": "OKB", "decimals": 18 }, + "features": [], + "infoURL": "https://www.okx.com/xlayer", + "shortName": "tokb", + "chainId": 1952, + "networkId": 1952, + "icon": "xlayerTestnet", + "explorers": [{ "name": "OKLink", "url": "https://web3.okx.com/explorer/x-layer-testnet", "standard": "EIP3091" }], + "status": "active" + }, { "name": "Ronin Mainnet", "title": "Ronin Mainnet", @@ -1418,6 +1404,42 @@ ], "parent": { "type": "L2", "chain": "eip155-1", "bridges": [{ "url": "https://portal.mainnet.abs.xyz/bridge" }] } }, + { + "name": "Morph", + "title": "Morph Mainnet", + "chain": "ETH", + "rpc": [ + "https://rpc.morphl2.io", + "wss://rpc.morphl2.io:8443", + "https://rpc-quicknode.morphl2.io", + "wss://rpc-quicknode.morphl2.io" + ], + "faucets": [], + "nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 }, + "infoURL": "https://morphl2.io", + "shortName": "morph", + "chainId": 2818, + "networkId": 2818, + "slip44": 1, + "explorers": [{ "name": "Morph Mainnet Explorer", "url": "https://explorer.morphl2.io", "standard": "EIP3091" }], + "parent": { "type": "L2", "chain": "eip155-1", "bridges": [{ "url": "https://bridge.morphl2.io/" }] } + }, + { + "name": "Morph Hoodi", + "chain": "ETH", + "rpc": ["https://rpc-hoodi.morphl2.io/"], + "faucets": [], + "nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 }, + "infoURL": "https://morphl2.io", + "shortName": "morph", + "chainId": 2910, + "networkId": 2910, + "slip44": 1, + "explorers": [ + { "name": "Morph Hoodi Explorer", "url": "https://explorer-hoodi.morphl2.io", "standard": "EIP3091" } + ], + "parent": { "type": "L2", "chain": "eip155-1", "bridges": [{ "url": "https://bridge.morphl2.io/" }] } + }, { "name": "Botanix Testnet", "chain": "BOTANIX", @@ -1499,6 +1521,18 @@ { "name": "liskscout", "url": "https://sepolia-blockscout.lisk.com", "icon": "blockscout", "standard": "EIP3091" } ] }, + { + "name": "MegaETH Mainnet", + "chain": "ETH", + "nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 }, + "rpc": ["https://mainnet.megaeth.com/rpc"], + "faucets": [], + "explorers": [{ "name": "blockscout", "url": "https://megaeth.blockscout.com/", "standard": "EIP3091" }], + "infoURL": "https://megaeth.com", + "shortName": "megaeth", + "chainId": 4326, + "networkId": 4326 + }, { "name": "World Chain Sepolia Testnet", "chain": "ETH", @@ -1604,7 +1638,7 @@ "name": "MegaETH Testnet", "chain": "ETH", "nativeCurrency": { "name": "MegaETH Testnet Ether", "symbol": "ETH", "decimals": 18 }, - "rpc": ["https://carrot.megaeth.com/rpc", "wss://carrot.megaeth.com/ws"], + "rpc": ["https://timothy.megaeth.com/rpc", "wss://carrot.megaeth.com/ws"], "faucets": [], "infoURL": "https://www.megaeth.com", "shortName": "megatest", @@ -1764,6 +1798,27 @@ "networkId": 13505, "explorers": [{ "name": "Blockscout", "url": "https://explorer-sepolia.gravity.xyz", "standard": "EIP3091" }] }, + { + "name": "Sonic Testnet", + "chain": "sonic-testnet", + "rpc": ["https://rpc.testnet.soniclabs.com"], + "faucets": ["https://testnet.soniclabs.com/account"], + "nativeCurrency": { "name": "Sonic", "symbol": "S", "decimals": 18 }, + "features": [{ "name": "EIP155" }], + "infoURL": "https://testnet.soniclabs.com", + "shortName": "sonic-testnet", + "chainId": 14601, + "networkId": 14601, + "icon": "sonic", + "explorers": [ + { + "name": "Sonic Testnet Explorer", + "url": "https://explorer.testnet.soniclabs.com", + "icon": "sonic", + "standard": "none" + } + ] + }, { "name": "0G-Galileo-Testnet", "chain": "0G-Testnet", @@ -1928,6 +1983,18 @@ { "name": "blockscout", "url": "https://explorer.celo.org", "standard": "none" } ] }, + { + "name": "Tempo Testnet", + "chain": "ETH", + "nativeCurrency": { "name": "USD", "symbol": "USD", "decimals": 18 }, + "rpc": ["https://rpc.testnet.tempo.xyz"], + "faucets": [], + "explorers": [{ "name": "Tempo Explorer", "url": "https://explore.tempo.xyz", "standard": "none" }], + "infoURL": "https://tempo.xyz/", + "shortName": "megaeth", + "chainId": 42429, + "networkId": 42429 + }, { "name": "Etherlink Mainnet", "chain": "Etherlink", @@ -2225,6 +2292,19 @@ ], "parent": { "type": "L2", "chain": "eip155-1", "bridges": [{ "url": "https://app.treasure.lol/chain/bridge" }] } }, + { + "name": "Nexon Henesys Mainnet", + "chain": "nexon", + "icon": "nexon", + "rpc": ["https://henesys-rpc.msu.io/"], + "faucets": [], + "nativeCurrency": { "name": "NXPC", "symbol": "NXPC", "decimals": 18 }, + "infoURL": "https://henesysstudio.com/", + "shortName": "nexon", + "chainId": 68414, + "networkId": 68414, + "explorers": [{ "name": "avax", "url": "https://subnets.avax.network/henesys", "standard": "EIP3091" }] + }, { "name": "Amoy", "title": "Polygon Amoy Testnet", @@ -2584,6 +2664,22 @@ "explorers": [{ "name": "Scrollscan", "url": "https://scrollscan.com", "standard": "EIP3091" }], "parent": { "type": "L2", "chain": "eip155-1", "bridges": [{ "url": "https://scroll.io/bridge" }] } }, + { + "name": "Ethereum Hoodi", + "title": "Ethereum Testnet Hoodi", + "chain": "ETH", + "icon": "ethereum", + "rpc": ["https://rpc.hoodi.ethpandaops.io"], + "features": [{ "name": "EIP155" }, { "name": "EIP1559" }], + "faucets": ["https://faucet.hoodi.ethpandaops.io", "https://hoodi-faucet.pk910.de/"], + "nativeCurrency": { "name": "Hoodi Ether", "symbol": "ETH", "decimals": 18 }, + "infoURL": "https://hoodi.ethpandaops.io", + "shortName": "hoe", + "chainId": 560048, + "networkId": 560048, + "slip44": 1, + "explorers": [{ "name": "Hoodi", "url": "https://hoodi.etherscan.io/", "standard": "none" }] + }, { "name": "Merlin Testnet", "chainId": 686868, @@ -2597,6 +2693,19 @@ "explorers": [{ "name": "Merlin Testnet", "url": "https://testnet-scan.merlinchain.io/", "standard": "none" }], "infoURL": "https://merlinchain.io/" }, + { + "name": "Pharos Atlantic Testnet", + "chain": "pharos", + "icon": "pharos", + "rpc": ["https://atlantic.dplabs-internal.com/"], + "faucets": [], + "nativeCurrency": { "name": "PHRS", "symbol": "PHRS", "decimals": 18 }, + "infoURL": "https://www.pharos.xyz/", + "shortName": "pharos", + "chainId": 688689, + "networkId": 688689, + "explorers": [{ "name": "pharosscan", "url": "https://atlantic.pharosscan.xyz/", "standard": "EIP3091" }] + }, { "name": "Hemi Sepolia", "chain": "ETH", @@ -2695,6 +2804,71 @@ ], "parent": { "type": "L2", "chain": "eip155-1", "bridges": [{ "url": "https://app.treasure.lol/chain/bridge" }] } }, + { + "name": "Jovay Sepolia Testnet", + "chain": "ETH", + "status": "active", + "rpc": [ + "https://api.zan.top/public/jovay-testnet", + "https://api.zan.top/node/v1/jovay/testnet/${ZAN_API_KEY}", + "wss://api.zan.top/node/ws/v1/jovay/testnet/${ZAN_API_KEY}" + ], + "faucets": ["https://zan.top/faucet/jovay"], + "nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 }, + "infoURL": "https://jovay.io", + "shortName": "jovay-sepolia", + "chainId": 2019775, + "networkId": 2019775, + "icon": "jovay", + "slip44": 1, + "explorers": [ + { "name": "Jovay Testnet Explorer", "url": "https://sepolia-explorer.jovay.io/l2", "standard": "none" } + ], + "parent": { + "type": "L2", + "chain": "eip155-11155111", + "bridges": [{ "url": "https://docs.jovay.io/guide/developer-quickstart" }] + } + }, + { + "name": "Arc Network Testnet", + "chain": "Arc Network", + "icon": "arcnetwork", + "rpc": [ + "https://rpc.testnet.arc.network", + "wss://rpc.testnet.arc.network", + "https://rpc.quicknode.testnet.arc.network", + "wss://rpc.quicknode.testnet.arc.network", + "https://rpc.blockdaemon.testnet.arc.network" + ], + "faucets": ["https://faucet.circle.com/"], + "nativeCurrency": { "name": "USDC", "symbol": "USDC", "decimals": 18 }, + "infoURL": "https://arc.network", + "shortName": "arc-testnet", + "chainId": 5042002, + "networkId": 5042002, + "slip44": 1, + "explorers": [{ "name": "Arcscan", "url": "https://testnet.arcscan.app", "standard": "EIP3091" }] + }, + { + "name": "Jovay Mainnet", + "chain": "ETH", + "status": "active", + "rpc": [ + "https://rpc.jovay.io", + "https://api.zan.top/node/v1/jovay/mainnet/${ZAN_API_KEY}", + "wss://api.zan.top/node/ws/v1/jovay/mainnet/${ZAN_API_KEY}" + ], + "faucets": [], + "nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 }, + "infoURL": "https://jovay.io", + "shortName": "jovay", + "chainId": 5734951, + "networkId": 5734951, + "icon": "jovay", + "explorers": [{ "name": "Jovay Explorer", "url": "https://explorer.jovay.io/l2", "standard": "none" }], + "parent": { "type": "L2", "chain": "eip155-1", "bridges": [] } + }, { "name": "Zora", "chain": "ETH", @@ -2708,6 +2882,19 @@ "networkId": 7777777, "explorers": [{ "name": "Zora Network Explorer", "url": "https://explorer.zora.energy", "standard": "EIP3091" }] }, + { + "name": "DogeOS Chikyū Testnet", + "chain": "DogeOS", + "rpc": ["https://rpc.testnet.dogeos.com/"], + "faucets": ["https://faucet.testnet.dogeos.com"], + "nativeCurrency": { "name": "Doge", "symbol": "DOGE", "decimals": 18 }, + "icon": "doge", + "infoURL": "https://www.dogeos.com/", + "shortName": "doge", + "chainId": 6281971, + "networkId": 6281971, + "explorers": [{ "name": "Blockscout", "url": "https://blockscout.testnet.dogeos.com", "standard": "EIP3091" }] + }, { "name": "Sepolia", "title": "Ethereum Testnet Sepolia", diff --git a/src/scripts/reference/linkNameSymbol.json b/src/scripts/reference/linkNameSymbol.json index ae28aa575cb..49355e3189e 100644 --- a/src/scripts/reference/linkNameSymbol.json +++ b/src/scripts/reference/linkNameSymbol.json @@ -623,5 +623,53 @@ "68414": { "name": "ChainLink Token", "symbol": "LINK" + }, + "5734951": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "2019775": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "2818": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "2910": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "988": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "42429": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "4326": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "560048": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "5042002": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "1952": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "14601": { + "name": "ChainLink Token", + "symbol": "LINK" + }, + "6281971": { + "name": "ChainLink Token", + "symbol": "LINK" } } diff --git a/src/stores/tryItOutStore.ts b/src/stores/tryItOutStore.ts new file mode 100644 index 00000000000..fe13f6662e9 --- /dev/null +++ b/src/stores/tryItOutStore.ts @@ -0,0 +1,3 @@ +import { atom } from "nanostores" + +export const activeAccordionIndex = atom(0) diff --git a/src/styles/code-blocks.css b/src/styles/code-blocks.css new file mode 100644 index 00000000000..652650faeee --- /dev/null +++ b/src/styles/code-blocks.css @@ -0,0 +1,119 @@ +/* Shared styles for custom code blocks (CodeSample + future fenced blocks) */ + +.code-sample { + margin: 1rem 0; + border-radius: 8px; + overflow: hidden; +} + +.code-sample__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; + padding: 10px 14px 11px 14px; + background: #3a3a3a; + color: #e0e0e0; + font-family: var( + --font-mono, + ui-monospace, + SFMono-Regular, + Menlo, + Monaco, + Consolas, + "Liberation Mono", + "Courier New", + monospace + ); + font-size: 0.9rem; + line-height: 1; +} + +.code-sample__header-left { + display: flex; + align-items: center; + gap: 0.75rem; + min-width: 0; +} + +.code-sample__lang { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 30px; + height: 24px; + padding: 0 6px; + border-radius: 6px; + background: rgba(255, 255, 255, 0.1); + font-weight: 600; + letter-spacing: 0.02em; +} + +.code-sample__lang-icon { + width: 24px; + height: 24px; + display: block; + object-fit: contain; +} + +.code-sample__lang-icon, +.code-sample__copy-button > img { + filter: brightness(0) invert(1); + opacity: 0.95; +} + +/* When we render an icon, drop the "badge" background block. */ +.code-sample__lang--icon { + background: transparent; + padding: 0; + min-width: 24px; + border-radius: 0; +} + +.code-sample__filename { + font-size: 0.95rem; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.code-sample__copy-button { + display: inline-flex; + align-items: center; + justify-content: center; + width: 34px; + height: 34px; + padding: 0; + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.15); + background: rgba(255, 255, 255, 0.08); + cursor: pointer; + flex: 0 0 auto; +} + +.code-sample__copy-button:hover { + background: rgba(255, 255, 255, 0.12); +} + +.code-sample__copy-button:focus-visible { + outline: 2px solid rgba(255, 255, 255, 0.35); + outline-offset: 2px; +} + +.code-sample__copy-button > img { + display: block; +} + +.code-sample__pre--with-header { + margin: 0; + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; +} + +/* Fenced blocks wrapped via remark won't have CodeSample's pre classes. */ +.code-sample > pre { + margin: 0; + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; +} diff --git a/src/styles/index.css b/src/styles/index.css index 8593eab6ab5..805359ae635 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -1,6 +1,6 @@ -/* +/* * Global styles and CSS variables - * + * * This file contains: * 1. CSS reset and base styles * 2. Global CSS variables for theming @@ -24,6 +24,9 @@ --user-font-scale: 1rem - 16px; --max-width: calc(100%); --fullwidth-max-width: calc(100% - 1rem); + + /* Page background and border colors */ + --Page-Background-Alt: #fafbfc; } /* Fonts provided via centralized design system/CDN; no local @font-face overrides here. */ diff --git a/src/styles/migrated.css b/src/styles/migrated.css index fec2d830359..6cb113bb278 100644 --- a/src/styles/migrated.css +++ b/src/styles/migrated.css @@ -14,37 +14,37 @@ border-radius: 6px; box-sizing: border-box; text-decoration: none !important; - color: #ffffff; + color: #ffffff !important; background-color: #375bd2; text-align: center; transition: all 0.2s; } .remix-callout > a:hover { - color: #ffffff; + color: #ffffff !important; background-color: #1a2b6b; border: 2px solid var(--gray-900); } .remix-callout > a:active { - color: #ffffff; + color: #ffffff !important; background-color: var(--gray-900); border: 2px solid var(--gray-900); } .remix-callout > a:nth-of-type(n + 2) { - color: #375bd2; + color: #375bd2 !important; background-color: #ffffff; } .remix-callout > a:nth-of-type(n + 2):hover { - color: #1a2b6b; + color: #1a2b6b !important; background-color: #f5f7fd; border: 2px solid #1a2b6b; } .remix-callout > a:nth-of-type(n + 2):active { - color: var(--gray-900); + color: var(--gray-900) !important; background-color: #f5f7fd; border: 2px solid var(--gray-900); } diff --git a/src/styles/theme.css b/src/styles/theme.css index 2f394ceb5d0..a922dafcf53 100644 --- a/src/styles/theme.css +++ b/src/styles/theme.css @@ -44,6 +44,10 @@ --color-gray-90: var(--color-base-gray), 90%; --color-gray-95: var(--color-base-gray), 95%; + /* Tertiary color aliases (matches design system) */ + --tertiary-border: #d1d6de; + --tertiary-foreground: #0e1119; + --color-blue: var(--color-base-blue), 61%; --color-blue-dark: var(--color-base-blue-dark), 39%; --color-green: var(--color-base-green), 42%; diff --git a/src/tests/chain-api.test.ts b/src/tests/chain-api.test.ts index da55a4ea2dd..346f5127e13 100644 --- a/src/tests/chain-api.test.ts +++ b/src/tests/chain-api.test.ts @@ -7,9 +7,9 @@ import { createMetadata, CCIPError, handleApiError, -} from "../pages/api/ccip/utils.ts" +} from "~/lib/ccip/utils.ts" import type { Environment } from "../config/data/ccip/types.ts" -import { ChainDataService } from "../pages/api/services/chain-data.ts" +import { ChainDataService } from "~/lib/ccip/services/chain-data.ts" import { mockReferenceData } from "../__mocks__/chainMock.ts" // Mock the Environment enum diff --git a/src/utils/changelogFilterUtils.ts b/src/utils/changelogFilterUtils.ts new file mode 100644 index 00000000000..718e96c11ff --- /dev/null +++ b/src/utils/changelogFilterUtils.ts @@ -0,0 +1,85 @@ +/** + * Utility functions for changelog filter management + */ + +/** + * Parse URL parameters to extract filter state + */ +export function parseURLParams(): { + products: string[] + networks: string[] + types: string[] + searchTerm: string + searchExpanded: boolean +} { + if (typeof window === "undefined") { + return { + products: [], + networks: [], + types: [], + searchTerm: "", + searchExpanded: false, + } + } + + const params = new URLSearchParams(window.location.search) + const productParam = params.get("product") + const networkParam = params.get("network") + const typeParam = params.get("type") + const searchParam = params.get("*") + + return { + products: productParam ? productParam.split(",") : [], + networks: networkParam ? networkParam.split(",") : [], + types: typeParam ? typeParam.split(",") : [], + searchTerm: searchParam || "", + searchExpanded: !!searchParam, + } +} + +/** + * Build URL search parameters from filter state + */ +export function buildFilterURL( + products: string[], + networks: string[], + types: string[], + searchTerm: string +): URLSearchParams { + const params = new URLSearchParams() + + if (searchTerm) { + params.set("*", searchTerm) + } else { + if (products.length > 0) { + params.set("product", products.join(",")) + } + if (networks.length > 0) { + params.set("network", networks.join(",")) + } + if (types.length > 0) { + params.set("type", types.join(",")) + } + } + + return params +} + +/** + * Update browser URL with filter parameters + */ +export function updateFilterURL(products: string[], networks: string[], types: string[], searchTerm: string): void { + if (typeof window === "undefined") return + + const params = buildFilterURL(products, networks, types, searchTerm) + const newURL = params.toString() ? `?${params.toString()}` : window.location.pathname + + window.history.replaceState({}, "", newURL) +} + +/** + * Toggle an item in an array (add if not present, remove if present) + */ +export function toggleItemInArray<T>(array: T[], item: T): T[] { + return array.includes(item) ? array.filter((i) => i !== item) : [...array, item] +} diff --git a/src/utils/changelogFilters.ts b/src/utils/changelogFilters.ts new file mode 100644 index 00000000000..f9d2fc3290b --- /dev/null +++ b/src/utils/changelogFilters.ts @@ -0,0 +1,106 @@ +import { ChangelogItem } from "~/components/ChangelogSnippet/types.ts" + +/** + * Extracts network names from the HTML networks field + * Networks are hidden in divs with fs-cmsfilter-field="network" class + */ +export function extractNetworkFromHtml(html: string): string[] { + const networks: string[] = [] + const regex = /<div[^>]*fs-cmsfilter-field="network"[^>]*class="hidden"[^>]*>(.*?)<\/div>/g + let match + + while ((match = regex.exec(html)) !== null) { + const networkName = match[1].trim() + if (networkName) { + networks.push(networkName) + } + } + + return networks +} + +/** + * Extracts all unique networks from changelog items + */ +export function getUniqueNetworks(items: ChangelogItem[]): string[] { + const networksSet = new Set<string>() + + items.forEach((item) => { + if (item.networks) { + const networks = extractNetworkFromHtml(item.networks) + networks.forEach((network) => networksSet.add(network)) + } + }) + + return Array.from(networksSet).sort() +} + +/** + * Extracts all unique topics from changelog items + */ +export function getUniqueTopics(items: ChangelogItem[]): string[] { + const topicsSet = new Set<string>() + + items.forEach((item) => { + if (item.topic) { + topicsSet.add(item.topic) + } + }) + + return Array.from(topicsSet).sort() +} + +/** + * Extracts all unique types from changelog items + */ +export function getUniqueTypes(items: ChangelogItem[]): string[] { + const typesSet = new Set<string>() + + items.forEach((item) => { + if (item.type) { + typesSet.add(item.type) + } + }) + + return Array.from(typesSet).sort() +} + +/** + * Checks if a changelog item matches the selected filters + */ +export function matchesFilters( + item: ChangelogItem, + selectedProducts: string[], + selectedNetworks: string[], + selectedTypes: string[] +): boolean { + // If no filters selected, show all items + const hasProductFilter = selectedProducts.length > 0 + const hasNetworkFilter = selectedNetworks.length > 0 + const hasTypeFilter = selectedTypes.length > 0 + + if (!hasProductFilter && !hasNetworkFilter && !hasTypeFilter) { + return true + } + + // Check product filter (matches against item.topic field) + if (hasProductFilter && !selectedProducts.includes(item.topic)) { + return false + } + + // Check type filter + if (hasTypeFilter && !selectedTypes.includes(item.type)) { + return false + } + + // Check network filter + if (hasNetworkFilter) { + const itemNetworks = extractNetworkFromHtml(item.networks) + const hasMatchingNetwork = selectedNetworks.some((network) => itemNetworks.includes(network)) + if (!hasMatchingNetwork) { + return false + } + } + + return true +} diff --git a/src/workers/data-worker.ts b/src/workers/data-worker.ts index 0d1ce44e2f9..db3cf94b45f 100644 --- a/src/workers/data-worker.ts +++ b/src/workers/data-worker.ts @@ -33,6 +33,13 @@ interface SearchData { } lane: LaneConfig }> + verifiers: Array<{ + id: string + name: string + type: string + logo: string + totalNetworks: number + }> } interface WorkerMessage { @@ -44,6 +51,7 @@ interface WorkerResponse { networks: SearchData["chains"] tokens: SearchData["tokens"] lanes: SearchData["lanes"] + verifiers: SearchData["verifiers"] } self.onmessage = (event: MessageEvent<WorkerMessage>) => { @@ -51,7 +59,7 @@ self.onmessage = (event: MessageEvent<WorkerMessage>) => { const { search, data } = event.data if (!search || !data) { - self.postMessage({ networks: [], tokens: [], lanes: [] } as WorkerResponse) + self.postMessage({ networks: [], tokens: [], lanes: [], verifiers: [] } as WorkerResponse) return } @@ -69,12 +77,20 @@ self.onmessage = (event: MessageEvent<WorkerMessage>) => { lane.sourceNetwork.name.toLowerCase().includes(searchLower) || lane.destinationNetwork.name.toLowerCase().includes(searchLower) - const hasTokens = lane.lane.supportedTokens ? Object.keys(lane.lane.supportedTokens).length > 0 : false + const hasTokens = lane.lane.supportedTokens ? lane.lane.supportedTokens.length > 0 : false return matchesNetwork && hasTokens }) - self.postMessage({ networks, tokens, lanes } as WorkerResponse) + // Filter verifiers + const verifiers = data.verifiers.filter( + (verifier) => + verifier.name.toLowerCase().includes(searchLower) || + verifier.id.toLowerCase().includes(searchLower) || + verifier.type.toLowerCase().includes(searchLower) + ) + + self.postMessage({ networks, tokens, lanes, verifiers } as WorkerResponse) } // Export types for use in main thread diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000000..3dc5b2f5d48 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,4 @@ +import baseConfig from "@chainlink/blocks/src/theme/base" +/** @type {import('tailwindcss').Config} */ + +export default baseConfig diff --git a/tsconfig.json b/tsconfig.json index b5df96aeb68..b718b196200 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "target": "ESNext", "module": "NodeNext", "moduleResolution": "nodenext", + "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true,