-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
viem/chains: chain exports for the superchain registry (#615)
* viem superchain registry bindings * chaingen * lint fix * more lint * fix template according to lint rules. use path.join * lint * changeset * index.ts for chains. remove from global export * export chains * add some comments * undo optimism submodule
- Loading branch information
1 parent
15ca959
commit d07cb41
Showing
14 changed files
with
3,506 additions
and
448 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@eth-optimism/viem": patch | ||
--- | ||
|
||
added viem chain bindings based on the superchain registry |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "lib/superchain-registry"] | ||
path = lib/superchain-registry | ||
url = https://github.com/ethereum-optimism/superchain-registry |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule superchain-registry
added at
c08331
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import toml from '@iarna/toml' | ||
import { Eta } from 'eta' | ||
import fs from 'fs' | ||
import path from 'path' | ||
import type { Address, PublicClient } from 'viem' | ||
import { createPublicClient, erc20Abi, http } from 'viem' | ||
import { mainnet, sepolia } from 'viem/chains' | ||
|
||
// Hardcoded. Can take a more elaborate approach if needed. | ||
const NETWORKS = ['mainnet', 'sepolia'] | ||
const SUPERCHAIN_REGISTRY_PATH = path.join( | ||
'..', | ||
'..', | ||
'lib', | ||
'superchain-registry', | ||
) | ||
|
||
type ChainDefinition = { | ||
chainName: string | ||
exportName: string | ||
chainId: number | ||
sourceChainId: number | ||
rpc: string | ||
explorer: string | ||
nativeCurrency: NativeCurrency | ||
l1Addresses: Record<string, Address> | ||
} | ||
|
||
type NativeCurrency = { name: string; symbol: string; decimals: number } | ||
|
||
/** Utility functions **/ | ||
|
||
function camelCase(str: string): string { | ||
const parts = str.replace(/-/g, ' ').replace(/_/g, ' ').split(' ') | ||
return ( | ||
parts[0].toLowerCase() + | ||
parts | ||
.slice(1) | ||
.map((part) => part[0].toUpperCase() + part.substring(1)) | ||
.join('') | ||
) | ||
} | ||
|
||
async function nativeCurrency( | ||
client: PublicClient, | ||
address: Address | undefined, | ||
): Promise<NativeCurrency> { | ||
if (!address) { | ||
return { name: 'Ether', symbol: 'ETH', decimals: 18 } | ||
} | ||
|
||
const [name, symbol, decimals] = await Promise.all([ | ||
client.readContract({ address, abi: erc20Abi, functionName: 'name' }), | ||
client.readContract({ address, abi: erc20Abi, functionName: 'symbol' }), | ||
client.readContract({ address, abi: erc20Abi, functionName: 'decimals' }), | ||
]) | ||
|
||
return { name, symbol, decimals } | ||
} | ||
|
||
/** Chain Generation **/ | ||
|
||
async function main() { | ||
console.log('Running chain generation...') | ||
const eta = new Eta({ | ||
views: './scripts/templates', | ||
debug: true, | ||
autoTrim: [false, false], | ||
}) | ||
|
||
const mainnetHttp = process.env.MAINNET_RPC_URL | ||
? [process.env.MAINNET_RPC_URL] | ||
: mainnet.rpcUrls.default.http | ||
const mainnetClient = createPublicClient({ | ||
chain: { ...mainnet, rpcUrls: { default: { http: mainnetHttp } } }, | ||
transport: http(), | ||
}) | ||
|
||
const sepoliaHttp = process.env.SEPOLIA_RPC_URL | ||
? [process.env.SEPOLIA_RPC_URL] | ||
: sepolia.rpcUrls.default.http | ||
const sepoliaClient = createPublicClient({ | ||
chain: { ...sepolia, rpcUrls: { default: { http: sepoliaHttp } } }, | ||
transport: http(), | ||
}) | ||
|
||
for (const network of NETWORKS) { | ||
console.log(`Generating ${network}`) | ||
const client = network === 'mainnet' ? mainnetClient : sepoliaClient | ||
|
||
const configPath = path.join( | ||
SUPERCHAIN_REGISTRY_PATH, | ||
'superchain', | ||
'configs', | ||
network, | ||
) | ||
|
||
// `superchain.toml` contains information on activation times as well as the | ||
// applicable l1 contracts for the chain. We exclude this file as a chain entry | ||
const entries = fs | ||
.readdirSync(configPath) | ||
.filter((entry) => !entry.includes('superchain')) | ||
|
||
const chainDefs = await Promise.all( | ||
entries.map(async (entry) => { | ||
const chainConfig = toml.parse( | ||
fs.readFileSync(`${configPath}/${entry}`, 'utf8'), | ||
) | ||
|
||
const addresses = chainConfig.addresses as Record<string, Address> | ||
const l1Addresses = { | ||
// Referenced as `portal` in viem | ||
portal: addresses.OptimismPortalProxy, | ||
|
||
// Standard Deployments | ||
l1StandardBridge: addresses.L1StandardBridgeProxy, | ||
l1Erc721Bridge: addresses.L1ERC721BridgeProxy, | ||
l1CrossDomainMessenger: addresses.L1CrossDomainMessengerProxy, | ||
systemConfig: addresses.SystemConfigProxy, | ||
} | ||
|
||
if (addresses.DisputeGameFactoryProxy) { | ||
l1Addresses['disputeGameFactory'] = addresses.DisputeGameFactoryProxy | ||
} | ||
if (addresses.L2OutputOracleProxy) { | ||
l1Addresses['l2OutputOracle'] = addresses.L2OutputOracleProxy | ||
} | ||
|
||
// This is an edge case handler for the `arena-z-testnet` chain name. | ||
const normalizedName = entry | ||
.replace('.toml', '') | ||
.replace('-testnet', '') | ||
|
||
return { | ||
chainName: chainConfig.name as string, | ||
exportName: camelCase(`${normalizedName}-${network}`), | ||
chainId: chainConfig.chain_id as number, | ||
sourceChainId: network === 'mainnet' ? 1 : 11155111, | ||
rpc: chainConfig.public_rpc as string, | ||
explorer: chainConfig.explorer as string, | ||
nativeCurrency: await nativeCurrency( | ||
client, | ||
chainConfig.gas_paying_token as Address, | ||
), | ||
l1Addresses, | ||
} satisfies ChainDefinition | ||
}), | ||
) | ||
|
||
const fileContents = eta.render('chains', { chainDefs, network }) | ||
|
||
console.log(`Writing chains to file...`) | ||
fs.writeFileSync(`src/chains/${network}.ts`, fileContents) | ||
} | ||
} | ||
|
||
;(async () => { | ||
try { | ||
await main() | ||
process.exit(0) | ||
} catch (e) { | ||
console.error(e) | ||
process.exit(-1) | ||
} | ||
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// DO NOT MODIFY THIS FILE IS AUTOGENERATED | ||
import type { Chain } from 'viem' | ||
import { defineChain } from 'viem' | ||
import { chainConfig } from 'viem/op-stack' | ||
|
||
<%- it.chainDefs.forEach(function(chainDef){ %> | ||
/** | ||
* Chain Definition for <%= chainDef.chainName %> | ||
*/ | ||
export const <%= chainDef.exportName %>: Chain = defineChain({ | ||
...chainConfig, | ||
name: '<%= chainDef.chainName %>', | ||
id: <%= chainDef.chainId %>, | ||
sourceId: <%= chainDef.sourceChainId %>, | ||
nativeCurrency: { | ||
name: '<%= chainDef.nativeCurrency.name %>', | ||
symbol: '<%= chainDef.nativeCurrency.symbol %>', | ||
decimals: <%= chainDef.nativeCurrency.decimals %>, | ||
}, | ||
rpcUrls: { | ||
default: { | ||
http: ['<%= chainDef.rpc %>'], | ||
}, | ||
}, | ||
blockExplorers: { | ||
default: { | ||
name: '<%= chainDef.chainName %> Explorer', | ||
url: '<%= chainDef.explorer %>', | ||
}, | ||
}, | ||
contracts: { | ||
...chainConfig.contracts, | ||
<%_ Object.entries(chainDef.l1Addresses).forEach(function([name, address]){ %> | ||
<%= name %>: { | ||
<%= chainDef.sourceChainId %>: { | ||
address: '<%= address %>', | ||
}, | ||
}, | ||
<%_ }) %> | ||
}, | ||
}) | ||
<% }) -%> | ||
|
||
export const <%= it.network %>Chains = [ | ||
<%_ it.chainDefs.forEach(function(chainDef){ %> | ||
<%= chainDef.exportName %>, | ||
<%_ }) %> | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './mainnet.js' | ||
export * from './sepolia.js' | ||
export * from './supersim.js' |
Oops, something went wrong.