Commit 9a5e8798 authored by Will Cory's avatar Will Cory

feat: Add ts contract package for TS

different package nah

do it right

Update packages/contracts-ts/CODE_GEN.md

Update packages/contracts-ts/CODE_GEN.md

Update packages/contracts-ts/package.json

Update packages/contracts-ts/package.json

Update packages/contracts-ts/package.json

Update packages/contracts-ts/package.json

Update packages/contracts-ts/package.json

Update packages/contracts-ts/wagmi.config.ts

Update packages/contracts-ts/wagmi.config.ts

feat: generate abis too

feat: Update op-bindings README

feat: Add lint

feat: Add circleci

fix: Fix deploy config

fix: Add coverage

fix: linter

self review nits

fix: Test was not doing what it thought it was doing

linter
parent 5eb852bb
......@@ -3,7 +3,7 @@
"changelog": ["@changesets/changelog-github", { "repo": "ethereum-optimism/optimism" }],
"commit": false,
"fixed": [],
"linked": [],
"linked": [["contracts-bedrock", "contracts-ts"]],
"access": "public",
"baseBranch": "develop",
"updateInternalDependencies": "patch",
......
......@@ -709,6 +709,27 @@ jobs:
name: Upload coverage
command: codecov --verbose --clean --flags <<parameters.coverage_flag>>
contracts-ts-tests:
docker:
- image: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
resource_class: large
steps:
- checkout
- attach_workspace: { at: "." }
- restore_cache:
name: Restore pnpm Package Cache
keys:
- pnpm-packages-v2-{{ checksum "pnpm.lock.yaml" }}
- check-changed:
patterns: sdk,contracts-bedrock,contracts
- run:
name: Check generated and build
command: pnpm generate:check
working_directory: packages/contracts-ts
- run:
name: typecheck
command: pnpm typecheck
sdk-next-tests:
docker:
- image: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
......@@ -1336,6 +1357,13 @@ workflows:
dependencies: "(common-ts|core-utils|sdk)"
requires:
- pnpm-monorepo
- js-lint-test:
name: contracts-ts-tests
coverage_flag: contracts-ts-tests
package_name: contracts-ts
dependencies: '(contracts-bedrock|contracts-ts)'
requires:
- pnpm-monorepo
- js-lint-test:
name: sdk-next-tests
coverage_flag: sdk-next-tests
......
......@@ -56,6 +56,9 @@
"inputs": ["default", "testing", "^production"],
"dependsOn": ["^build"]
},
"generate": {
"dependsOn": ["^build"]
},
"build:contracts": {
"inputs": [
"configsProject",
......
......@@ -28,3 +28,7 @@ $ make devtools
```
The geth docs for `abigen` can be found [here](https://geth.ethereum.org/docs/dapp/native-bindings).
## See also
TypeScript bindings are also generated in [@eth-optimism/contracts-ts](../packages/contracts-ts/)
......@@ -9,8 +9,10 @@
"contracts/**/*.sol"
],
"scripts": {
"bindings": "cd ../../op-bindings && make",
"build": "npx nx build:contracts",
"bindings": "pnpm bindings:ts && pnpm bindings:go",
"bindings:ts": "nx generate @eth-optimism/contracts-ts",
"bindings:go": "cd ../../op-bindings && make",
"build": "nx build:contracts",
"prebuild:contracts": "./scripts/verify-foundry-install.sh",
"build:contracts": "pnpm build:forge",
"build:forge": "forge build",
......
artifacts
cache
typechain
.deps
.envrc
.env
/dist/
coverage
artifacts
cache
typechain
.deps
.envrc
.env
/dist/
module.exports = {
...require('../../.prettierrc.js'),
}
# Code gen
Summary -
- This package is generated from [contracts-bedrock](../contracts-bedrock/)
- It's version is kept in sync with contracts bedrock via the [changeset config](../../.changeset/config.json) e.g. if contracts-bedrock is `4.2.0` this package will have the same version.
## Code gen instructions
To run the code gen run the `generate` script from [package.json](./package.json). Make sure node modules is installed.
```bash
pnpm i && pnpm generate
```
MIT License
Copyright (c) 2022 Optimism
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
## Contracts TS
[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/develop/graph/badge.svg?token=0VTG7PG7YR&flag=contracts-bedrock-tests)](https://codecov.io/gh/ethereum-optimism/optimism)
ABI and Address constants + generated code from [@eth-optimism/contracts-bedrock/](../contracts-bedrock/) for use in TypeScript.
Much of this package is generated. See [CODE_GEN.md](./CODE_GEN.md) for instructions on how to generate.
#### @eth-optimism/contracts-ts
The main entrypoint exports constants related to contracts bedrock as const. As const allows it to be [used in TypeScript with stronger typing than importing JSON](https://github.com/microsoft/TypeScript/issues/32063).
- Exports contract abis.
- Exports contract addresses
```typescript
import {
l2OutputOracleProxyABI,
l2OutputOracleAddresses,
} from '@eth-optimism/contracts-ts'
console.log(l2OutputOracleAddresses[10], abi)
```
Addresses are also exported as an object for convenience.
```typescript
import { addresses } from '@eth-optimism/contracts-ts'
console.log(addresses.l2OutputOracle[10])
```
#### @eth-optimism/contracts-ts/react
- All [React hooks](https://wagmi.sh/cli/plugins/react) `@eth-optimism/contracts-ts/react`
```typescript
import { useAddressManagerAddress } from '@eth-optimism/contracts-ts/react'
const component = () => {
const { data, error, loading } = useAddressManagerAddress()
if (loading) {
return <div>Loading</div>
}
if (err) {
return <div>Error</div>
}
return <div>{data}</div>
}
```
#### @eth-optimism/contracts-ts/actions
- All [wagmi actions](https://wagmi.sh/react/actions) for use in Vanilla JS or non react code
```typescript
import { readSystemConfig } from '@eth-optimism/contracts-ts/actions'
console.log(await readSystemConfig())
```
#### See Also
- [Contracts bedrock specs](../../specs/)
- [Wagmi](https://wagmi.sh)
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"AddressManager": {
"1": "0xdE1FCfB0851916CA5101820A69b13a4E276bd81F",
"5": "0xa6f73589243a6A7a9023b1Fa0651b1d89c177111"
},
"L1CrossDomainMessenger": {
"1": "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1",
"5": "0x5086d1eEF304eb5284A0f6720f79403b4e9bE294"
},
"L1ERC721Bridge": {
"1": "0x5a7749f83b81B301cAb5f48EB8516B986DAef23D",
"5": "0x8DD330DdE8D9898d43b4dc840Da27A07dF91b3c9"
},
"L1StandardBridge": {
"1": "0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1",
"5": "0x636Af16bf2f682dD3109e60102b8E1A089FedAa8"
},
"L2OutputOracle": {
"1": "0xdfe97868233d1aa22e815a266982f2cf17685a27",
"5": "0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0"
},
"OptimismMintableERC20Factory": {
"1": "0x4200000000000000000000000000000000000012",
"5": "0x4200000000000000000000000000000000000012",
"420": "0x4200000000000000000000000000000000000012"
},
"OptimismPortal": {
"1": "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed",
"5": "0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383"
},
"PortalSender": {
"1": "0x0A893d9576b9cFD9EF78595963dc973238E78210",
"5": "0xe7FACd39531ee3C313330E93B4d7a8B8A3c84Aa4"
},
"ProxyAdmin": {
"1": "0x4200000000000000000000000000000000000018",
"5": "0x4200000000000000000000000000000000000018"
},
"SystemConfig": {
"1": "0x229047fed2591dbec1eF1118d64F7aF3dB9EB290",
"5": "0xAe851f927Ee40dE99aaBb7461C00f9622ab91d60"
},
"SystemDictator": {
"1": "0xB4453CEb33d2e67FA244A24acf2E50CEF31F53cB"
},
"SystemDictator_goerli": {
"5": "0x1f0613A44c9a8ECE7B3A2e0CdBdF0F5B47A50971"
},
"MintManager": {
"10": "0x5C4e7Ba1E219E47948e6e3F55019A647bA501005",
"420": "0x038a8825A3C3B0c08d52Cc76E5E361953Cf6Dc76"
},
"OptimismMintableERC721Factory": {
"10": "0x4200000000000000000000000000000000000017"
},
"OptimismMintableERC721Factory_optimism-goerli": {
"420": "0x4200000000000000000000000000000000000017"
},
"BaseFeeVault": {
"420": "0x4200000000000000000000000000000000000019"
},
"GasPriceOracle": {
"420": "0x420000000000000000000000000000000000000F"
},
"L1Block": {
"420": "0x4200000000000000000000000000000000000015"
},
"L1FeeVault": {
"420": "0x420000000000000000000000000000000000001a"
},
"L2CrossDomainMessenger": {
"420": "0x4200000000000000000000000000000000000007"
},
"L2ERC721Bridge": {
"420": "0x4200000000000000000000000000000000000014"
},
"L2StandardBridge": {
"420": "0x4200000000000000000000000000000000000010"
},
"L2ToL1MessagePasser": {
"420": "0x4200000000000000000000000000000000000016"
},
"SequencerFeeVault": {
"420": "0x4200000000000000000000000000000000000011"
}
}
VITE_RPC_URL_L2_GOERLI=
VITE_RPC_URL_L2_MAINNET=
VITE_RPC_URL_L1_GOERLI=
VITE_RPC_URL_L1_MAINNET=
{
"name": "@eth-optimism/contracts-ts",
"version": "0.15.0",
"description": "TypeScript interface for Contracts Bedrock",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/ethereum-optimism/optimism.git",
"directory": "packages/contracts-ts"
},
"homepage": "https://optimism.io",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "src/index.ts",
"exports": {
".": {
"types": "./src/index.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"./actions": {
"types": "./src/actions.ts",
"import": "./dist/actions.js",
"require": "./dist/actions.cjs"
},
"./react": {
"types": "./src/react.ts",
"import": "./dist/react.js",
"require": "./dist/react.cjs"
}
},
"files": [
"dist/",
"src/"
],
"scripts": {
"build": "tsup",
"generate": "nx build @eth-optimism/contracts-bedrock && wagmi generate && pnpm build && pnpm lint:fix",
"generate:check": "pnpm generate && git diff --exit-code ./addresses.json && git diff --exit-code ./abis.json",
"lint": "prettier --check .",
"lint:fix": "prettier --write .",
"test": "vitest",
"test:coverage": "vitest run --coverage",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@eth-optimism/contracts-bedrock": "workspace:0.15.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react-hooks": "^8.0.1",
"@types/glob": "^8.1.0",
"@vitest/coverage-istanbul": "^0.33.0",
"@wagmi/cli": "^1.3.0",
"@wagmi/core": "^1.3.7",
"abitype": "^0.9.0",
"glob": "^7.2.3",
"isomorphic-fetch": "^3.0.0",
"jest-dom": "link:@types/@testing-library/jest-dom",
"jsdom": "^22.1.0",
"tsup": "^7.1.0",
"typescript": "^4.9.3",
"vite": "^4.4.3",
"vitest": "^0.33.0"
},
"peerDependencies": {
"@wagmi/core": ">1.0.0",
"wagmi": ">1.0.0"
},
"peerDependenciesMeta": {
"wagmi": {
"optional": true
},
"@wagmi/core": {
"optional": true
}
},
"dependencies": {
"@testing-library/react": "^14.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"viem": "^0.3.30"
}
}
import fetch from 'isomorphic-fetch'
// viem needs this
global.fetch = fetch
import { test, expect } from 'vitest'
import { getOptimismPortal } from './actions'
import { createConfig, configureChains } from 'wagmi'
import { jsonRpcProvider } from 'wagmi/providers/jsonRpc'
import { mainnet } from 'viem/chains'
const { publicClient } = configureChains(
[mainnet],
[
jsonRpcProvider({
rpc: () => ({
http:
import.meta.env.VITE_RPC_URL_L1_MAINNET ?? mainnet.rpcUrls.default[0],
}),
}),
]
)
createConfig({
publicClient: ({ chainId }) => publicClient({ chainId }),
})
const blockNumber = BigInt(17681356)
test('should be able to create a wagmi contract and use it', async () => {
const portal = getOptimismPortal({ chainId: 1 })
expect(portal).toBeDefined()
expect(await portal.read.version({ blockNumber })).toMatchInlineSnapshot(
'"1.6.0"'
)
})
This source diff could not be displayed because it is too large. You can view the blob instead.
import { test, expect } from 'vitest'
import { addresses } from './constants'
import { readFileSync } from 'fs'
import { join } from 'path'
const jsonAddresses = JSON.parse(
readFileSync(join(__dirname, '../addresses.json'), 'utf8')
)
test('should have generated addresses', () => {
expect(addresses).toEqual(jsonAddresses)
})
This source diff could not be displayed because it is too large. You can view the blob instead.
export * from './constants'
import matchers from '@testing-library/jest-dom/matchers'
import { cleanup, waitFor } from '@testing-library/react'
import { renderHook } from '@testing-library/react-hooks'
import { afterEach, expect, test } from 'vitest'
import { useMintManagerOwner } from './react'
import { configureChains, createConfig, WagmiConfig } from 'wagmi'
import * as React from 'react'
import { optimism } from 'viem/chains'
import { jsonRpcProvider } from 'wagmi/providers/jsonRpc'
expect.extend(matchers)
afterEach(() => {
cleanup()
})
const { publicClient } = configureChains(
[optimism],
[
jsonRpcProvider({
rpc: () => ({
http:
import.meta.env.VITE_RPC_URL_L2_MAINNET ??
'https://mainnet.optimism.io',
}),
}),
]
)
const config = createConfig({
publicClient: ({ chainId }) => publicClient({ chainId }),
})
const blockNumber = BigInt(106806163)
test('react hooks should work', async () => {
const hook = renderHook(
() => useMintManagerOwner({ chainId: 10, blockNumber }),
{
wrapper: ({ children }) => (
<WagmiConfig config={config}>{children}</WagmiConfig>
),
}
)
await waitFor(() => {
hook.rerender()
if (hook.result.current.error) throw hook.result.current.error
expect(hook.result.current?.data).toBeDefined()
})
const normalizedResult = {
...hook.result.current,
internal: {
...hook.result.current.internal,
dataUpdatedAt: 'SNAPSHOT_TEST_REMOVED!!!',
},
}
expect(normalizedResult).toMatchInlineSnapshot(`
{
"data": "0x2A82Ae142b2e62Cb7D10b55E323ACB1Cab663a26",
"error": null,
"fetchStatus": "idle",
"internal": {
"dataUpdatedAt": "SNAPSHOT_TEST_REMOVED!!!",
"errorUpdatedAt": 0,
"failureCount": 0,
"isFetchedAfterMount": true,
"isLoadingError": false,
"isPaused": false,
"isPlaceholderData": false,
"isPreviousData": false,
"isRefetchError": false,
"isStale": true,
"remove": [Function],
},
"isError": false,
"isFetched": true,
"isFetchedAfterMount": true,
"isFetching": false,
"isIdle": false,
"isLoading": false,
"isRefetching": false,
"isSuccess": true,
"refetch": [Function],
"status": "success",
}
`)
})
This source diff could not be displayed because it is too large. You can view the blob instead.
/// <reference types="vite/client" />
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"baseUrl": "./src",
"strict": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "node",
"jsx": "react",
"target": "ESNext",
"noEmit": true
},
"include": ["./src"]
}
import { defineConfig } from 'tsup'
export default defineConfig({
name: '@eth-optimsim/contracts-ts',
entry: ['src/index.ts', 'src/actions.ts', 'src/react.ts'],
outDir: 'dist',
format: ['esm', 'cjs'],
splitting: false,
sourcemap: true,
clean: false,
})
import { defineConfig } from 'vitest/config'
// @see https://vitest.dev/config/
export default defineConfig({
test: {
setupFiles: './setupVitest.ts',
environment: 'jsdom',
coverage: {
provider: 'istanbul',
},
},
})
import { ContractConfig, defineConfig, Plugin } from '@wagmi/cli'
import { actions, react } from '@wagmi/cli/plugins'
import glob from 'glob'
import { readFileSync, writeFileSync } from 'fs'
import type { Abi, AbiFunction, Address } from 'abitype'
import { isDeepStrictEqual } from 'util'
/**
* Predeployed contract addresses
* In future it would be nice to have a json file in contracts bedrock be generated as source of truth
*/
const predeployContracts = {
LegacyMessagePasser: {
address: '0x4200000000000000000000000000000000000000',
introduced: 'Legacy',
deprecated: true,
proxied: true,
},
DeployerWhitelist: {
address: '0x4200000000000000000000000000000000000002',
introduced: 'Legacy',
deprecated: true,
proxied: true,
},
LegacyERC20ETH: {
address: '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
introduced: 'Legacy',
deprecated: true,
proxied: false,
},
WETH9: {
address: '0x4200000000000000000000000000000000000006',
introduced: 'Legacy',
deprecated: false,
proxied: false,
},
L2CrossDomainMessenger: {
address: '0x4200000000000000000000000000000000000007',
introduced: 'Legacy',
deprecated: false,
proxied: true,
},
L2StandardBridge: {
address: '0x4200000000000000000000000000000000000010',
introduced: 'Legacy',
deprecated: false,
proxied: true,
},
SequencerFeeVault: {
address: '0x4200000000000000000000000000000000000011',
introduced: 'Legacy',
deprecated: false,
proxied: true,
},
OptimismMintableERC20Factory: {
address: '0x4200000000000000000000000000000000000012',
introduced: 'Legacy',
deprecated: false,
proxied: true,
},
L1BlockNumber: {
address: '0x4200000000000000000000000000000000000013',
introduced: 'Legacy',
deprecated: true,
proxied: true,
},
GasPriceOracle: {
address: '0x420000000000000000000000000000000000000F',
introduced: 'Legacy',
deprecated: false,
proxied: true,
},
GovernanceToken: {
address: '0x4200000000000000000000000000000000000042',
introduced: 'Legacy',
deprecated: false,
proxied: false,
},
L1Block: {
address: '0x4200000000000000000000000000000000000015',
introduced: 'Bedrock',
deprecated: false,
proxied: true,
},
L2ToL1MessagePasser: {
address: '0x4200000000000000000000000000000000000016',
introduced: 'Bedrock',
deprecated: false,
proxied: true,
},
L2ERC721Bridge: {
address: '0x4200000000000000000000000000000000000014',
introduced: 'Legacy',
deprecated: false,
proxied: true,
},
OptimismMintableERC721Factory: {
address: '0x4200000000000000000000000000000000000017',
introduced: 'Bedrock',
deprecated: false,
proxied: true,
},
ProxyAdmin: {
address: '0x4200000000000000000000000000000000000018',
introduced: 'Bedrock',
deprecated: false,
proxied: true,
},
BaseFeeVault: {
address: '0x4200000000000000000000000000000000000019',
introduced: 'Bedrock',
deprecated: false,
proxied: true,
},
L1FeeVault: {
address: '0x420000000000000000000000000000000000001a',
introduced: 'Bedrock',
deprecated: false,
proxied: true,
},
} as const
type DeploymentJson = {
abi: Abi
address: `0x${string}`
}
const chains = {
1: 'mainnet',
10: 'optimism-mainnet',
5: 'goerli',
420: 'optimism-goerli',
} as const
if (!glob.sync('node_modules/*').length) {
throw new Error(
'No node_modules found. Please run `pnpm install` before running this script'
)
}
const deployments = {
[1]: glob.sync(
`node_modules/@eth-optimism/contracts-bedrock/deployments/${chains[1]}/*.json`
),
[10]: glob.sync(
`node_modules/@eth-optimism/contracts-bedrock/deployments/${chains[10]}/*.json`
),
[5]: glob.sync(
`node_modules/@eth-optimism/contracts-bedrock/deployments/${chains[5]}/*.json`
),
[420]: glob.sync(
`node_modules/@eth-optimism/contracts-bedrock/deployments/${chains[420]}/*.json`
),
}
Object.entries(deployments).forEach(([chain, deploymentFiles]) => {
if (deploymentFiles.length === 0) {
throw new Error(`No deployments found for ${chains[chain]}`)
}
})
const getWagmiContracts = (deploymentFiles: string[]) =>
deploymentFiles.map((artifactPath) => {
const deployment = JSON.parse(
readFileSync(artifactPath, 'utf8')
) as DeploymentJson
// There is a wagmi bug we need to filter out the MESSENGER method because it collides with messenger
// @see https://github.com/wagmi-dev/wagmi/issues/2724
const filterOut = new Set([
'MESSENGER',
'OTHER_BRIDGE',
'VERSION',
'DECIMALS',
])
const abi = deployment.abi.filter(
(item) => !filterOut.has((item as AbiFunction).name)
)
const contractConfig = {
abi,
name: artifactPath.split('/').reverse()[0]?.replace('.json', ''),
address: deployment.address,
} satisfies ContractConfig
if (!contractConfig.name) {
throw new Error(
'Unable to identify the name of the contract at ' + artifactPath
)
}
return contractConfig
})
/**
* Returns the contracts for the wagmi cli config
*/
const getContractConfigs = () => {
const contracts = {
1: getWagmiContracts(deployments[1]),
10: getWagmiContracts(deployments[10]),
5: getWagmiContracts(deployments[5]),
420: getWagmiContracts(deployments[420]),
}
const allContracts = Object.values(contracts).flat()
const config: ContractConfig[] = []
// this for loop is not terribly efficient but seems fast enough for the scale here
for (const contract of allContracts) {
// we will only process the implementation ABI but will use teh proxy addresses for deployments
const isProxy = contract.name.endsWith('Proxy')
// once we see the first deployment of a contract we will process all networks all at once
const alreadyProcessedContract = config.find(
(c) => c.name === contract.name
)
if (isProxy || alreadyProcessedContract) {
continue
}
const implementations = {
// @warning Later code assumes mainnet is first!!!
[1]: contracts[1].find((c) => c.name === contract.name),
// @warning Later code assumes mainnet is first!!!
[10]: contracts[10].find((c) => c.name === contract.name),
[5]: contracts[5].find((c) => c.name === contract.name),
[420]: contracts[420].find((c) => c.name === contract.name),
}
const maybeProxyName = contract.name + 'Proxy'
const proxies = {
// @warning Later code assumes mainnet is first!!!
[1]: contracts[1].find((c) => c.name === maybeProxyName),
// @warning Later code assumes mainnet is first!!!
[10]: contracts[10].find((c) => c.name === maybeProxyName),
[5]: contracts[5].find((c) => c.name === maybeProxyName),
[420]: contracts[420].find((c) => c.name === maybeProxyName),
}
const predeploy = predeployContracts[
contract.name as keyof typeof predeployContracts
] as { address: Address } | undefined
// If the contract has different abis on different networks we don't want to group them as a single abi
const isContractUnique = !Object.values(implementations).some(
(implementation) =>
implementation && !isDeepStrictEqual(implementation.abi, contract.abi)
)
if (!isContractUnique) {
Object.entries(implementations)
.filter(([_, implementation]) => implementation)
.forEach(([chain, implementation], i) => {
if (implementation) {
// make the first one cannonical. This will be mainnet or op mainnet if they exist
const name =
i === 0 ? contract.name : `${contract.name}_${chains[chain]}`
const nextConfig = {
abi: implementation.abi,
name,
address: {
[Number.parseInt(chain)]:
predeploy?.address ??
proxies[chain]?.address ??
implementation?.address,
}, // predeploy?.address ?? proxies[chain]?.address ?? implementation?.address
} satisfies ContractConfig
config.push(nextConfig)
}
})
continue
}
const wagmiConfig = {
abi: contract.abi,
name: contract.name,
address: {},
} satisfies ContractConfig
Object.entries(implementations).forEach(([chain, proxy]) => {
if (proxy) {
wagmiConfig.address[chain] =
predeploy?.address ?? proxy.address ?? contract.address
}
})
// if proxies exist overwrite the address with the proxy address
Object.entries(proxies).forEach(([chain, proxy]) => {
if (proxy) {
wagmiConfig.address[chain] = predeploy?.address ?? proxy.address
}
})
config.push(wagmiConfig)
}
return config
}
/**
* This plugin will create a addresses mapping from contract name to address
*/
const addressesByContractByNetworkPlugin: Plugin = {
name: 'addressesByContractByNetwork',
run: async ({ contracts }) => {
const addresses = Object.fromEntries(
contracts.map((contract) => [contract.name, contract.address ?? {}])
)
// write to json file so it's easy to audit in prs relative to the generated file diff
writeFileSync('./addresses.json', JSON.stringify(addresses, null, 2))
return {
content: [
`export const addresses = ${JSON.stringify(addresses)} as const`,
`export const predeploys = ${JSON.stringify(predeployContracts)}`,
].join('\n'),
}
},
}
/**
* This plugin will create an abi mapping from contract name to abi
*/
const abiPlugin: Plugin = {
name: 'abisByContractByNetwork',
run: async ({ contracts }) => {
const abis = Object.fromEntries(
contracts.map((contract) => [contract.name, contract.abi])
)
// write to json file so it's easy to audit in prs relative to the generated file diff
writeFileSync('./abis.json', JSON.stringify(abis, null, 2))
return {
content: `export const abis = ${JSON.stringify(abis)} as const`,
}
},
}
/**
* This plugin adds an eslint ignore to the generated code
*/
const eslintIgnorePlugin: Plugin = {
name: 'eslintIgnore',
run: async () => {
return {
prepend: `/* eslint-disable */`,
content: ``,
}
},
}
const contracts = getContractConfigs()
// @see https://wagmi.sh/cli
export default defineConfig([
{
out: 'src/constants.ts',
contracts,
plugins: [
eslintIgnorePlugin,
addressesByContractByNetworkPlugin,
abiPlugin,
],
},
{
out: 'src/actions.ts',
contracts,
plugins: [eslintIgnorePlugin, actions()],
},
{
out: 'src/react.ts',
contracts,
plugins: [eslintIgnorePlugin, react()],
},
])
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment