From 7e5f65a0863578c83c5f309a49014134d2b9fb51 Mon Sep 17 00:00:00 2001 From: defiQUG Date: Sat, 18 Apr 2026 12:05:34 -0700 Subject: [PATCH] feat: refresh token list and oracle provider wiring --- README.md | 2 +- chain138-snap-minimal | 2 +- config/token-list.json | 254 +---------------------------------------- provider/index.js | 2 + provider/oracles.js | 124 ++++++++++++++++---- provider/types.d.ts | 7 ++ 6 files changed, 114 insertions(+), 277 deletions(-) diff --git a/README.md b/README.md index e26ad38..be0ce52 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This repository contains all MetaMask integration components for ChainID 138, including: - Network configuration -- Token lists +- Token lists (**`config/token-list.json`** mirrors the parent repo **`token-lists/lists/dbis-138.tokenlist.json`**; live apps typically use **`https://explorer.d-bis.org/api/config/token-list`** for the multichain DUAL list) - Price feed integration - **Smart Accounts Kit integration** ✅ - Documentation diff --git a/chain138-snap-minimal b/chain138-snap-minimal index 5293b62..8c52fea 160000 --- a/chain138-snap-minimal +++ b/chain138-snap-minimal @@ -1 +1 @@ -Subproject commit 5293b62a615e12da38649ff307d8d37de88ce46b +Subproject commit 8c52fea84585719bb40e8b38ac6a2ff0230b355c diff --git a/config/token-list.json b/config/token-list.json index feac54e..1871d51 100644 --- a/config/token-list.json +++ b/config/token-list.json @@ -1,253 +1 @@ -{ - "name": "SMOM-DBIS-138 Token List", - "version": { - "major": 1, - "minor": 5, - "patch": 0 - }, - "timestamp": "2026-04-04T04:23:53.362Z", - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/chain138-list.svg", - "keywords": [ - "chain138", - "dbis", - "defi-oracle-meta", - "metamask" - ], - "tokens": [ - { - "chainId": 138, - "address": "0xD51482e567c03899eecE3CAe8a058161FD56069D", - "name": "Australian Dollar (Compliant)", - "symbol": "cAUDC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cAUDC.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0x54dBd40cF05e15906A2C21f600937e96787f5679", - "name": "Canadian Dollar (Compliant)", - "symbol": "cCADC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cCADC.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0x873990849DDa5117d7C644f0aF24370797C03885", - "name": "Swiss Franc (Compliant)", - "symbol": "cCHFC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cCHFC.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0x8085961F9cF02b4d800A3c6d386D31da4B34266a", - "name": "Euro Coin (Compliant)", - "symbol": "cEURC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cEURC.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0xdf4b71c61E5912712C1Bdd451416B9aC26949d72", - "name": "Tether EUR (Compliant)", - "symbol": "cEURT", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cEURT.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0x003960f16D9d34F2e98d62723B6721Fb92074aD2", - "name": "Pound Sterling (Compliant)", - "symbol": "cGBPC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cGBPC.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0x350f54e4D23795f86A9c03988c7135357CCaD97c", - "name": "Tether GBP (Compliant)", - "symbol": "cGBPT", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cGBPT.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0xEe269e1226a334182aace90056EE4ee5Cc8A6770", - "name": "Japanese Yen (Compliant)", - "symbol": "cJPYC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cJPYC.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0xf22258f57794CC8E06237084b353Ab30fFfa640b", - "name": "Compliant USD Coin", - "symbol": "cUSDC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cUSDC.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0x93E66202A11B1772E55407B32B44e5Cd8eda7f22", - "name": "Compliant Tether USD", - "symbol": "cUSDT", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cUSDT.svg", - "tags": [ - "stablecoin", - "defi", - "compliant" - ] - }, - { - "chainId": 138, - "address": "0x290E52a8819A4fbD0714E517225429aA2B70EC6b", - "name": "Gold (Compliant)", - "symbol": "cXAUC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cXAUC.svg", - "tags": [ - "defi", - "compliant" - ], - "extensions": { - "unitOfAccount": "troy_ounce", - "unitDescription": "1 full token (10^decimals base units) = 1 troy oz fine gold" - } - }, - { - "chainId": 138, - "address": "0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E", - "name": "Tether XAU (Compliant)", - "symbol": "cXAUT", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cXAUT.svg", - "tags": [ - "defi", - "compliant" - ], - "extensions": { - "unitOfAccount": "troy_ounce", - "unitDescription": "1 full token (10^decimals base units) = 1 troy oz fine gold" - } - }, - { - "chainId": 138, - "address": "0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6", - "name": "ETH/USD Price Feed", - "symbol": "ETH-USD", - "decimals": 8, - "logoURI": "https://ipfs.io/ipfs/QmPZuycjyJEe2otREuQ5HirvPJ8X6Yc6MBtwz1VhdD79pY", - "tags": [ - "oracle", - "price-feed" - ] - }, - { - "chainId": 138, - "address": "0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03", - "name": "Chainlink Token", - "symbol": "LINK", - "decimals": 18, - "logoURI": "https://ipfs.io/ipfs/QmenWcmfNGfssz4HXvrRV912eZDiKqLTt6z2brRYuTGz9A", - "tags": [ - "defi", - "oracle", - "ccip" - ] - }, - { - "chainId": 138, - "address": "0x71D6687F38b93CCad569Fa6352c876eea967201b", - "name": "USD Coin (Official Mirror)", - "symbol": "USDC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png", - "tags": [ - "stablecoin", - "defi" - ] - }, - { - "chainId": 138, - "address": "0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1", - "name": "Tether USD (Official Mirror)", - "symbol": "USDT", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xdAC17F958D2ee523a2206206994597C13D831ec7/logo.png", - "tags": [ - "stablecoin", - "defi" - ] - }, - { - "chainId": 138, - "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - "name": "Wrapped Ether", - "symbol": "WETH", - "decimals": 18, - "logoURI": "https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong", - "tags": [ - "defi", - "wrapped" - ] - }, - { - "chainId": 138, - "address": "0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F", - "name": "Wrapped Ether v10", - "symbol": "WETH10", - "decimals": 18, - "logoURI": "https://ipfs.io/ipfs/QmanDFPHxnbKd6SSNzzXHf9GbpL9dLXSphxDZSPPYE6ds4", - "tags": [ - "defi", - "wrapped" - ] - } - ] -} +{"name":"DBIS Chain 138 Token List","version":{"major":1,"minor":7,"patch":4},"timestamp":"2026-04-14T22:00:00.000Z","keywords":["dbis","chain138","defi oracle meta"],"logoURI":"https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/chain138-list.svg","tokens":[{"chainId":138,"address":"0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6","name":"ETH/USD Price Feed","symbol":"ETH-USD","decimals":8,"logoURI":"https://ipfs.io/ipfs/QmPZuycjyJEe2otREuQ5HirvPJ8X6Yc6MBtwz1VhdD79pY","tags":["oracle","pricefeed"]},{"chainId":138,"address":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","name":"Wrapped Ether","symbol":"WETH","decimals":18,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["defi","wrapped"],"extensions":{"aliasSymbols":["WETH9"],"aliasNote":"Expose WETH9 as a compatibility alias on surfaces that distinguish WETH9 branding; canonical symbol remains WETH."}},{"chainId":138,"address":"0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F","name":"Wrapped Ether v10","symbol":"WETH10","decimals":18,"logoURI":"https://ipfs.io/ipfs/QmanDFPHxnbKd6SSNzzXHf9GbpL9dLXSphxDZSPPYE6ds4","tags":["defi","wrapped"]},{"chainId":138,"address":"0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03","name":"Chainlink Token","symbol":"LINK","decimals":18,"logoURI":"https://ipfs.io/ipfs/QmenWcmfNGfssz4HXvrRV912eZDiKqLTt6z2brRYuTGz9A","tags":["defi","oracle","ccip"]},{"chainId":138,"address":"0x93E66202A11B1772E55407B32B44e5Cd8eda7f22","name":"Tether USD (Compliant)","symbol":"cUSDT","decimals":6,"logoURI":"https://explorer.d-bis.org/token-icons/cUSDT.png","tags":["stablecoin","defi","compliant"],"extensions":{"currencyCode":"USD","gruVersion":"v1","forwardCanonical":false,"x402Ready":false}},{"chainId":138,"address":"0x9FBfab33882Efe0038DAa608185718b772EE5660","name":"Tether USD (Compliant V2)","symbol":"cUSDT","decimals":6,"logoURI":"https://explorer.d-bis.org/token-icons/cUSDT.png","tags":["stablecoin","defi","compliant","v2","x402","fwdcanon"],"extensions":{"currencyCode":"USD","gruVersion":"v2","forwardCanonical":true,"x402Ready":true,"explorerLabel":"Chain 138 cUSDT V2 forward canonical"}},{"chainId":138,"address":"0xf22258f57794CC8E06237084b353Ab30fFfa640b","name":"USD Coin (Compliant)","symbol":"cUSDC","decimals":6,"logoURI":"https://explorer.d-bis.org/token-icons/cUSDC.png","tags":["stablecoin","defi","compliant"],"extensions":{"currencyCode":"USD","gruVersion":"v1","forwardCanonical":false,"x402Ready":false}},{"chainId":138,"address":"0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d","name":"USD Coin (Compliant V2)","symbol":"cUSDC","decimals":6,"logoURI":"https://explorer.d-bis.org/token-icons/cUSDC.png","tags":["stablecoin","defi","compliant","v2","x402","fwdcanon"],"extensions":{"currencyCode":"USD","gruVersion":"v2","forwardCanonical":true,"x402Ready":true,"explorerLabel":"Chain 138 cUSDC V2 forward canonical"}},{"chainId":138,"address":"0x71D6687F38b93CCad569Fa6352c876eea967201b","name":"USD Coin (Chain 138)","symbol":"USDC","decimals":6,"logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png","tags":["stablecoin","defi"]},{"chainId":138,"address":"0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1","name":"Tether USD (Chain 138)","symbol":"USDT","decimals":6,"logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xdAC17F958D2ee523a2206206994597C13D831ec7/logo.png","tags":["stablecoin","defi"]},{"chainId":138,"address":"0x8085961F9cF02b4d800A3c6d386D31da4B34266a","name":"Euro Coin (Compliant)","symbol":"cEURC","decimals":6,"logoURI":"https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cEURC.svg","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0xdf4b71c61E5912712C1Bdd451416B9aC26949d72","name":"Tether EUR (Compliant)","symbol":"cEURT","decimals":6,"logoURI":"https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cEURT.svg","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x003960f16D9d34F2e98d62723B6721Fb92074aD2","name":"Pound Sterling (Compliant)","symbol":"cGBPC","decimals":6,"logoURI":"https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cGBPC.svg","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x350f54e4D23795f86A9c03988c7135357CCaD97c","name":"Tether GBP (Compliant)","symbol":"cGBPT","decimals":6,"logoURI":"https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cGBPT.svg","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0xD51482e567c03899eecE3CAe8a058161FD56069D","name":"Australian Dollar (Compliant)","symbol":"cAUDC","decimals":6,"logoURI":"https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cAUDC.svg","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0xEe269e1226a334182aace90056EE4ee5Cc8A6770","name":"Japanese Yen (Compliant)","symbol":"cJPYC","decimals":6,"logoURI":"https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cJPYC.svg","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x873990849DDa5117d7C644f0aF24370797C03885","name":"Swiss Franc (Compliant)","symbol":"cCHFC","decimals":6,"logoURI":"https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cCHFC.svg","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x54dBd40cF05e15906A2C21f600937e96787f5679","name":"Canadian Dollar (Compliant)","symbol":"cCADC","decimals":6,"logoURI":"https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru/cCADC.svg","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x290E52a8819A4fbD0714E517225429aA2B70EC6b","name":"Gold (Compliant)","symbol":"cXAUC","decimals":6,"logoURI":"https://explorer.d-bis.org/token-icons/cXAUC.png","tags":["defi","compliant"],"extensions":{"unitOfAccount":"troy_ounce","unitDescription":"1 full token = 1 troy oz fine gold"}},{"chainId":138,"address":"0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E","name":"Tether XAU (Compliant)","symbol":"cXAUT","decimals":6,"logoURI":"https://explorer.d-bis.org/token-icons/cXAUT.png","tags":["defi","compliant"],"extensions":{"unitOfAccount":"troy_ounce","unitDescription":"1 full token = 1 troy oz fine gold"}},{"chainId":138,"address":"0xF8e9802a1766422e33a269556AD5fC032338EeFc","name":"Ethereum Mainnet Gas (Compliant)","symbol":"cETH","logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png","decimals":18,"tags":["defi","compliant","gasnative"],"extensions":{"assetClass":"gas_native","familyKey":"eth_mainnet","mirroredSymbol":"cWETH","backingMode":"strict_escrow","redeemPolicy":"family_only","canonicalChainId":138,"wave":"wave1"}},{"chainId":138,"address":"0x18A6B163d255cC0Cb32B99697843b487D059907d","name":"Ethereum L2 Gas (Compliant)","symbol":"cETHL2","logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png","decimals":18,"tags":["defi","compliant","gasnative"],"extensions":{"assetClass":"gas_native","familyKey":"eth_l2","mirroredSymbol":"cWETHL2","backingMode":"hybrid_cap","redeemPolicy":"family_fungible_inventory_gated","canonicalChainId":138,"wave":"wave1"}},{"chainId":138,"address":"0x94517875f32680984a5921DA7abf78E22f65d70F","name":"BNB Gas (Compliant)","symbol":"cBNB","logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/smartchain/info/logo.png","decimals":18,"tags":["defi","compliant","gasnative"],"extensions":{"assetClass":"gas_native","familyKey":"bnb","mirroredSymbol":"cWBNB","backingMode":"hybrid_cap","redeemPolicy":"family_only","canonicalChainId":138,"wave":"wave1"}},{"chainId":138,"address":"0x19fec21eDedE9EdB91D1FbeC7C4095C5Ac1FC10c","name":"Polygon Gas (Compliant)","symbol":"cPOL","logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/polygon/info/logo.png","decimals":18,"tags":["defi","compliant","gasnative"],"extensions":{"assetClass":"gas_native","familyKey":"pol","mirroredSymbol":"cWPOL","backingMode":"hybrid_cap","redeemPolicy":"family_only","canonicalChainId":138,"wave":"wave1"}},{"chainId":138,"address":"0x9c8f6F4fe1e535e6F85a78Ee95249deD5540A2D0","name":"Avalanche Gas (Compliant)","symbol":"cAVAX","logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/avalanchec/info/logo.png","decimals":18,"tags":["defi","compliant","gasnative"],"extensions":{"assetClass":"gas_native","familyKey":"avax","mirroredSymbol":"cWAVAX","backingMode":"hybrid_cap","redeemPolicy":"family_only","canonicalChainId":138,"wave":"wave1"}},{"chainId":138,"address":"0xFb48bb6c623571F9795B535B73f0D660E8643fd4","name":"Cronos Gas (Compliant)","symbol":"cCRO","logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cronos/info/logo.png","decimals":18,"tags":["defi","compliant","gasnative"],"extensions":{"assetClass":"gas_native","familyKey":"cro","mirroredSymbol":"cWCRO","backingMode":"hybrid_cap","redeemPolicy":"family_only","canonicalChainId":138,"wave":"wave1"}},{"chainId":138,"address":"0xA39A59138F8a45b4a31455875b8A29FF31E76Ec8","name":"Gnosis Gas (Compliant)","symbol":"cXDAI","logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/xdai/info/logo.png","decimals":18,"tags":["defi","compliant","gasnative"],"extensions":{"assetClass":"gas_native","familyKey":"xdai","mirroredSymbol":"cWXDAI","backingMode":"hybrid_cap","redeemPolicy":"family_only","canonicalChainId":138,"wave":"wave1"}},{"chainId":138,"address":"0x1814661DAE0933Bf397b1274f5a62411B94195C7","name":"Celo Gas (Compliant)","symbol":"cCELO","logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/celo/info/logo.png","decimals":18,"tags":["defi","compliant","gasnative"],"extensions":{"assetClass":"gas_native","familyKey":"celo","mirroredSymbol":"cWCELO","backingMode":"hybrid_cap","redeemPolicy":"family_only","canonicalChainId":138,"wave":"wave1"}},{"chainId":138,"address":"0x4D82206BeC5B4Dfa17759FFEDE07E35f4f63a050","name":"Wemix Gas (Compliant)","symbol":"cWEMIX","logoURI":"https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/wemix/info/logo.png","decimals":18,"tags":["defi","compliant","gasnative"],"extensions":{"assetClass":"gas_native","familyKey":"wemix","mirroredSymbol":"cWWEMIX","backingMode":"hybrid_cap","redeemPolicy":"family_only","canonicalChainId":138,"wave":"wave1"}}],"tags":{"defi":{"name":"DeFi","description":"Decentralized Finance tokens"},"wrapped":{"name":"Wrapped","description":"Wrapped tokens representing native assets"},"oracle":{"name":"Oracle","description":"Oracle price feed tokens"},"pricefeed":{"name":"Price Feed","description":"Price feed oracle contracts"},"stablecoin":{"name":"Stablecoin","description":"Stable value tokens pegged to fiat currencies"},"compliant":{"name":"Compliant","description":"Regulatory compliant tokens with compliance features"},"ccip":{"name":"CCIP","description":"Cross Chain Interoperability Protocol tokens"},"v2":{"name":"Version 2","description":"Next generation GRU token contracts"},"x402":{"name":"x402 Ready","description":"Permit or authorization capable payment tokens"},"staged":{"name":"Staged","description":"Deployed and discoverable, not yet canonical"},"fwdcanon":{"name":"Forward canonical","description":"GRU v2 forward canonical token variant"},"gasnative":{"name":"Gas native","description":"Gas native compliant families and wrapped gas mirrors"}}} \ No newline at end of file diff --git a/provider/index.js b/provider/index.js index 10937b7..3ef4edc 100644 --- a/provider/index.js +++ b/provider/index.js @@ -22,7 +22,9 @@ export { ORACLES_CHAIN_138, ORACLES_MAINNET, ORACLE_ABI, + CHAIN138_STABLE_USD_1, getEthUsdPrice, + getAssetUsdPrice, getOracleConfig, } from './oracles.js' diff --git a/provider/oracles.js b/provider/oracles.js index cfd5bf2..84b4004 100644 --- a/provider/oracles.js +++ b/provider/oracles.js @@ -1,17 +1,48 @@ /** * Oracle addresses and helpers for Chain 138 and Ethereum Mainnet. - * Use these to read price feeds so MetaMask and dApps can display USD values. + * Use these to read price feeds so dApps (and optional wallet overlays) can show USD values. + * + * Chain 138: MetaMask’s **native** token/fiat column uses a **central price service**, not + * your RPC or on-chain feeds — custom chains often stay unmapped until third-party listings exist. + * Use `getEthUsdPrice` / `getAssetUsdPrice` in **your dApp UI**, explorer Snap flows, or + * token-aggregation APIs for multi-asset USD. */ -/** Chain 138: ETH/USD proxy and aggregator */ +/** Chain 138: ETH/USD reads (prefer keeper-synced mock; legacy proxy often returns zero) */ export const ORACLES_CHAIN_138 = { chainId: 138, + /** Legacy proxy — do not rely on for live reads */ ethUsdProxy: '0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6', - aggregator: '0x99b3511a2d315a497c8112c1fdd8d508d4b1e506', + /** Keeper-synced MockPriceFeed (8 decimals); same as `CHAIN138_WETH_MOCK_PRICE_FEED` */ + ethUsdAggregator: '0x3e8725b8De386feF3eFE5678c92eA6aDB41992B2', + /** Managed aggregator slot (Chainlink-style staleness rules; can lag on Besu) */ + legacyEthUsdAggregator: '0x99b3511a2d315a497c8112c1fdd8d508d4b1e506', decimals: 8, rpcUrl: 'https://rpc-http-pub.d-bis.org', } +/** + * Chain 138 tokens we treat as ~$1 USD for dApp / Snap UX hints (not MetaMask’s built-in column). + * Includes compliant **cUSDT/cUSDC**, **V2** mints, and official-mirror **USDT/USDC** used in D3 routing. + */ +export const CHAIN138_STABLE_USD_1 = new Set( + [ + '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22', // cUSDT + '0xf22258f57794CC8E06237084b353Ab30fFfa640b', // cUSDC + '0x9FBfab33882Efe0038DAa608185718b772EE5660', // cUSDT V2 + '0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d', // cUSDC V2 + '0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1', // USDT (official mirror, D3) + '0x71D6687F38b93CCad569Fa6352c876eea967201b', // USDC (official mirror, D3) + ].map((a) => a.toLowerCase()), +) + +const WETH_VARIANTS = new Set( + [ + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH9 + '0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f', // WETH10 + ].map((a) => a.toLowerCase()), +) + /** Ethereum Mainnet: Chainlink ETH/USD */ export const ORACLES_MAINNET = { chainId: 1, @@ -27,31 +58,80 @@ export const ORACLE_ABI = [ ] /** - * Get ETH/USD price from the appropriate oracle for the given chain. + * Read ETH/USD from a Chainlink-compatible feed contract. + * @param {import('ethers').Provider} provider + * @param {string} feedAddress + */ +async function readEthUsdFromFeed(provider, feedAddress) { + const { ethers } = await import('ethers') + const contract = new ethers.Contract(feedAddress, ORACLE_ABI, provider) + const [roundId, answer, , updatedAt] = await contract.latestRoundData() + const decimals = Number(await contract.decimals()) + const price = Number(answer) / 10 ** decimals + return { + price, + updatedAt: new Date(Number(updatedAt) * 1000), + decimals, + roundId: Number(roundId), + feedAddress, + } +} + +/** + * Get ETH/USD price for the given chain (138 uses keeper-synced mock first). * @param {import('ethers').Provider} provider - ethers v6 JsonRpcProvider or BrowserProvider * @param {number} chainId - 138 or 1 - * @returns {Promise<{ price: number, updatedAt: Date, decimals: number } | null>} + * @returns {Promise<{ price: number, updatedAt: Date, decimals: number, feedAddress?: string } | null>} */ export async function getEthUsdPrice(provider, chainId) { - const oracleConfig = chainId === 138 ? ORACLES_CHAIN_138 : chainId === 1 ? ORACLES_MAINNET : null - if (!oracleConfig) return null - - try { - const { ethers } = await import('ethers') - const contract = new ethers.Contract(oracleConfig.ethUsdProxy, ORACLE_ABI, provider) - const [roundId, answer, startedAt, updatedAt] = await contract.latestRoundData() - const decimals = Number(await contract.decimals()) - const price = Number(answer) / Math.pow(10, decimals) - return { - price, - updatedAt: new Date(Number(updatedAt) * 1000), - decimals, - roundId: Number(roundId), + if (chainId === 1) { + try { + return await readEthUsdFromFeed(provider, ORACLES_MAINNET.ethUsdProxy) + } catch (err) { + console.error('getEthUsdPrice mainnet error:', err) + return null } - } catch (err) { - console.error('getEthUsdPrice error:', err) - return null } + + if (chainId !== 138) return null + + const cfg = ORACLES_CHAIN_138 + const tryFeeds = [cfg.ethUsdAggregator, cfg.legacyEthUsdAggregator, cfg.ethUsdProxy] + + for (const addr of tryFeeds) { + try { + const out = await readEthUsdFromFeed(provider, addr) + if (out.price > 0 && !Number.isNaN(out.price)) { + return out + } + } catch { + // try next + } + } + return null +} + +/** + * USD hint for a token on Chain 138 (dApp use). Returns null if unknown. + * Stablecoins (~$1): cUSDT, cUSDC, their V2 mints, and mirror USDT/USDC (D3 routing addresses). + * WETH9/WETH10: ETH/USD from on-chain feeds. + * @param {import('ethers').Provider} provider + * @param {number} chainId + * @param {string} tokenAddress - ERC-20 (checksummed or not) + * @returns {Promise<{ usd: number, source: string } | null>} + */ +export async function getAssetUsdPrice(provider, chainId, tokenAddress) { + if (!tokenAddress || chainId !== 138) return null + const a = tokenAddress.toLowerCase() + if (CHAIN138_STABLE_USD_1.has(a)) { + return { usd: 1, source: 'policy:GRU_USD_stable_1' } + } + if (WETH_VARIANTS.has(a)) { + const eth = await getEthUsdPrice(provider, 138) + if (!eth) return null + return { usd: eth.price, source: `eth_usd:${eth.feedAddress ?? 'feed'}` } + } + return null } /** diff --git a/provider/types.d.ts b/provider/types.d.ts index 931214a..cb34573 100644 --- a/provider/types.d.ts +++ b/provider/types.d.ts @@ -27,4 +27,11 @@ export interface OraclePriceResult { updatedAt: Date decimals: number roundId?: number + /** Chain 138: which feed answered (mock, legacy aggregator, or proxy) */ + feedAddress?: string +} + +export interface AssetUsdHint { + usd: number + source: string }