Skip to content

Commit 400fda6

Browse files
committed
chore: implements base populate script
1 parent 4e346aa commit 400fda6

6 files changed

Lines changed: 399 additions & 0 deletions

File tree

populate-script/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# General
2+
yarn-error.log
3+
node_modules
4+
.DS_STORE
5+
.vscode
6+
7+
# Config files
8+
.env
9+
10+
# Avoid ignoring gitkeep
11+
!/**/.gitkeep
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[
2+
{
3+
"type": "function",
4+
"name": "setRecords",
5+
"stateMutability": "nonpayable",
6+
"inputs": [
7+
{ "name": "_nodes", "type": "bytes32[]" },
8+
{ "name": "_keys", "type": "string[]" },
9+
{ "name": "_values", "type": "bytes[]" }
10+
],
11+
"outputs": []
12+
}
13+
]

populate-script/package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "populate-script",
3+
"version": "1.0.0",
4+
"license": "MIT",
5+
"main": "index.js",
6+
"scripts": {
7+
"populate": "ts-node script.ts"
8+
},
9+
"dependencies": {
10+
"viem": "^2.36.0"
11+
},
12+
"devDependencies": {
13+
"@types/node": "^24.3.0",
14+
"ts-node": "^10.9.2",
15+
"typescript": "^5.9.2"
16+
}
17+
}

populate-script/script.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { encodeAbiParameters, encodeFunctionData, keccak256, namehash, stringToBytes } from 'viem';
2+
import L2ResolverAbi from './abis/L2Resolver.json';
3+
4+
type RawChainItem = {
5+
name: string;
6+
chainId: number;
7+
subDomain: string;
8+
shortName: string;
9+
};
10+
11+
type ChainRecord = {
12+
name: string;
13+
chainId: number;
14+
subDomain: string;
15+
shortName: string;
16+
};
17+
18+
const SOURCE_URL: string = "https://chainid.network/chains_mini.json";
19+
const BATCH_SIZE: number = 10;
20+
const L2_SUFFIX = '.l2.eth';
21+
const CHAIN_IDENTIFIER_EIP7930_KEY = 'chain.id.eip7930';
22+
const REVERSE_LOOKUP_NODE: `0x${string}` = keccak256(stringToBytes('reverse.chain.id.eip7930')) as `0x${string}`;
23+
24+
const processBatch = async (
25+
_batch: ChainRecord[]
26+
): Promise<[number[], `0x${string}`, `0x${string}`]> => {
27+
const forwardNodes: `0x${string}`[] = [];
28+
const forwardKeys: string[] = [];
29+
const forwardValues: `0x${string}`[] = [];
30+
31+
const reverseNodes: `0x${string}`[] = [];
32+
const reverseKeys: string[] = [];
33+
const reverseValues: `0x${string}`[] = [];
34+
35+
const chainIds: number[] = [];
36+
37+
for (const item of _batch) {
38+
const subDomain = item.subDomain || item.shortName || item.name; // TODO: Review this
39+
const domain = `${subDomain}${L2_SUFFIX}`;
40+
41+
const nodeNamehash = namehash(domain);
42+
const chainIdBytes = encodeEIP7930ChainIdBytes(item.chainId);
43+
chainIds.push(item.chainId);
44+
45+
forwardNodes.push(nodeNamehash);
46+
forwardKeys.push(CHAIN_IDENTIFIER_EIP7930_KEY);
47+
forwardValues.push(chainIdBytes);
48+
49+
const identifierHash = keccak256(chainIdBytes); // do I need keccak256?
50+
const reverseKey = `${CHAIN_IDENTIFIER_EIP7930_KEY}${identifierHash}`;
51+
const encodedDomain = encodeAbiParameters([{ type: 'string' }], [domain]);
52+
53+
reverseNodes.push(REVERSE_LOOKUP_NODE);
54+
reverseKeys.push(reverseKey);
55+
reverseValues.push(encodedDomain);
56+
}
57+
58+
const forwardCalldata = encodeFunctionData({
59+
abi: L2ResolverAbi,
60+
functionName: 'setRecords',
61+
args: [forwardNodes, forwardKeys, forwardValues],
62+
});
63+
64+
const reverseCalldata = encodeFunctionData({
65+
abi: L2ResolverAbi,
66+
functionName: 'setRecords',
67+
args: [reverseNodes, reverseKeys, reverseValues],
68+
});
69+
70+
return [chainIds, forwardCalldata, reverseCalldata];
71+
};
72+
73+
const fetchChains = async (): Promise<RawChainItem[]> => {
74+
const response = await fetch(SOURCE_URL);
75+
if (!response.ok) {
76+
throw new Error(`Failed to fetch chains: ${response.status} ${response.statusText}`);
77+
}
78+
return (await response.json()) as RawChainItem[];
79+
};
80+
81+
const toChainRecord = (item: RawChainItem): ChainRecord => {
82+
return {
83+
name: item.name,
84+
chainId: item.chainId,
85+
subDomain: item.subDomain || '',
86+
shortName: item.shortName,
87+
};
88+
};
89+
90+
const chunkArray = <ChainRecord>(items: ChainRecord[], chunkSize: number): ChainRecord[][] => {
91+
const chunks: ChainRecord[][] = [];
92+
for (let i = 0; i < items.length; i += chunkSize) {
93+
chunks.push(items.slice(i, i + chunkSize));
94+
}
95+
return chunks;
96+
};
97+
98+
const main = async (): Promise<void> => {
99+
const chains: RawChainItem[] = await fetchChains();
100+
const records: ChainRecord[] = chains.map(toChainRecord);
101+
const batches: ChainRecord[][] = chunkArray(records, BATCH_SIZE);
102+
103+
for (const batch of batches) {
104+
const [chainIds, forwardCalldata, reverseCalldata] = await processBatch(batch);
105+
console.log(chainIds, forwardCalldata, reverseCalldata);
106+
}
107+
};
108+
109+
main().catch((error) => {
110+
console.error(error);
111+
process.exitCode = 1;
112+
});
113+
114+
function encodeEIP7930ChainIdBytes(chainId: number): `0x${string}` {
115+
// TODO
116+
return '0x00';
117+
}
118+

populate-script/tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2020",
4+
"module": "commonjs",
5+
"esModuleInterop": true,
6+
"strict": true,
7+
"skipLibCheck": true,
8+
"resolveJsonModule": true
9+
}
10+
}

0 commit comments

Comments
 (0)