Skip to content

Commit ebb7b8a

Browse files
feat(statics): add zama support
TICKET: CHALO-402
1 parent 2392d91 commit ebb7b8a

7 files changed

Lines changed: 228 additions & 0 deletions

File tree

modules/statics/src/account.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
CANTON_TOKEN_FEATURES,
99
CELO_TOKEN_FEATURES,
1010
COSMOS_SIDECHAIN_FEATURES,
11+
ERC7984_TOKEN_FEATURES,
1112
TEMPO_FEATURES,
1213
} from './coinFeatures';
1314

@@ -294,6 +295,15 @@ export class Erc721Coin extends ContractAddressDefinedToken {}
294295
*/
295296
export class Erc1155Coin extends ContractAddressDefinedToken {}
296297

298+
/**
299+
* ERC-7984 is the confidential token standard for fhEVM-enabled blockchains (Zama).
300+
* Token balances are stored as FHE-encrypted ciphertexts; transfers use confidentialTransfer()
301+
* instead of the standard ERC-20 transfer(). Balance reads require delegated decryption via ACL.
302+
*
303+
* {@link https://eips.ethereum.org/EIPS/eip-7984 EIP-7984}
304+
*/
305+
export class Erc7984Coin extends ContractAddressDefinedToken {}
306+
297307
/**
298308
* The TRON blockchain supports tokens of the ERC20 standard similar to ETH ERC20 tokens.
299309
*/
@@ -1087,6 +1097,99 @@ export function terc20(
10871097
return erc20(id, name, fullName, decimalPlaces, contractAddress, asset, features, prefix, suffix, network);
10881098
}
10891099

1100+
/**
1101+
* Factory function for ERC-7984 confidential token instances (Zama fhEVM).
1102+
*
1103+
* ERC-7984 tokens store balances as FHE-encrypted ciphertexts. Transfers use
1104+
* confidentialTransfer() and balance reads require ACL delegation to BitGo.
1105+
*
1106+
* @param id uuid v4
1107+
* @param name unique identifier of the token (e.g. 'eth:ctkn')
1108+
* @param fullName Complete human-readable name of the token
1109+
* @param decimalPlaces Number of decimal places this token supports (divisibility exponent)
1110+
* @param contractAddress Contract address of this token
1111+
* @param asset Asset which this coin represents. This is the same for both mainnet and testnet variants of a coin.
1112+
* @param features? Features of this coin. Defaults to ERC7984_TOKEN_FEATURES
1113+
* @param prefix? Optional token prefix. Defaults to empty string
1114+
* @param suffix? Optional token suffix. Defaults to token name.
1115+
* @param network? Optional token network. Defaults to Ethereum main network.
1116+
* @param primaryKeyCurve The elliptic curve for this chain/token
1117+
*/
1118+
export function erc7984(
1119+
id: string,
1120+
name: string,
1121+
fullName: string,
1122+
decimalPlaces: number,
1123+
contractAddress: string,
1124+
asset: UnderlyingAsset,
1125+
features: CoinFeature[] = ERC7984_TOKEN_FEATURES,
1126+
prefix = '',
1127+
suffix: string = name.toUpperCase(),
1128+
network: EthereumNetwork = Networks.main.ethereum,
1129+
primaryKeyCurve: KeyCurve = KeyCurve.Secp256k1
1130+
) {
1131+
return Object.freeze(
1132+
new Erc7984Coin({
1133+
id,
1134+
name,
1135+
fullName,
1136+
network,
1137+
contractAddress,
1138+
prefix,
1139+
suffix,
1140+
features,
1141+
decimalPlaces,
1142+
asset,
1143+
isToken: true,
1144+
primaryKeyCurve,
1145+
baseUnit: BaseUnit.ETH,
1146+
})
1147+
);
1148+
}
1149+
1150+
/**
1151+
* Factory function for testnet ERC-7984 confidential token instances (Zama fhEVM).
1152+
*
1153+
* @param id uuid v4
1154+
* @param name unique identifier of the token (e.g. 'hteth:ctkn')
1155+
* @param fullName Complete human-readable name of the token
1156+
* @param decimalPlaces Number of decimal places this token supports (divisibility exponent)
1157+
* @param contractAddress Contract address of this token
1158+
* @param asset Asset which this coin represents. This is the same for both mainnet and testnet variants of a coin.
1159+
* @param features? Features of this coin. Defaults to ERC7984_TOKEN_FEATURES
1160+
* @param prefix? Optional token prefix. Defaults to empty string
1161+
* @param suffix? Optional token suffix. Defaults to token name.
1162+
* @param network? Optional token network. Defaults to Hoodi test network.
1163+
* @param primaryKeyCurve The elliptic curve for this chain/token
1164+
*/
1165+
export function terc7984(
1166+
id: string,
1167+
name: string,
1168+
fullName: string,
1169+
decimalPlaces: number,
1170+
contractAddress: string,
1171+
asset: UnderlyingAsset,
1172+
features: CoinFeature[] = ERC7984_TOKEN_FEATURES,
1173+
prefix = '',
1174+
suffix: string = name.toUpperCase(),
1175+
network: EthereumNetwork = Networks.test.hoodi,
1176+
primaryKeyCurve: KeyCurve = KeyCurve.Secp256k1
1177+
) {
1178+
return erc7984(
1179+
id,
1180+
name,
1181+
fullName,
1182+
decimalPlaces,
1183+
contractAddress,
1184+
asset,
1185+
features,
1186+
prefix,
1187+
suffix,
1188+
network,
1189+
primaryKeyCurve
1190+
);
1191+
}
1192+
10901193
/**
10911194
* Factory function for erc721 token instances.
10921195
*

modules/statics/src/allCoinsAndTokens.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import { nep141Tokens } from './coins/nep141Tokens';
7272
import { vetTokens } from './coins/vetTokens';
7373
import { cosmosTokens } from './coins/cosmosTokens';
7474
import { jettonTokens } from './coins/jettonTokens';
75+
import { erc7984Tokens } from './coins/erc7984Tokens';
7576
import { polyxTokens } from './coins/polyxTokens';
7677
import { cantonTokens } from './coins/cantonTokens';
7778
import { flrp } from './flrp';
@@ -164,6 +165,7 @@ export const allCoinsAndTokens = [
164165
...botTokens,
165166
...adaTokens,
166167
...jettonTokens,
168+
...erc7984Tokens,
167169
...polyxTokens,
168170
...cantonTokens,
169171
avaxp(

modules/statics/src/base.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,18 @@ export enum CoinFeature {
559559
* This coin allows negative fees in transactions
560560
*/
561561
ALLOWS_NEGATIVE_FEE = 'allows-negative-fee',
562+
563+
/**
564+
* This token uses fully homomorphic encryption (FHE) for confidential transfers (ERC-7984).
565+
* Balances are stored as encrypted ciphertexts; transfers use confidentialTransfer() instead of transfer().
566+
*/
567+
CONFIDENTIAL_TRANSFER = 'confidential-transfer',
568+
569+
/**
570+
* Reading the balance of this token requires the wallet owner to delegate decryption access
571+
* to BitGo via ACL.delegateForUserDecryption() before balances can be displayed.
572+
*/
573+
REQUIRES_DECRYPTION_DELEGATION = 'requires-decryption-delegation',
562574
}
563575

564576
/**
@@ -3794,6 +3806,12 @@ export enum UnderlyingAsset {
37943806
'eth:drv' = 'eth:drv',
37953807
'eth:prn' = 'eth:prn',
37963808
'eth:zama' = 'eth:zama',
3809+
// ERC-7984 confidential tokens (Zama fhEVM - mainnet, contract addresses TBD pending Zama mainnet launch)
3810+
'eth:ctkn' = 'eth:ctkn',
3811+
'eth:cusdt' = 'eth:cusdt',
3812+
// ERC-7984 confidential tokens (Zama fhEVM - testnet / hteth)
3813+
'hteth:ctkn' = 'hteth:ctkn',
3814+
'hteth:cusdt' = 'hteth:cusdt',
37973815
'eth:mony' = 'eth:mony',
37983816
'eth:architectgvi' = 'eth:architectgvi',
37993817
'eth:zk' = 'eth:zk',

modules/statics/src/coinFeatures.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,3 +789,12 @@ export const CANTON_TOKEN_FEATURES = [
789789
CoinFeature.REQUIRES_DEPOSIT_ACCEPTANCE_TRANSACTION,
790790
CoinFeature.ALPHANUMERIC_MEMO_ID,
791791
];
792+
793+
export const ERC7984_TOKEN_FEATURES = [
794+
...ACCOUNT_COIN_DEFAULT_FEATURES,
795+
CoinFeature.BULK_TRANSACTION,
796+
CoinFeature.TSS,
797+
CoinFeature.TSS_COLD,
798+
CoinFeature.CONFIDENTIAL_TRANSFER,
799+
CoinFeature.REQUIRES_DECRYPTION_DELEGATION,
800+
];
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { erc7984, terc7984 } from '../account';
2+
import { UnderlyingAsset } from '../base';
3+
4+
/**
5+
* ERC-7984 confidential tokens (Zama fhEVM).
6+
*
7+
* These tokens use fully homomorphic encryption (FHE) for on-chain confidential transfers.
8+
* Balances are stored as encrypted ciphertexts; plaintext amounts require ACL-delegated
9+
* decryption via the Zama Gateway before they can be displayed.
10+
*
11+
* Mainnet contract addresses are TBD pending Zama fhEVM mainnet launch.
12+
* Testnet tokens (hteth:*) are deployed on the BitGo-supported ETH testnet (Hoodi).
13+
*
14+
* Sandbox development contracts (Sepolia):
15+
* CTKN: 0x94167129172A35ab093B44b8b96213DDbc3cD387
16+
* cUSDT: 0x4E7B06D78965594eB5EF5414c357ca21E1554491
17+
*/
18+
export const erc7984Tokens = [
19+
// Mainnet tokens (contract addresses TBD pending Zama fhEVM mainnet launch)
20+
erc7984(
21+
'f47ac10b-58cc-4372-a567-0e02b2c3d479',
22+
'eth:ctkn',
23+
'Confidential Test Token',
24+
6,
25+
'0x0000000000000000000000000000000000000000', // TODO: update with mainnet contract address
26+
UnderlyingAsset['eth:ctkn']
27+
),
28+
erc7984(
29+
'f47ac10b-58cc-4372-a567-0e02b2c3d480',
30+
'eth:cusdt',
31+
'Confidential USDT',
32+
6,
33+
'0x0000000000000000000000000000000000000000', // TODO: update with mainnet contract address
34+
UnderlyingAsset['eth:cusdt']
35+
),
36+
37+
// Testnet tokens (hteth / Hoodi)
38+
// Note: sandbox development contracts are on Ethereum Sepolia; deploy to Hoodi for BitGo testnet support
39+
terc7984(
40+
'f47ac10b-58cc-4372-a567-0e02b2c3d481',
41+
'hteth:ctkn',
42+
'Confidential Test Token',
43+
6,
44+
'0x0000000000000000000000000000000000000000', // TODO: deploy to Hoodi and update address (Sepolia dev: 0x94167129172A35ab093B44b8b96213DDbc3cD387)
45+
UnderlyingAsset['hteth:ctkn']
46+
),
47+
terc7984(
48+
'f47ac10b-58cc-4372-a567-0e02b2c3d482',
49+
'hteth:cusdt',
50+
'Confidential USDT',
51+
6,
52+
'0x0000000000000000000000000000000000000000', // TODO: deploy to Hoodi and update address (Sepolia dev: 0x4E7B06D78965594eB5EF5414c357ca21E1554491)
53+
UnderlyingAsset['hteth:cusdt']
54+
),
55+
];

modules/statics/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export {
3535
AdaToken,
3636
JettonToken,
3737
CantonToken,
38+
Erc7984Coin,
3839
} from './account';
3940
export { CoinMap } from './map';
4041
export { networkFeatureMapForTokens, registerNetworkFeatures, getNetworkFeatures } from './networkFeatureMapForTokens';

modules/statics/src/tokenConfig.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Erc1155Coin,
1414
Erc20Coin,
1515
Erc721Coin,
16+
Erc7984Coin,
1617
EthLikeERC20Token,
1718
EthLikeERC721Token,
1819
FlrERC20Token,
@@ -68,6 +69,7 @@ export type EosTokenConfig = BaseContractAddressConfig & {
6869
contractAddress: string;
6970
};
7071
export type Erc20TokenConfig = BaseContractAddressConfig;
72+
export type Erc7984TokenConfig = BaseContractAddressConfig;
7173
export type TrxTokenConfig = BaseContractAddressConfig;
7274
export type StellarTokenConfig = BaseNetworkConfig;
7375

@@ -342,6 +344,44 @@ export const getFormattedErc20Tokens = (customCoinMap = coins) =>
342344
return acc;
343345
}, []);
344346

347+
function getErc7984TokenConfig(coin: Erc7984Coin): Erc7984TokenConfig {
348+
let baseCoin: string;
349+
switch (coin.network.name) {
350+
case Networks.main.ethereum.name:
351+
baseCoin = 'eth';
352+
break;
353+
case Networks.test.kovan.name:
354+
baseCoin = 'teth';
355+
break;
356+
case Networks.test.goerli.name:
357+
baseCoin = 'gteth';
358+
break;
359+
case Networks.test.holesky.name:
360+
case Networks.test.hoodi.name:
361+
baseCoin = 'hteth';
362+
break;
363+
default:
364+
throw new Error(`ERC-7984 token ${coin.name} has an unsupported network`);
365+
}
366+
return {
367+
type: coin.name,
368+
coin: baseCoin,
369+
network: coin.network.type === NetworkType.MAINNET ? 'Mainnet' : 'Testnet',
370+
name: coin.fullName,
371+
tokenContractAddress: coin.contractAddress.toString().toLowerCase(),
372+
decimalPlaces: coin.decimalPlaces,
373+
};
374+
}
375+
376+
// Get the list of ERC-7984 confidential tokens from statics and format it properly
377+
export const getFormattedErc7984Tokens = (customCoinMap = coins) =>
378+
customCoinMap.reduce((acc: Erc7984TokenConfig[], coin) => {
379+
if (coin instanceof Erc7984Coin) {
380+
acc.push(getErc7984TokenConfig(coin));
381+
}
382+
return acc;
383+
}, []);
384+
345385
export const ethGasConfigs = {
346386
minimumGasPrice: 1000000000, // minimum gas price a user can provide (1 Gwei)
347387
defaultGasPrice: 20000000000, // default gas price if estimation fails (20 Gwei)

0 commit comments

Comments
 (0)