From 61e38156355f94d1fc08afa50afee98a873a3770 Mon Sep 17 00:00:00 2001 From: Prabhsharan Singh Date: Thu, 29 Oct 2026 12:22:04 +0530 Subject: [PATCH] feat(statics): wire mainnet ERC-7984 wrapper-underlying metadata for Zama tokens (CHALO-2007) Register underlyingErc20Address, rate, and requiresApprovalReset for all six mainnet Zama confidential pairs (eth:czama, eth:cxaut, eth:ctgbp, eth:cweth, eth:cusdt, eth:cusdc). Values verified on-chain via underlying()/rate(). abstract-eth registers an ERC-7984 shield pair only when underlyingErc20Address is set, so this enables the shield/unshield (wrap/wrapApprove/unwrap/ finalizeUnwrap) journey for mainnet wallets. eth:cusdt sets requiresApprovalReset=true (real USDT requires approve(0) before non-zero approve); all other underlyings are standard ERC-20. Also updates the sdk-coin-eth wrapper-registry scoping test, which asserted the old no-metadata state (eth:cusdt underlyingErc20Address === undefined) and now asserts the wired on-chain value - the three intent verifications it runs resolve wrappers by network scope and are unchanged. statics unit tests: 41522 passing. AMS allowlisting/vetting (CHALO-1145) remains the separate gate. --- modules/sdk-coin-eth/test/unit/eth.ts | 6 +- modules/statics/src/coins/erc7984Tokens.ts | 64 +++++++++++++++++++--- modules/statics/src/tokenConfig.ts | 2 +- modules/statics/test/unit/erc7984Tokens.ts | 51 +++++++++++++++-- 4 files changed, 107 insertions(+), 16 deletions(-) diff --git a/modules/sdk-coin-eth/test/unit/eth.ts b/modules/sdk-coin-eth/test/unit/eth.ts index 3bae6ed1cb0..6a821017680 100644 --- a/modules/sdk-coin-eth/test/unit/eth.ts +++ b/modules/sdk-coin-eth/test/unit/eth.ts @@ -1556,8 +1556,10 @@ describe('ETH:', function () { ]); const wrapCalldata = intentCalldata('wrap(address,uint256)', [baseAddress, amount]); - it('should verify unwrap, finalizeUnwrap and wrap against a mainnet pair without underlyingErc20Address', async function () { - (mainnetPair.underlyingErc20Address === undefined).should.equal(true); + it('should verify unwrap, finalizeUnwrap and wrap against a registered mainnet pair', async function () { + // CHALO-2007 wired wrapper↔underlying metadata for every mainnet pair; eth:cusdt's + // underlying is real mainnet USDT. + mainnetPair.underlyingErc20Address!.should.equal('0xdac17f958d2ee523a2206206994597c13d831ec7'); ( await verifyIntent('unwrap', unwrapCalldata, { coinName: 'eth', diff --git a/modules/statics/src/coins/erc7984Tokens.ts b/modules/statics/src/coins/erc7984Tokens.ts index 9b393ad0177..372316f5c11 100644 --- a/modules/statics/src/coins/erc7984Tokens.ts +++ b/modules/statics/src/coins/erc7984Tokens.ts @@ -9,8 +9,8 @@ import { UnderlyingAsset } from '../base'; * decryption via the Zama Gateway before they can be displayed. * * Wrapper↔underlying metadata (`underlyingErc20Address`, `rate`, `requiresApprovalReset`) - * is wired on Hoodi test pairs only for now so mainnet served configs stay unchanged. - * Allowlisting is owned by AMS. + * is wired for every registered shield pair (Hoodi test pairs and all mainnet pairs; + * mainnet values verified on-chain, CHALO-2007). Allowlisting is owned by AMS. * * Testnet tokens (hteth:*) are deployed on Hoodi using Zama's cleartext FHE stack. * Hoodi ACL: 0x6D3FAf6f86e1fF9F3B0831Dda920AbA1cBd5bd68 (Networks.test.hoodi.zamaAclContractAddress) @@ -24,7 +24,15 @@ export const erc7984Tokens = [ 'Confidential Zama', 6, '0x80cb147fd86dc6dee3eee7e4cee33d1397d98071', // https://etherscan.io/token/0x80CB147Fd86dC6dEe3Eee7e4Cee33d1397d98071 - UnderlyingAsset['eth:czama'] + UnderlyingAsset['eth:czama'], + undefined, // features: default ERC7984_TOKEN_FEATURES + undefined, // prefix + undefined, // suffix + undefined, // network: Ethereum mainnet + undefined, // primaryKeyCurve: secp256k1 + '0xa12cc123ba206d4031d1c7f6223d1c2ec249f4f3', // underlying()=ZAMA 18dp + '1000000000000', // rate() on-chain: 18dp → 6dp + false // standard ERC-20 approve ), erc7984( 'c9d5d51b-15b7-4d93-b079-9af313160e66', @@ -32,7 +40,15 @@ export const erc7984Tokens = [ 'Zama Confidential XAUT', 6, '0x73cc9af9d6befdb3c3faf8a5e8c05cb95fdaeef1', // https://etherscan.io/token/0x73cc9aF9d6BEFdb3c3fAf8a5E8c05Cb95FdaEEf1 - UnderlyingAsset['eth:cxaut'] + UnderlyingAsset['eth:cxaut'], + undefined, // features: default ERC7984_TOKEN_FEATURES + undefined, // prefix + undefined, // suffix + undefined, // network: Ethereum mainnet + undefined, // primaryKeyCurve: secp256k1 + '0x68749665ff8d2d112fa859aa293f07a622782f38', // underlying()=XAUt (Tether Gold) 6dp + '1', // rate() on-chain + false // standard ERC-20 approve ), erc7984( '0d1b01c8-ee4a-4ca4-a1af-2ab3132d91ee', @@ -40,7 +56,15 @@ export const erc7984Tokens = [ 'Zama Confidential TGBP', 6, '0xa873750ccbafd5ec7dd13bfd5237d7129832edd9', // https://etherscan.io/token/0xa873750ccBafD5ec7Dd13bfD5237d7129832eDD9 - UnderlyingAsset['eth:ctgbp'] + UnderlyingAsset['eth:ctgbp'], + undefined, // features: default ERC7984_TOKEN_FEATURES + undefined, // prefix + undefined, // suffix + undefined, // network: Ethereum mainnet + undefined, // primaryKeyCurve: secp256k1 + '0x27f6c8289550fce67f6b50bed1f519966afe5287', // underlying()=tGBP 18dp + '1000000000000', // rate() on-chain: 18dp → 6dp + false // standard ERC-20 approve ), erc7984( '2fbf960e-9747-4d38-b93b-28029e78b5d4', @@ -48,7 +72,15 @@ export const erc7984Tokens = [ 'Zama Confidential WETH', 6, '0xda9396b82634ea99243ce51258b6a5ae512d4893', // https://etherscan.io/token/0xda9396b82634Ea99243cE51258B6A5Ae512D4893 - UnderlyingAsset['eth:cweth'] + UnderlyingAsset['eth:cweth'], + undefined, // features: default ERC7984_TOKEN_FEATURES + undefined, // prefix + undefined, // suffix + undefined, // network: Ethereum mainnet + undefined, // primaryKeyCurve: secp256k1 + '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // underlying()=WETH 18dp + '1000000000000', // rate() on-chain: 18dp → 6dp + false // standard ERC-20 approve ), erc7984( 'f47ac10b-58cc-4372-a567-0e02b2c3d480', @@ -56,7 +88,15 @@ export const erc7984Tokens = [ 'Zama USDT', 6, '0xae0207c757aa2b4019ad96edd0092ddc63ef0c50', // https://etherscan.io/token/0xAe0207C757Aa2B4019Ad96edD0092ddc63EF0c50 - UnderlyingAsset['eth:cusdt'] + UnderlyingAsset['eth:cusdt'], + undefined, // features: default ERC7984_TOKEN_FEATURES + undefined, // prefix + undefined, // suffix + undefined, // network: Ethereum mainnet + undefined, // primaryKeyCurve: secp256k1 + '0xdac17f958d2ee523a2206206994597c13d831ec7', // underlying()=USDT 6dp + '1', // rate() on-chain + true // USDT-style approve(0) reset required ), erc7984( 'fb41ba70-858c-48e6-a513-9da1ea030853', @@ -64,7 +104,15 @@ export const erc7984Tokens = [ 'Zama USDC', 6, '0xe978f22157048e5db8e5d07971376e86671672b2', // https://etherscan.io/token/0xe978f22157048e5db8e5d07971376e86671672b2 - UnderlyingAsset['eth:cusdc'] + UnderlyingAsset['eth:cusdc'], + undefined, // features: default ERC7984_TOKEN_FEATURES + undefined, // prefix + undefined, // suffix + undefined, // network: Ethereum mainnet + undefined, // primaryKeyCurve: secp256k1 + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // underlying()=USDC 6dp + '1', // rate() on-chain + false // standard ERC-20 approve ), // Testnet tokens (hteth / Hoodi) — Zama cleartext FHE stack (chain ID 560048) diff --git a/modules/statics/src/tokenConfig.ts b/modules/statics/src/tokenConfig.ts index 6c980633a3f..1c750a9fe1e 100644 --- a/modules/statics/src/tokenConfig.ts +++ b/modules/statics/src/tokenConfig.ts @@ -71,7 +71,7 @@ export type EosTokenConfig = BaseContractAddressConfig & { }; export type Erc20TokenConfig = BaseContractAddressConfig; export type Erc7984TokenConfig = BaseContractAddressConfig & { - /** Present for Hoodi test pairs; omitted on mainnet until shield/unshield ships there. */ + /** Wrapper↔underlying shield metadata; set for every registered shield pair (mainnet and Hoodi). */ underlyingErc20Address?: string; rate?: string; requiresApprovalReset?: boolean; diff --git a/modules/statics/test/unit/erc7984Tokens.ts b/modules/statics/test/unit/erc7984Tokens.ts index 5b9ba773d09..5eb4b2bc062 100644 --- a/modules/statics/test/unit/erc7984Tokens.ts +++ b/modules/statics/test/unit/erc7984Tokens.ts @@ -29,11 +29,52 @@ describe('ERC-7984 wrapper metadata on Erc7984Coin', function () { coin.requiresApprovalReset.should.equal(false); }); - it('leaves mainnet wrapper metadata unset', function () { - const coin = getErc7984('eth:cusdt'); - should.equal(coin.underlyingErc20Address, undefined); - should.equal(coin.rate, undefined); - should.equal(coin.requiresApprovalReset, undefined); + it('stores on-chain wrapper metadata for every mainnet pair', function () { + const mainnet = { + 'eth:czama': { + contractAddress: '0x80cb147fd86dc6dee3eee7e4cee33d1397d98071', + underlyingErc20Address: '0xa12cc123ba206d4031d1c7f6223d1c2ec249f4f3', + rate: '1000000000000', + requiresApprovalReset: false, + }, + 'eth:cxaut': { + contractAddress: '0x73cc9af9d6befdb3c3faf8a5e8c05cb95fdaeef1', + underlyingErc20Address: '0x68749665ff8d2d112fa859aa293f07a622782f38', + rate: '1', + requiresApprovalReset: false, + }, + 'eth:ctgbp': { + contractAddress: '0xa873750ccbafd5ec7dd13bfd5237d7129832edd9', + underlyingErc20Address: '0x27f6c8289550fce67f6b50bed1f519966afe5287', + rate: '1000000000000', + requiresApprovalReset: false, + }, + 'eth:cweth': { + contractAddress: '0xda9396b82634ea99243ce51258b6a5ae512d4893', + underlyingErc20Address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + rate: '1000000000000', + requiresApprovalReset: false, + }, + 'eth:cusdt': { + contractAddress: '0xae0207c757aa2b4019ad96edd0092ddc63ef0c50', + underlyingErc20Address: '0xdac17f958d2ee523a2206206994597c13d831ec7', + rate: '1', + requiresApprovalReset: true, + }, + 'eth:cusdc': { + contractAddress: '0xe978f22157048e5db8e5d07971376e86671672b2', + underlyingErc20Address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + rate: '1', + requiresApprovalReset: false, + }, + }; + for (const [name, expected] of Object.entries(mainnet)) { + const coin = getErc7984(name); + coin.contractAddress.should.equal(expected.contractAddress); + coin.underlyingErc20Address!.should.equal(expected.underlyingErc20Address); + coin.rate!.should.equal(expected.rate); + coin.requiresApprovalReset!.should.equal(expected.requiresApprovalReset); + } }); it('lowercases addresses on construction for test pairs', function () {