|
| 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 | + |
0 commit comments