Skip to content

Commit 6a89aef

Browse files
committed
refactor
1 parent 5032e19 commit 6a89aef

32 files changed

+259
-315
lines changed

ccip/cct/hardhat/README.md

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,22 @@ All tasks in this project use Hardhat's global options. The most important one i
2323

2424
The following networks are configured and available for use:
2525

26-
| Network Name | Description | Environment Variable |
27-
| ----------------- | ------------------------ | -------------------------- |
28-
| `avalancheFuji` | Avalanche Fuji Testnet | `AVALANCHE_FUJI_RPC_URL` |
29-
| `arbitrumSepolia` | Arbitrum Sepolia Testnet | `ARBITRUM_SEPOLIA_RPC_URL` |
30-
| `sepolia` | Ethereum Sepolia Testnet | `ETHEREUM_SEPOLIA_RPC_URL` |
31-
| `baseSepolia` | Base Sepolia Testnet | `BASE_SEPOLIA_RPC_URL` |
32-
| `polygonAmoy` | Polygon Amoy Testnet | `POLYGON_AMOY_RPC_URL` |
26+
| Network Name | Description | Environment Variable | Type |
27+
| ----------------- | ------------------------ | ---------------------------- | ------- |
28+
| `avalancheFuji` | Avalanche Fuji Testnet | `AVALANCHE_FUJI_RPC_URL` | EVM |
29+
| `arbitrumSepolia` | Arbitrum Sepolia Testnet | `ARBITRUM_SEPOLIA_RPC_URL` | EVM |
30+
| `ethereumSepolia` | Ethereum Sepolia Testnet | `ETHEREUM_SEPOLIA_RPC_URL` | EVM |
31+
| `baseSepolia` | Base Sepolia Testnet | `BASE_SEPOLIA_RPC_URL` | EVM |
32+
| `polygonAmoy` | Polygon Amoy Testnet | `POLYGON_AMOY_RPC_URL` | EVM |
33+
| `solanaDevnet` | Solana Devnet | N/A (destination only) | Non-EVM |
3334

3435
### Network Configuration
3536

36-
Network configurations are defined in:
37+
Network configurations use a **professional single source of truth architecture**:
3738

38-
- **Network settings**: `/config/networks.ts`
39-
- **Chain parameters**: `/config/config.json`
40-
- **Contract addresses**: Automatically loaded per network
39+
- **All network settings**: `/config/networks.ts` (consolidated configuration)
40+
- **Types auto-generated**: From the network configuration data
41+
- **Zero maintenance**: No manual enum synchronization needed
4142

4243
To use a network, ensure:
4344

@@ -1567,3 +1568,79 @@ npx hardhat applyChainUpdatesFromSafe \
15671568
- **Network Configuration**:
15681569
- Chain selectors and other network details are automatically fetched from the network configuration.
15691570
- The task validates all addresses and chain configurations before creating the Safe transaction.
1571+
1572+
## Adding New Networks
1573+
1574+
The network configuration system uses a single source of truth architecture that automatically generates TypeScript types and Hardhat network configurations from the network data.
1575+
1576+
### Adding a Network
1577+
1578+
To add a new CCIP-supported network, add the network configuration to the `configData` object in `config/networks.ts`:
1579+
1580+
```typescript
1581+
export const configData = {
1582+
// ... existing networks
1583+
newNetwork: {
1584+
chainFamily: "evm", // or "svm" for non-EVM chains
1585+
chainId: 12345,
1586+
chainSelector: "1234567890123456789",
1587+
router: "0xRouterAddress",
1588+
rmnProxy: "0xRMNProxyAddress",
1589+
tokenAdminRegistry: "0xTokenAdminRegistryAddress",
1590+
registryModuleOwnerCustom: "0xRegistryModuleOwnerAddress",
1591+
link: "0xLinkTokenAddress",
1592+
confirmations: 2,
1593+
nativeCurrencySymbol: "NEW",
1594+
chainType: "l1",
1595+
}
1596+
};
1597+
```
1598+
1599+
The network becomes available in:
1600+
- All task `--network` options
1601+
- TypeScript type checking (`Chains` and `EVMChains` types)
1602+
- Hardhat network configuration
1603+
- Cross-chain destination options
1604+
- Network validation throughout all tasks
1605+
1606+
### CCIP Configuration Sources
1607+
1608+
Obtain the required addresses and chain selectors from the official CCIP directories:
1609+
1610+
- **Mainnet Networks**: [https://docs.chain.link/ccip/directory/mainnet](https://docs.chain.link/ccip/directory/mainnet)
1611+
- **Testnet Networks**: [https://docs.chain.link/ccip/directory/testnet](https://docs.chain.link/ccip/directory/testnet)
1612+
1613+
Required information from these directories:
1614+
- Router contract addresses
1615+
- Chain selectors (unique CCIP identifiers)
1616+
- RMN Proxy addresses
1617+
- Token Admin Registry addresses
1618+
- LINK token addresses
1619+
1620+
### Environment Variable
1621+
1622+
Set the RPC URL environment variable:
1623+
1624+
```bash
1625+
npx env-enc set NEW_NETWORK_RPC_URL
1626+
```
1627+
1628+
### Example: Adding Optimism Sepolia
1629+
1630+
```typescript
1631+
optimismSepolia: {
1632+
chainFamily: "evm",
1633+
chainId: 11155420,
1634+
chainSelector: "5224473277236331295",
1635+
router: "0x114A20A10b43D4115e5aeef7345a1A71d2a60C57",
1636+
rmnProxy: "0x...",
1637+
tokenAdminRegistry: "0x...",
1638+
registryModuleOwnerCustom: "0x...",
1639+
link: "0x...",
1640+
confirmations: 2,
1641+
nativeCurrencySymbol: "ETH",
1642+
chainType: "op",
1643+
}
1644+
```
1645+
1646+
All tasks will support `--network optimismSepolia` after adding this configuration.

ccip/cct/hardhat/config/config.json

Lines changed: 0 additions & 73 deletions
This file was deleted.

ccip/cct/hardhat/config/index.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
1-
import { Chains, EVMChains } from "./types";
2-
import { networks } from "./networks";
3-
1+
import type { Chains, EVMChains } from "./types";
2+
import { configData, networks } from "./networks";
43
export {
5-
Chains,
6-
EVMChains,
74
PoolType,
85
TokenContractName,
96
TokenPoolContractName,
107
CCIPContractName,
118
} from "./types";
12-
13-
export type { Networks } from "./types";
14-
export { networks, configData } from "./networks";
9+
export type { Chains, EVMChains, Networks } from "./types";
10+
export { configData, networks } from "./networks";
1511
export { logger } from "./logger";
1612

13+
/**
14+
* Type guard to check if a string is a valid chain name
15+
*/
16+
export function isValidChain(chain: string): chain is Chains {
17+
return chain in configData;
18+
}
19+
1720
/**
1821
* Type guard to check if a chain is an EVM chain
1922
*/
20-
export function isEVMChain(chain: string): boolean {
21-
return Object.values(EVMChains).includes(chain as EVMChains);
23+
export function isEVMChain(chain: string): chain is EVMChains {
24+
if (!isValidChain(chain)) return false;
25+
return configData[chain].chainFamily === "evm";
26+
}
27+
28+
/**
29+
* Validates and returns a typed network name from Hardhat runtime environment
30+
*/
31+
export function validateNetworkName(networkName: string): Chains {
32+
if (!isValidChain(networkName)) {
33+
throw new Error(`Unsupported network: ${networkName}`);
34+
}
35+
return networkName;
2236
}
2337

2438
/**
Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { EVMChains, EtherscanConfig, Networks } from "./types";
2-
import configData from "./config.json";
31
import * as envEnc from "@chainlink/env-enc";
42
envEnc.config();
53

@@ -9,47 +7,96 @@ const accounts: string[] = [];
97
if (PRIVATE_KEY) accounts.push(PRIVATE_KEY);
108
if (PRIVATE_KEY_2) accounts.push(PRIVATE_KEY_2);
119

12-
const networks: Networks = {
13-
[EVMChains.avalancheFuji]: {
14-
type: "http",
15-
...configData.avalancheFuji,
16-
url: process.env.AVALANCHE_FUJI_RPC_URL || "https://UNSET-PLEASE-SET-AVALANCHE_FUJI_RPC_URL",
17-
gasPrice: undefined,
18-
nonce: undefined,
19-
accounts,
10+
export const configData = {
11+
avalancheFuji: {
12+
chainId: 43113,
13+
chainSelector: "14767482510784806043",
14+
router: "0xF694E193200268f9a4868e4Aa017A0118C9a8177",
15+
rmnProxy: "0xAc8CFc3762a979628334a0E4C1026244498E821b",
16+
tokenAdminRegistry: "0xA92053a4a3922084d992fD2835bdBa4caC6877e6",
17+
registryModuleOwnerCustom: "0x97300785aF1edE1343DB6d90706A35CF14aA3d81",
18+
link: "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846",
19+
confirmations: 2,
20+
nativeCurrencySymbol: "AVAX",
21+
chainType: "l1",
22+
chainFamily: "evm"
2023
},
21-
[EVMChains.arbitrumSepolia]: {
22-
type: "http",
23-
...configData.arbitrumSepolia,
24-
url: process.env.ARBITRUM_SEPOLIA_RPC_URL || "https://UNSET-PLEASE-SET-ARBITRUM_SEPOLIA_RPC_URL",
25-
gasPrice: undefined,
26-
nonce: undefined,
27-
accounts,
24+
arbitrumSepolia: {
25+
chainId: 421614,
26+
chainSelector: "3478487238524512106",
27+
router: "0x2a9C5afB0d0e4BAb2BCdaE109EC4b0c4Be15a165",
28+
rmnProxy: "0x9527E2d01A3064ef6b50c1Da1C0cC523803BCFF2",
29+
tokenAdminRegistry: "0x8126bE56454B628a88C17849B9ED99dd5a11Bd2f",
30+
registryModuleOwnerCustom: "0xE625f0b8b0Ac86946035a7729Aba124c8A64cf69",
31+
link: "0xb1D4538B4571d411F07960EF2838Ce337FE1E80E",
32+
confirmations: 2,
33+
nativeCurrencySymbol: "ETH",
34+
chainType: "l1",
35+
chainFamily: "evm"
2836
},
29-
[EVMChains.ethereumSepolia]: {
30-
type: "http",
31-
...configData.ethereumSepolia,
32-
url: process.env.ETHEREUM_SEPOLIA_RPC_URL || "https://UNSET-PLEASE-SET-ETHEREUM_SEPOLIA_RPC_URL",
33-
gasPrice: undefined,
34-
nonce: undefined,
35-
accounts,
37+
ethereumSepolia: {
38+
chainId: 11155111,
39+
chainSelector: "16015286601757825753",
40+
router: "0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59",
41+
rmnProxy: "0xba3f6251de62dED61Ff98590cB2fDf6871FbB991",
42+
tokenAdminRegistry: "0x95F29FEE11c5C55d26cCcf1DB6772DE953B37B82",
43+
registryModuleOwnerCustom: "0x62e731218d0D47305aba2BE3751E7EE9E5520790",
44+
link: "0x779877A7B0D9E8603169DdbD7836e478b4624789",
45+
confirmations: 3,
46+
nativeCurrencySymbol: "ETH",
47+
chainType: "l1",
48+
chainFamily: "evm"
3649
},
37-
[EVMChains.baseSepolia]: {
38-
type: "http",
39-
...configData.baseSepolia,
40-
url: process.env.BASE_SEPOLIA_RPC_URL || "https://UNSET-PLEASE-SET-BASE_SEPOLIA_RPC_URL",
41-
gasPrice: undefined,
42-
nonce: undefined,
43-
accounts,
50+
baseSepolia: {
51+
chainId: 84532,
52+
chainSelector: "10344971235874465080",
53+
router: "0xD3b06cEbF099CE7DA4AcCf578aaebFDBd6e88a93",
54+
rmnProxy: "0x99360767a4705f68CcCb9533195B761648d6d807",
55+
tokenAdminRegistry: "0x736D0bBb318c1B27Ff686cd19804094E66250e17",
56+
registryModuleOwnerCustom: "0x8A55C61227f26a3e2f217842eCF20b52007bAaBe",
57+
link: "0xE4aB69C077896252FAFBD49EFD26B5D171A32410",
58+
confirmations: 2,
59+
nativeCurrencySymbol: "ETH",
60+
chainType: "op",
61+
chainFamily: "evm"
4462
},
45-
[EVMChains.polygonAmoy]: {
46-
type: "http",
47-
...configData.polygonAmoy,
48-
url: process.env.POLYGON_AMOY_RPC_URL || "https://UNSET-PLEASE-SET-POLYGON_AMOY_RPC_URL",
49-
gasPrice: undefined,
50-
nonce: undefined,
51-
accounts,
63+
polygonAmoy: {
64+
chainId: 80002,
65+
chainSelector: "16281711391670634445",
66+
router: "0x9C32fCB86BF0f4a1A8921a9Fe46de3198bb884B2",
67+
rmnProxy: "0x7c1e545A40750Ee8761282382D51E017BAC68CBB",
68+
tokenAdminRegistry: "0x1e73f6842d7afDD78957ac143d1f315404Dd9e5B",
69+
registryModuleOwnerCustom: "0x84ad5890A63957C960e0F19b0448A038a574936B",
70+
link: "0x0Fd9e8d3aF1aaee056EB9e802c3A762a667b1904",
71+
confirmations: 3,
72+
nativeCurrencySymbol: "POL",
73+
chainType: "l1",
74+
chainFamily: "evm"
5275
},
76+
solanaDevnet: {
77+
chainId: "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG",
78+
chainSelector: "16423721717087811551",
79+
chainType: "generic",
80+
chainFamily: "svm"
81+
}
5382
};
5483

55-
export { networks, configData };
84+
// Generate Hardhat networks from configData (EVM only)
85+
const networks: Record<string, any> = {};
86+
87+
for (const [name, config] of Object.entries(configData)) {
88+
if (config.chainFamily === "evm") {
89+
const envVarName = `${name.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase()}_RPC_URL`;
90+
networks[name] = {
91+
type: "http" as const,
92+
...config,
93+
url: process.env[envVarName] || `https://UNSET-PLEASE-SET-${envVarName}`,
94+
gasPrice: undefined,
95+
nonce: undefined,
96+
accounts,
97+
};
98+
}
99+
}
100+
101+
export { networks };
102+

0 commit comments

Comments
 (0)