Commit a14047b0 authored by Kelvin Fichter's avatar Kelvin Fichter

refactor: remove hardhat-ovm plugin and its deps

parent 1e63ffa0
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
# packages/contracts/ @smartcontracts @ben-chain @maurelian @elenadimitrova # packages/contracts/ @smartcontracts @ben-chain @maurelian @elenadimitrova
# packages/specs/protocol/ @smartcontracts @ben-chain @maurelian # packages/specs/protocol/ @smartcontracts @ben-chain @maurelian
# ops/ @tynes @karlfloersch # ops/ @tynes @karlfloersch
# packages/hardhat-ovm/ @smartcontracts
# packages/core-utils/ @smartcontracts @annieke @ben-chain # packages/core-utils/ @smartcontracts @annieke @ben-chain
# packages/common-ts/ @annieke # packages/common-ts/ @annieke
# packages/core-utils/src/watcher.ts @K-Ho # packages/core-utils/src/watcher.ts @K-Ho
......
...@@ -30,8 +30,5 @@ M-core-utils: ...@@ -30,8 +30,5 @@ M-core-utils:
M-dtl: M-dtl:
- any: ['packages/data-transport-layer/**/*'] - any: ['packages/data-transport-layer/**/*']
M-hardhat-ovm:
- any: ['packages/hardhat-ovm/**/*']
M-ops: M-ops:
- any: ['ops/**/*'] - any: ['ops/**/*']
...@@ -8,9 +8,7 @@ coverage.json ...@@ -8,9 +8,7 @@ coverage.json
dist dist
artifacts artifacts
artifacts-ovm
cache cache
cache-ovm
l2geth/build/bin l2geth/build/bin
packages/contracts/deployments/custom packages/contracts/deployments/custom
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
"eslint.workingDirectories": [ "eslint.workingDirectories": [
{"directory": "packages/core-utils", "changeProcessCWD": true }, {"directory": "packages/core-utils", "changeProcessCWD": true },
{"directory": "packages/common-ts", "changeProcessCWD": true }, {"directory": "packages/common-ts", "changeProcessCWD": true },
{"directory": "packages/hardhat-ovm", "changeProcessCWD": true },
{"directory": "packages/contracts", "changeProcessCWD": true }, {"directory": "packages/contracts", "changeProcessCWD": true },
{"directory": "packages/data-transport-layer", "changeProcessCWD": true }, {"directory": "packages/data-transport-layer", "changeProcessCWD": true },
{"directory": "packages/batch-submitter", "changeProcessCWD": true }, {"directory": "packages/batch-submitter", "changeProcessCWD": true },
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
These packages only require 1 reviewer (all other packages require 2 reviewers, unless the changes do not affect production or test code). These packages only require 1 reviewer (all other packages require 2 reviewers, unless the changes do not affect production or test code).
- packages/core-utils - packages/core-utils
- packages/hardhat-ovm
- packages/common-ts - packages/common-ts
- integration-tests - integration-tests
......
...@@ -27,7 +27,6 @@ Extensive documentation is available [here](http://community.optimism.io/docs/). ...@@ -27,7 +27,6 @@ Extensive documentation is available [here](http://community.optimism.io/docs/).
* [`contracts`](./packages/contracts): Solidity smart contracts implementing the OVM * [`contracts`](./packages/contracts): Solidity smart contracts implementing the OVM
* [`core-utils`](./packages/core-utils): Low-level utilities and encoding packages * [`core-utils`](./packages/core-utils): Low-level utilities and encoding packages
* [`common-ts`](./packages/common-ts): Common tools for TypeScript code that runs in Node * [`common-ts`](./packages/common-ts): Common tools for TypeScript code that runs in Node
* [`hardhat-ovm`](./packages/hardhat-ovm): Hardhat plugin which enables the [OVM Compiler](https://github.com/ethereum-optimism/solidity)
* [`data-transport-layer`](./packages/data-transport-layer): Event indexer, allowing the `l2geth` node to access L1 data * [`data-transport-layer`](./packages/data-transport-layer): Event indexer, allowing the `l2geth` node to access L1 data
* [`batch-submitter`](./packages/batch-submitter): Daemon for submitting L2 transaction and state root batches to L1 * [`batch-submitter`](./packages/batch-submitter): Daemon for submitting L2 transaction and state root batches to L1
* [`message-relayer`](./packages/message-relayer): Service for relaying L2 messages to L1 * [`message-relayer`](./packages/message-relayer): Service for relaying L2 messages to L1
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
"test:integration": "hardhat --network optimism test", "test:integration": "hardhat --network optimism test",
"test:integration:live": "IS_LIVE_NETWORK=true hardhat --network optimism test", "test:integration:live": "IS_LIVE_NETWORK=true hardhat --network optimism test",
"test:sync": "hardhat --network optimism test sync-tests/*.spec.ts --no-compile", "test:sync": "hardhat --network optimism test sync-tests/*.spec.ts --no-compile",
"clean": "rimraf cache artifacts artifacts-ovm cache-ovm" "clean": "rimraf cache artifacts"
}, },
"devDependencies": { "devDependencies": {
"@eth-optimism/contracts": "^0.4.14", "@eth-optimism/contracts": "^0.4.14",
......
...@@ -21,7 +21,6 @@ COPY --from=builder /optimism/packages/contracts/package.json ./packages/contrac ...@@ -21,7 +21,6 @@ COPY --from=builder /optimism/packages/contracts/package.json ./packages/contrac
COPY --from=builder /optimism/packages/contracts/deployments ./packages/contracts/deployments COPY --from=builder /optimism/packages/contracts/deployments ./packages/contracts/deployments
COPY --from=builder /optimism/packages/contracts/dist ./packages/contracts/dist COPY --from=builder /optimism/packages/contracts/dist ./packages/contracts/dist
COPY --from=builder /optimism/packages/contracts/artifacts ./packages/contracts/artifacts COPY --from=builder /optimism/packages/contracts/artifacts ./packages/contracts/artifacts
COPY --from=builder /optimism/packages/contracts/artifacts-ovm ./packages/contracts/artifacts-ovm
# copy the service # copy the service
WORKDIR /opt/optimism/packages/batch-submitter WORKDIR /opt/optimism/packages/batch-submitter
......
...@@ -22,7 +22,6 @@ COPY --from=builder /optimism/packages/contracts/package.json ./packages/contrac ...@@ -22,7 +22,6 @@ COPY --from=builder /optimism/packages/contracts/package.json ./packages/contrac
COPY --from=builder /optimism/packages/contracts/deployments ./packages/contracts/deployments COPY --from=builder /optimism/packages/contracts/deployments ./packages/contracts/deployments
COPY --from=builder /optimism/packages/contracts/dist ./packages/contracts/dist COPY --from=builder /optimism/packages/contracts/dist ./packages/contracts/dist
COPY --from=builder /optimism/packages/contracts/artifacts ./packages/contracts/artifacts COPY --from=builder /optimism/packages/contracts/artifacts ./packages/contracts/artifacts
COPY --from=builder /optimism/packages/contracts/artifacts-ovm ./packages/contracts/artifacts-ovm
# copy the service # copy the service
WORKDIR /opt/optimism/packages/data-transport-layer WORKDIR /opt/optimism/packages/data-transport-layer
......
...@@ -14,16 +14,12 @@ COPY --from=builder /optimism/node_modules ./node_modules ...@@ -14,16 +14,12 @@ COPY --from=builder /optimism/node_modules ./node_modules
COPY --from=builder /optimism/packages/core-utils/package.json ./packages/core-utils/package.json COPY --from=builder /optimism/packages/core-utils/package.json ./packages/core-utils/package.json
COPY --from=builder /optimism/packages/core-utils/dist ./packages/core-utils/dist COPY --from=builder /optimism/packages/core-utils/dist ./packages/core-utils/dist
COPY --from=builder /optimism/packages/hardhat-ovm/package.json ./packages/hardhat-ovm/package.json
COPY --from=builder /optimism/packages/hardhat-ovm/dist ./packages/hardhat-ovm/dist
# get the needed built artifacts # get the needed built artifacts
WORKDIR /opt/optimism/packages/contracts WORKDIR /opt/optimism/packages/contracts
COPY --from=builder /optimism/packages/contracts/dist ./dist COPY --from=builder /optimism/packages/contracts/dist ./dist
COPY --from=builder /optimism/packages/contracts/*.json ./ COPY --from=builder /optimism/packages/contracts/*.json ./
COPY --from=builder /optimism/packages/contracts/node_modules ./node_modules COPY --from=builder /optimism/packages/contracts/node_modules ./node_modules
COPY --from=builder /optimism/packages/contracts/artifacts ./artifacts COPY --from=builder /optimism/packages/contracts/artifacts ./artifacts
COPY --from=builder /optimism/packages/contracts/artifacts-ovm ./artifacts-ovm
# get non-build artifacts from the host # get non-build artifacts from the host
COPY packages/contracts/bin ./bin COPY packages/contracts/bin ./bin
......
...@@ -17,9 +17,6 @@ COPY --from=builder /optimism/packages/core-utils/dist ./packages/core-utils/dis ...@@ -17,9 +17,6 @@ COPY --from=builder /optimism/packages/core-utils/dist ./packages/core-utils/dis
COPY --from=builder /optimism/packages/message-relayer/package.json ./packages/message-relayer/package.json COPY --from=builder /optimism/packages/message-relayer/package.json ./packages/message-relayer/package.json
COPY --from=builder /optimism/packages/message-relayer/dist ./packages/message-relayer/dist COPY --from=builder /optimism/packages/message-relayer/dist ./packages/message-relayer/dist
COPY --from=builder /optimism/packages/hardhat-ovm/package.json ./packages/hardhat-ovm/package.json
COPY --from=builder /optimism/packages/hardhat-ovm/dist ./packages/hardhat-ovm/dist
COPY --from=builder /optimism/packages/contracts ./packages/contracts COPY --from=builder /optimism/packages/contracts ./packages/contracts
# get the needed built artifacts # get the needed built artifacts
......
...@@ -22,7 +22,6 @@ COPY --from=builder /optimism/packages/contracts/package.json ./packages/contrac ...@@ -22,7 +22,6 @@ COPY --from=builder /optimism/packages/contracts/package.json ./packages/contrac
COPY --from=builder /optimism/packages/contracts/deployments ./packages/contracts/deployments COPY --from=builder /optimism/packages/contracts/deployments ./packages/contracts/deployments
COPY --from=builder /optimism/packages/contracts/dist ./packages/contracts/dist COPY --from=builder /optimism/packages/contracts/dist ./packages/contracts/dist
COPY --from=builder /optimism/packages/contracts/artifacts ./packages/contracts/artifacts COPY --from=builder /optimism/packages/contracts/artifacts ./packages/contracts/artifacts
COPY --from=builder /optimism/packages/contracts/artifacts-ovm ./packages/contracts/artifacts-ovm
# copy the service # copy the service
WORKDIR /opt/optimism/packages/message-relayer WORKDIR /opt/optimism/packages/message-relayer
......
...@@ -26,7 +26,6 @@ WORKDIR /optimism ...@@ -26,7 +26,6 @@ WORKDIR /optimism
COPY *.json yarn.lock ./ COPY *.json yarn.lock ./
COPY packages/core-utils/package.json ./packages/core-utils/package.json COPY packages/core-utils/package.json ./packages/core-utils/package.json
COPY packages/common-ts/package.json ./packages/common-ts/package.json COPY packages/common-ts/package.json ./packages/common-ts/package.json
COPY packages/hardhat-ovm/package.json ./packages/hardhat-ovm/package.json
COPY packages/contracts/package.json ./packages/contracts/package.json COPY packages/contracts/package.json ./packages/contracts/package.json
COPY packages/data-transport-layer/package.json ./packages/data-transport-layer/package.json COPY packages/data-transport-layer/package.json ./packages/data-transport-layer/package.json
COPY packages/batch-submitter/package.json ./packages/batch-submitter/package.json COPY packages/batch-submitter/package.json ./packages/batch-submitter/package.json
......
...@@ -13,7 +13,6 @@ import '@nomiclabs/hardhat-waffle' ...@@ -13,7 +13,6 @@ import '@nomiclabs/hardhat-waffle'
import '@nomiclabs/hardhat-etherscan' import '@nomiclabs/hardhat-etherscan'
import 'hardhat-deploy' import 'hardhat-deploy'
import '@typechain/hardhat' import '@typechain/hardhat'
import '@eth-optimism/hardhat-ovm'
import './tasks/deploy' import './tasks/deploy'
import './tasks/l2-gasprice' import './tasks/l2-gasprice'
import './tasks/set-owner' import './tasks/set-owner'
...@@ -39,10 +38,8 @@ const config: HardhatUserConfig = { ...@@ -39,10 +38,8 @@ const config: HardhatUserConfig = {
tags: ['local'], tags: ['local'],
hardfork: 'istanbul', hardfork: 'istanbul',
}, },
// Add this network to your config!
optimism: { optimism: {
url: 'http://127.0.0.1:8545', url: 'http://127.0.0.1:8545',
ovm: true,
saveDeployments: false, saveDeployments: false,
}, },
'optimism-kovan': { 'optimism-kovan': {
...@@ -77,9 +74,6 @@ const config: HardhatUserConfig = { ...@@ -77,9 +74,6 @@ const config: HardhatUserConfig = {
}, },
}, },
}, },
ovm: {
solcVersion: '0.7.6+commit.3b061308',
},
typechain: { typechain: {
outDir: 'dist/types', outDir: 'dist/types',
target: 'ethers-v5', target: 'ethers-v5',
......
...@@ -5,9 +5,7 @@ ...@@ -5,9 +5,7 @@
"files": [ "files": [
"dist/**/*.js", "dist/**/*.js",
"dist/types/*.ts", "dist/types/*.ts",
"dist/types-ovm/*.ts",
"artifacts/contracts/**/*.json", "artifacts/contracts/**/*.json",
"artifacts-ovm/contracts/**/*.json",
"deployments/**/*.json", "deployments/**/*.json",
"OVM", "OVM",
"iOVM", "iOVM",
...@@ -24,10 +22,8 @@ ...@@ -24,10 +22,8 @@
"build:mainnet": "yarn run build:contracts && yarn run build:typescript && yarn run build:copy && CHAIN_ID=10 yarn run build:dump && yarn run build:typechain", "build:mainnet": "yarn run build:contracts && yarn run build:typescript && yarn run build:copy && CHAIN_ID=10 yarn run build:dump && yarn run build:typechain",
"build:typescript": "tsc -p ./tsconfig.build.json", "build:typescript": "tsc -p ./tsconfig.build.json",
"build:contracts": "hardhat compile --show-stack-traces", "build:contracts": "hardhat compile --show-stack-traces",
"build:contracts:ovm": "hardhat compile --network optimism",
"build:dump": "ts-node \"bin/take-dump.ts\"", "build:dump": "ts-node \"bin/take-dump.ts\"",
"build:typechain": "hardhat typechain", "build:typechain": "hardhat typechain",
"build:typechain:ovm": "hardhat --network optimism typechain",
"test": "yarn run test:contracts", "test": "yarn run test:contracts",
"test:contracts": "hardhat test --show-stack-traces", "test:contracts": "hardhat test --show-stack-traces",
"test:gas": "hardhat test \"test/contracts/OVM/execution/OVM_StateManager.gas-spec.ts\" --no-compile --show-stack-traces", "test:gas": "hardhat test \"test/contracts/OVM/execution/OVM_StateManager.gas-spec.ts\" --no-compile --show-stack-traces",
...@@ -38,7 +34,7 @@ ...@@ -38,7 +34,7 @@
"lint:check": "eslint .", "lint:check": "eslint .",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:contracts": "yarn solhint -f table contracts/optimistic-ethereum/**/*.sol", "lint:contracts": "yarn solhint -f table contracts/optimistic-ethereum/**/*.sol",
"clean": "rm -rf ./dist ./artifacts ./artifacts-ovm ./cache ./cache-ovm ./tsconfig.build.tsbuildinfo", "clean": "rm -rf ./dist ./artifacts ./cache ./tsconfig.build.tsbuildinfo",
"deploy": "ts-node \"./bin/deploy.ts\" && yarn generate:markdown", "deploy": "ts-node \"./bin/deploy.ts\" && yarn generate:markdown",
"serve": "./bin/serve_dump.sh", "serve": "./bin/serve_dump.sh",
"prepublishOnly": "yarn copyfiles -u 2 \"contracts/optimistic-ethereum/**/*\" ./", "prepublishOnly": "yarn copyfiles -u 2 \"contracts/optimistic-ethereum/**/*\" ./",
...@@ -60,7 +56,6 @@ ...@@ -60,7 +56,6 @@
}, },
"devDependencies": { "devDependencies": {
"@codechecks/client": "^0.1.11", "@codechecks/client": "^0.1.11",
"@eth-optimism/hardhat-ovm": "^0.2.4",
"@eth-optimism/smock": "^1.1.10", "@eth-optimism/smock": "^1.1.10",
"@ethersproject/transactions": "^5.4.0", "@ethersproject/transactions": "^5.4.0",
"@nomiclabs/hardhat-ethers": "^2.0.2", "@nomiclabs/hardhat-ethers": "^2.0.2",
......
...@@ -3,6 +3,5 @@ ...@@ -3,6 +3,5 @@
set -e set -e
yarn build:contracts yarn build:contracts
yarn build:contracts:ovm
yarn generate:artifacts yarn generate:artifacts
yarn build:typescript yarn build:typescript
...@@ -15,9 +15,6 @@ const fs = require('fs') ...@@ -15,9 +15,6 @@ const fs = require('fs')
const evmArtifactPaths = getContractJsonFiles( const evmArtifactPaths = getContractJsonFiles(
path.resolve(__dirname, `../artifacts/contracts`) path.resolve(__dirname, `../artifacts/contracts`)
) )
const ovmArtifactPaths = getContractJsonFiles(
path.resolve(__dirname, `../artifacts-ovm/contracts`)
)
const content = ` const content = `
/* eslint-disable @typescript-eslint/no-var-requires, no-empty */ /* eslint-disable @typescript-eslint/no-var-requires, no-empty */
...@@ -26,18 +23,6 @@ const fs = require('fs') ...@@ -26,18 +23,6 @@ const fs = require('fs')
DO NOT EDIT. DO NOT EDIT.
*/ */
${ovmArtifactPaths
.map((artifactPath) => {
const artifact = require(artifactPath)
const relPath = path.relative(__dirname, artifactPath)
return `
let ovm__${artifact.contractName}
try {
ovm__${artifact.contractName} = require('${relPath}')
} catch {}
`
})
.join('\n')}
${evmArtifactPaths ${evmArtifactPaths
.map((artifactPath) => { .map((artifactPath) => {
const artifact = require(artifactPath) const artifact = require(artifactPath)
...@@ -51,26 +36,15 @@ const fs = require('fs') ...@@ -51,26 +36,15 @@ const fs = require('fs')
}) })
.join('\n')} .join('\n')}
export const getContractArtifact = (name: string, ovm: boolean): any => { export const getContractArtifact = (name: string): any => {
if (ovm) { return {
return { ${evmArtifactPaths
${ovmArtifactPaths .map((artifactPath) => {
.map((artifactPath) => { const artifact = require(artifactPath)
const artifact = require(artifactPath) return `${artifact.contractName}: ${artifact.contractName}`
return `${artifact.contractName}: ovm__${artifact.contractName}` })
}) .join(',\n')}
.join(',\n')} }[name]
}[name]
} else {
return {
${evmArtifactPaths
.map((artifactPath) => {
const artifact = require(artifactPath)
return `${artifact.contractName}: ${artifact.contractName}`
})
.join(',\n')}
}[name]
}
} }
` `
......
import { Signer, Contract, providers, ethers } from 'ethers' import { Signer, Contract } from 'ethers'
import { Provider } from '@ethersproject/abstract-provider' import { Provider } from '@ethersproject/abstract-provider'
import { getL1ContractData, getL2ContractData } from './contract-data' import { getL1ContractData, getL2ContractData } from './contract-data'
......
...@@ -112,15 +112,15 @@ export const getL1ContractData = (network: Network) => { ...@@ -112,15 +112,15 @@ export const getL1ContractData = (network: Network) => {
} }
} }
const OVM_ETH = require('../artifacts-ovm/contracts/optimistic-ethereum/OVM/predeploys/OVM_ETH.sol/OVM_ETH.json') const OVM_ETH = require('../artifacts/contracts/optimistic-ethereum/OVM/predeploys/OVM_ETH.sol/OVM_ETH.json')
const OVM_L2CrossDomainMessenger = require('../artifacts-ovm/contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L2CrossDomainMessenger.sol/OVM_L2CrossDomainMessenger.json') const OVM_L2CrossDomainMessenger = require('../artifacts/contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L2CrossDomainMessenger.sol/OVM_L2CrossDomainMessenger.json')
const OVM_L2ToL1MessagePasser = require('../artifacts-ovm/contracts/optimistic-ethereum/OVM/predeploys/OVM_L2ToL1MessagePasser.sol/OVM_L2ToL1MessagePasser.json') const OVM_L2ToL1MessagePasser = require('../artifacts/contracts/optimistic-ethereum/OVM/predeploys/OVM_L2ToL1MessagePasser.sol/OVM_L2ToL1MessagePasser.json')
const OVM_L1MessageSender = require('../artifacts/contracts/optimistic-ethereum/OVM/predeploys/OVM_L1MessageSender.sol/OVM_L1MessageSender.json') const OVM_L1MessageSender = require('../artifacts/contracts/optimistic-ethereum/OVM/predeploys/OVM_L1MessageSender.sol/OVM_L1MessageSender.json')
const OVM_DeployerWhitelist = require('../artifacts-ovm/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol/OVM_DeployerWhitelist.json') const OVM_DeployerWhitelist = require('../artifacts/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol/OVM_DeployerWhitelist.json')
const OVM_ECDSAContractAccount = require('../artifacts-ovm/contracts/optimistic-ethereum/OVM/predeploys/OVM_ECDSAContractAccount.sol/OVM_ECDSAContractAccount.json') const OVM_ECDSAContractAccount = require('../artifacts/contracts/optimistic-ethereum/OVM/predeploys/OVM_ECDSAContractAccount.sol/OVM_ECDSAContractAccount.json')
const OVM_SequencerEntrypoint = require('../artifacts-ovm/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol/OVM_SequencerEntrypoint.json') const OVM_SequencerEntrypoint = require('../artifacts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol/OVM_SequencerEntrypoint.json')
const ERC1820Registry = require('../artifacts-ovm/contracts/optimistic-ethereum/OVM/predeploys/ERC1820Registry.sol/ERC1820Registry.json') const ERC1820Registry = require('../artifacts/contracts/optimistic-ethereum/OVM/predeploys/ERC1820Registry.sol/ERC1820Registry.json')
const Lib_AddressManager = require('../artifacts-ovm/contracts/optimistic-ethereum/libraries/resolver/Lib_AddressManager.sol/Lib_AddressManager.json') const Lib_AddressManager = require('../artifacts/contracts/optimistic-ethereum/libraries/resolver/Lib_AddressManager.sol/Lib_AddressManager.json')
export const getL2ContractData = () => { export const getL2ContractData = () => {
return { return {
......
import { import { ethers } from 'ethers'
ethers,
ContractFactory,
Signer,
providers,
Contract,
constants,
} from 'ethers'
import { Interface } from 'ethers/lib/utils'
export const getContractDefinition = (name: string, ovm?: boolean): any => { export const getContractDefinition = (name: string): any => {
// We import this using `require` because hardhat tries to build this file when compiling // We import this using `require` because hardhat tries to build this file when compiling
// the contracts, but we need the contracts to be compiled before the contract-artifacts.ts // the contracts, but we need the contracts to be compiled before the contract-artifacts.ts
// file can be generated. // file can be generated.
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const { getContractArtifact } = require('./contract-artifacts') const { getContractArtifact } = require('./contract-artifacts')
const artifact = getContractArtifact(name, ovm) const artifact = getContractArtifact(name)
if (artifact === undefined) { if (artifact === undefined) {
throw new Error(`Unable to find artifact for contract: ${name}`) throw new Error(`Unable to find artifact for contract: ${name}`)
} }
return artifact return artifact
} }
export const getContractInterface = ( export const getContractInterface = (name: string): ethers.utils.Interface => {
name: string, const definition = getContractDefinition(name)
ovm?: boolean
): Interface => {
const definition = getContractDefinition(name, ovm)
return new ethers.utils.Interface(definition.abi) return new ethers.utils.Interface(definition.abi)
} }
export const getContractFactory = ( export const getContractFactory = (
name: string, name: string,
signer?: Signer, signer?: ethers.Signer
ovm?: boolean ): ethers.ContractFactory => {
): ContractFactory => { const definition = getContractDefinition(name)
const definition = getContractDefinition(name, ovm) const contractInterface = getContractInterface(name)
const contractInterface = getContractInterface(name, ovm) return new ethers.ContractFactory(
return new ContractFactory(contractInterface, definition.bytecode, signer) contractInterface,
definition.bytecode,
signer
)
} }
export const loadContract = ( export const loadContract = (
name: string, name: string,
address: string, address: string,
provider: providers.JsonRpcProvider provider: ethers.providers.JsonRpcProvider
): Contract => { ): ethers.Contract => {
return new Contract(address, getContractInterface(name) as any, provider) return new ethers.Contract(
address,
getContractInterface(name) as any,
provider
)
} }
export const loadContractFromManager = async (args: { export const loadContractFromManager = async (args: {
name: string name: string
proxy?: string proxy?: string
Lib_AddressManager: Contract Lib_AddressManager: ethers.Contract
provider: providers.JsonRpcProvider provider: ethers.providers.JsonRpcProvider
}): Promise<Contract> => { }): Promise<ethers.Contract> => {
const { name, proxy, Lib_AddressManager, provider } = args const { name, proxy, Lib_AddressManager, provider } = args
const address = await Lib_AddressManager.getAddress(proxy ? proxy : name) const address = await Lib_AddressManager.getAddress(proxy ? proxy : name)
if (address === ethers.constants.AddressZero) {
if (address === constants.AddressZero) {
throw new Error( throw new Error(
`Lib_AddressManager does not have a record for a contract named: ${name}` `Lib_AddressManager does not have a record for a contract named: ${name}`
) )
} }
return loadContract(name, address, provider) return loadContract(name, address, provider)
} }
...@@ -27,10 +27,7 @@ task('set-l2-gasprice') ...@@ -27,10 +27,7 @@ task('set-l2-gasprice')
provider provider
) )
const GasPriceOracleArtifact = getContractDefinition( const GasPriceOracleArtifact = getContractDefinition('OVM_GasPriceOracle')
'OVM_GasPriceOracle',
true
)
const GasPriceOracle = new ethers.Contract( const GasPriceOracle = new ethers.Contract(
predeploys.OVM_GasPriceOracle, predeploys.OVM_GasPriceOracle,
......
/* Internal Imports */
import { remove0x, toHexString } from '@eth-optimism/core-utils'
import { ethers } from 'ethers'
import { predeploys } from '../../../../../src'
import {
ExecutionManagerTestRunner,
TestDefinition,
OVM_TX_GAS_LIMIT,
NON_NULL_BYTES32,
REVERT_FLAGS,
VERIFIED_EMPTY_CONTRACT_HASH,
} from '../../../../helpers'
const ovmEthBalanceOfStorageLayoutKey =
'0000000000000000000000000000000000000000000000000000000000000000'
// TODO: use fancy chugsplash storage getter once possible
const getOvmEthBalanceSlot = (addressOrPlaceholder: string): string => {
let address: string
if (addressOrPlaceholder.startsWith('$DUMMY_OVM_ADDRESS_')) {
address = ExecutionManagerTestRunner.getDummyAddress(addressOrPlaceholder)
} else {
address = addressOrPlaceholder
}
const balanceOfSlotPreimage =
ethers.utils.hexZeroPad(address, 32) + ovmEthBalanceOfStorageLayoutKey
const balanceOfSlot = ethers.utils.keccak256(balanceOfSlotPreimage)
return balanceOfSlot
}
const INITIAL_BALANCE = 1234
const CALL_VALUE = 69
const test_nativeETH: TestDefinition = {
name: 'Basic tests for ovmCALL',
preState: {
ExecutionManager: {
ovmStateManager: '$OVM_STATE_MANAGER',
ovmSafetyChecker: '$OVM_SAFETY_CHECKER',
messageRecord: {
nuisanceGasLeft: OVM_TX_GAS_LIMIT,
},
},
StateManager: {
owner: '$OVM_EXECUTION_MANAGER',
accounts: {
$DUMMY_OVM_ADDRESS_1: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
$DUMMY_OVM_ADDRESS_2: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
$DUMMY_OVM_ADDRESS_3: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
},
contractStorage: {
[predeploys.OVM_ETH]: {
[getOvmEthBalanceSlot('$DUMMY_OVM_ADDRESS_1')]: {
getStorageXOR: true,
value: toHexString(INITIAL_BALANCE),
},
[getOvmEthBalanceSlot('$DUMMY_OVM_ADDRESS_2')]: {
getStorageXOR: true,
value: '0x00',
},
[getOvmEthBalanceSlot('$DUMMY_OVM_ADDRESS_3')]: {
getStorageXOR: true,
value: '0x00',
},
},
},
verifiedContractStorage: {
[predeploys.OVM_ETH]: {
[getOvmEthBalanceSlot('$DUMMY_OVM_ADDRESS_1')]: true,
[getOvmEthBalanceSlot('$DUMMY_OVM_ADDRESS_2')]: true,
[getOvmEthBalanceSlot('$DUMMY_OVM_ADDRESS_3')]: true,
},
},
},
},
parameters: [
{
name: 'ovmCALL(ADDRESS_1) => ovmBALANCE(ADDRESS_1)',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_1',
},
expectedReturnStatus: true,
expectedReturnValue: INITIAL_BALANCE,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCALL(ADDRESS_1) => ovmCALL(EMPTY_ACCOUNT, value)',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_3',
value: CALL_VALUE,
calldata: '0x',
},
expectedReturnStatus: true,
},
// Check balances are still applied:
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_1',
},
expectedReturnStatus: true,
expectedReturnValue: INITIAL_BALANCE - CALL_VALUE,
},
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_3',
},
expectedReturnStatus: true,
expectedReturnValue: CALL_VALUE,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2, value) [successful call]',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
// expected initial balances:
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_1',
},
expectedReturnStatus: true,
expectedReturnValue: INITIAL_BALANCE,
},
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_2',
},
expectedReturnStatus: true,
expectedReturnValue: 0,
},
// do the call with some value
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_2',
value: CALL_VALUE,
subSteps: [
// check that the ovmCALLVALUE is updated
{
functionName: 'ovmCALLVALUE',
expectedReturnValue: CALL_VALUE,
},
// check that the balances have been updated
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_1',
},
expectedReturnStatus: true,
expectedReturnValue: INITIAL_BALANCE - CALL_VALUE,
},
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_2',
},
expectedReturnStatus: true,
expectedReturnValue: CALL_VALUE,
},
],
},
expectedReturnStatus: true,
},
// check that the ovmCALLVALUE is reset back to 0
{
functionName: 'ovmCALLVALUE',
expectedReturnValue: 0,
},
// check that the balances have persisted
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_1',
},
expectedReturnStatus: true,
expectedReturnValue: INITIAL_BALANCE - CALL_VALUE,
},
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_2',
},
expectedReturnStatus: true,
expectedReturnValue: CALL_VALUE,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2, value) [reverting call]',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
// expected initial balances:
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_1',
},
expectedReturnStatus: true,
expectedReturnValue: INITIAL_BALANCE,
},
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_2',
},
expectedReturnStatus: true,
expectedReturnValue: 0,
},
// do the call with some value
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_2',
value: CALL_VALUE,
subSteps: [
// check that the ovmCALLVALUE is updated
{
functionName: 'ovmCALLVALUE',
expectedReturnValue: CALL_VALUE,
},
// check that the balances have been updated
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_1',
},
expectedReturnStatus: true,
expectedReturnValue: INITIAL_BALANCE - CALL_VALUE,
},
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_2',
},
expectedReturnStatus: true,
expectedReturnValue: CALL_VALUE,
},
// now revert everything
{
functionName: 'ovmREVERT',
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INTENTIONAL_REVERT,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: true,
expectedReturnValue: {
ovmSuccess: false,
returnData: '0x',
},
},
// check that the ovmCALLVALUE is reset back to 0
{
functionName: 'ovmCALLVALUE',
expectedReturnValue: 0,
},
// check that the balances have NOT persisted
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_1',
},
expectedReturnStatus: true,
expectedReturnValue: INITIAL_BALANCE,
},
{
functionName: 'ovmBALANCE',
functionParams: {
address: '$DUMMY_OVM_ADDRESS_2',
},
expectedReturnStatus: true,
expectedReturnValue: 0,
},
],
},
expectedReturnStatus: true,
},
],
},
],
}
const runner = new ExecutionManagerTestRunner()
runner.run(test_nativeETH)
/* Internal Imports */
import {
ExecutionManagerTestRunner,
TestDefinition,
OVM_TX_GAS_LIMIT,
NON_NULL_BYTES32,
REVERT_FLAGS,
VERIFIED_EMPTY_CONTRACT_HASH,
} from '../../../../helpers'
const DUMMY_REVERT_DATA =
'0xdeadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420'
const DEAD_ADDRESS = '0xdeaddeaddeaddeaddeaddeaddeaddeaddead1234'
const test_ovmCALL: TestDefinition = {
name: 'Basic tests for ovmCALL',
preState: {
ExecutionManager: {
ovmStateManager: '$OVM_STATE_MANAGER',
ovmSafetyChecker: '$OVM_SAFETY_CHECKER',
messageRecord: {
nuisanceGasLeft: OVM_TX_GAS_LIMIT,
},
},
StateManager: {
owner: '$OVM_EXECUTION_MANAGER',
accounts: {
$DUMMY_OVM_ADDRESS_1: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
$DUMMY_OVM_ADDRESS_2: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
$DUMMY_OVM_ADDRESS_3: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
},
verifiedContractStorage: {
$DUMMY_OVM_ADDRESS_1: {
[NON_NULL_BYTES32]: true,
},
},
},
},
parameters: [
{
name: 'ovmCALL(ADDRESS_1) => ovmADDRESS',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmADDRESS',
expectedReturnValue: '$DUMMY_OVM_ADDRESS_1',
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCALL(ADDRESS_1) => ovmSSTORE',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmSSTORE',
functionParams: {
key: NON_NULL_BYTES32,
value: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCALL(ADDRESS_1) => ovmSSTORE + ovmSLOAD, ovmCALL(ADDRESS_1) => ovmSLOAD',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmSSTORE',
functionParams: {
key: NON_NULL_BYTES32,
value: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
},
{
functionName: 'ovmSLOAD',
functionParams: {
key: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
expectedReturnValue: NON_NULL_BYTES32,
},
],
},
expectedReturnStatus: true,
},
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmSLOAD',
functionParams: {
key: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
expectedReturnValue: NON_NULL_BYTES32,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmADDRESS + ovmCALLER',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_2',
subSteps: [
{
functionName: 'ovmADDRESS',
expectedReturnValue: '$DUMMY_OVM_ADDRESS_2',
},
{
functionName: 'ovmCALLER',
expectedReturnValue: '$DUMMY_OVM_ADDRESS_1',
},
],
},
expectedReturnStatus: true,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_3)',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_3',
calldata: '0x',
},
expectedReturnStatus: true,
},
],
},
expectedReturnStatus: true,
expectedReturnValue: '0x',
},
],
},
{
name: 'ovmCALL(ADDRESS_1) => INTENTIONAL_REVERT',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'evmREVERT',
returnData: {
flag: REVERT_FLAGS.INTENTIONAL_REVERT,
data: DUMMY_REVERT_DATA,
},
},
],
},
expectedReturnStatus: false,
expectedReturnValue: DUMMY_REVERT_DATA,
},
],
},
{
name: 'ovmCALL(ADDRESS_1) => EXCEEDS_NUISANCE_GAS',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'evmREVERT',
returnData: {
flag: REVERT_FLAGS.EXCEEDS_NUISANCE_GAS,
},
},
],
},
expectedReturnStatus: false,
expectedReturnValue: '0x',
},
],
},
{
name: 'ovmCALL(0xdeaddeaddead...) returns (true, 0x)',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: DEAD_ADDRESS,
subSteps: [],
},
expectedReturnStatus: true,
expectedReturnValue: {
ovmSuccess: true,
returnData: '0x',
},
},
],
},
],
}
const runner = new ExecutionManagerTestRunner()
runner.run(test_ovmCALL)
/* Internal Imports */
import { constants, ethers } from 'ethers'
import {
ExecutionManagerTestRunner,
TestDefinition,
OVM_TX_GAS_LIMIT,
NON_NULL_BYTES32,
REVERT_FLAGS,
DUMMY_BYTECODE,
UNSAFE_BYTECODE,
VERIFIED_EMPTY_CONTRACT_HASH,
DUMMY_BYTECODE_BYTELEN,
DUMMY_BYTECODE_HASH,
getStorageXOR,
encodeSolidityError,
} from '../../../../helpers'
import { predeploys } from '../../../../../src'
const CREATED_CONTRACT_1 = '0x2bda4a99d5be88609d23b1e4ab5d1d34fb1c2feb'
const CREATED_CONTRACT_2 = '0x2bda4a99d5be88609d23b1e4ab5d1d34fb1c2feb'
const CREATED_CONTRACT_BY_2_1 = '0xe0d8be8101f36ebe6b01abacec884422c39a1f62'
const CREATED_CONTRACT_BY_2_2 = '0x15ac629e1a3866b17179ee4ae86de5cbda744335'
const NESTED_CREATED_CONTRACT = '0xcb964b3f4162a0d4f5c997b40e19da5a546bc36f'
const DUMMY_REVERT_DATA =
'0xdeadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420'
const NON_WHITELISTED_DEPLOYER = '0x1234123412341234123412341234123412341234'
const NON_WHITELISTED_DEPLOYER_KEY = ethers.utils.keccak256(
'0x' +
'0000000000000000000000001234123412341234123412341234123412341234' +
'0000000000000000000000000000000000000000000000000000000000000001'
)
const CREATED_BY_NON_WHITELISTED_DEPLOYER =
'0x794e4aa3be128b0fc01ba12543b70bf9d77072fc'
const WHITELISTED_DEPLOYER = '0x3456345634563456345634563456345634563456'
const WHITELISTED_DEPLOYER_KEY = ethers.utils.keccak256(
'0x' +
'0000000000000000000000003456345634563456345634563456345634563456' +
'0000000000000000000000000000000000000000000000000000000000000001'
)
const CREATED_BY_WHITELISTED_DEPLOYER =
'0x9f397a91ccb7cc924d1585f1053bc697d30f343f'
const test_ovmCREATE: TestDefinition = {
name: 'Basic tests for ovmCREATE',
preState: {
ExecutionManager: {
ovmStateManager: '$OVM_STATE_MANAGER',
ovmSafetyChecker: '$OVM_SAFETY_CHECKER',
messageRecord: {
nuisanceGasLeft: OVM_TX_GAS_LIMIT,
},
},
StateManager: {
owner: '$OVM_EXECUTION_MANAGER',
accounts: {
$DUMMY_OVM_ADDRESS_1: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
$DUMMY_OVM_ADDRESS_2: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
[CREATED_CONTRACT_1]: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
[CREATED_CONTRACT_2]: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
[CREATED_CONTRACT_BY_2_1]: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
[CREATED_CONTRACT_BY_2_2]: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
[NESTED_CREATED_CONTRACT]: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
},
contractStorage: {
$DUMMY_OVM_ADDRESS_2: {
[ethers.constants.HashZero]: getStorageXOR(ethers.constants.HashZero),
[NON_NULL_BYTES32]: getStorageXOR(ethers.constants.HashZero),
},
},
verifiedContractStorage: {
$DUMMY_OVM_ADDRESS_1: {
[NON_NULL_BYTES32]: true,
},
$DUMMY_OVM_ADDRESS_2: {
[ethers.constants.HashZero]: true,
[NON_NULL_BYTES32]: true,
},
},
},
},
parameters: [
{
name: 'ovmCREATE, ovmEXTCODESIZE(CREATED)',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
bytecode: DUMMY_BYTECODE,
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_1,
},
{
functionName: 'ovmEXTCODESIZE',
functionParams: {
address: CREATED_CONTRACT_1,
},
expectedReturnStatus: true,
expectedReturnValue: DUMMY_BYTECODE_BYTELEN,
},
],
},
{
name: 'ovmCREATE, ovmEXTCODEHASH(CREATED)',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
bytecode: DUMMY_BYTECODE,
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_1,
},
{
functionName: 'ovmEXTCODEHASH',
functionParams: {
address: CREATED_CONTRACT_1,
},
expectedReturnStatus: true,
expectedReturnValue: DUMMY_BYTECODE_HASH,
},
],
},
{
name: 'ovmCREATE, ovmEXTCODECOPY(CREATED)',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
bytecode: DUMMY_BYTECODE,
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_1,
},
{
functionName: 'ovmEXTCODECOPY',
functionParams: {
address: CREATED_CONTRACT_1,
offset: 0,
length: DUMMY_BYTECODE_BYTELEN,
},
expectedReturnStatus: true,
expectedReturnValue: DUMMY_BYTECODE,
},
],
},
{
name: 'ovmCREATE => ovmREVERT',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmREVERT',
revertData: DUMMY_REVERT_DATA,
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INTENTIONAL_REVERT,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: true,
expectedReturnValue: {
address: constants.AddressZero,
revertData: DUMMY_REVERT_DATA,
},
},
],
},
{
name: 'ovmCREATE => ovmREVERT, ovmEXTCODESIZE(CREATED)',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmREVERT',
revertData: DUMMY_REVERT_DATA,
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INTENTIONAL_REVERT,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: true,
expectedReturnValue: {
address: constants.AddressZero,
revertData: DUMMY_REVERT_DATA,
},
},
{
functionName: 'ovmEXTCODESIZE',
functionParams: {
address: CREATED_CONTRACT_1,
},
expectedReturnStatus: true,
expectedReturnValue: 0,
},
],
},
{
name: 'ovmCREATE => ovmREVERT, ovmEXTCODEHASH(CREATED)',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmREVERT',
revertData: DUMMY_REVERT_DATA,
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INTENTIONAL_REVERT,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: true,
expectedReturnValue: {
address: constants.AddressZero,
revertData: DUMMY_REVERT_DATA,
},
},
{
functionName: 'ovmEXTCODEHASH',
functionParams: {
address: CREATED_CONTRACT_1,
},
expectedReturnStatus: true,
expectedReturnValue: ethers.constants.HashZero,
},
],
},
{
name: 'ovmCREATE => ovmREVERT, ovmEXTCODECOPY(CREATED)',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmREVERT',
revertData: DUMMY_REVERT_DATA,
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INTENTIONAL_REVERT,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: true,
expectedReturnValue: {
address: constants.AddressZero,
revertData: DUMMY_REVERT_DATA,
},
},
{
functionName: 'ovmEXTCODECOPY',
functionParams: {
address: CREATED_CONTRACT_1,
offset: 0,
length: 256,
},
expectedReturnStatus: true,
expectedReturnValue: '0x' + '00'.repeat(256),
},
],
},
{
name: 'ovmCREATE => ovmADDRESS',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmADDRESS',
expectedReturnValue: CREATED_CONTRACT_1,
},
],
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_1,
},
],
},
{
name: 'ovmCREATE => ovmSLOAD',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmSLOAD',
functionParams: {
key: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
expectedReturnValue: ethers.constants.HashZero,
},
],
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_1,
},
],
},
{
name: 'ovmCALL => ovmCREATE => ovmCALLER',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmSLOAD',
functionParams: {
key: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
expectedReturnValue: ethers.constants.HashZero,
},
],
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_2,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCREATE => ovmSSTORE + ovmSLOAD',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmSSTORE',
functionParams: {
key: NON_NULL_BYTES32,
value: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
},
{
functionName: 'ovmSLOAD',
functionParams: {
key: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
expectedReturnValue: NON_NULL_BYTES32,
},
],
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_1,
},
],
},
{
name: 'ovmCREATE => ovmSSTORE, ovmCALL(CREATED) => ovmSLOAD(EXIST) + ovmSLOAD(NONEXIST)',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmSSTORE',
functionParams: {
key: NON_NULL_BYTES32,
value: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
},
],
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_1,
},
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: CREATED_CONTRACT_1,
subSteps: [
{
functionName: 'ovmSLOAD',
functionParams: {
key: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
expectedReturnValue: NON_NULL_BYTES32,
},
{
functionName: 'ovmSLOAD',
functionParams: {
key: ethers.constants.HashZero,
},
expectedReturnStatus: true,
expectedReturnValue: ethers.constants.HashZero,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCREATE => ovmCALL(ADDRESS_1) => ovmSSTORE, ovmCALL(ADDRESS_1) => ovmSLOAD',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmSSTORE',
functionParams: {
key: NON_NULL_BYTES32,
value: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
},
],
},
expectedReturnStatus: true,
},
],
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_1,
},
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmSLOAD',
functionParams: {
key: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
expectedReturnValue: NON_NULL_BYTES32,
},
],
},
expectedReturnStatus: true,
},
],
},
{
// TODO: appears to be failing due to a smoddit issue
skip: true,
name: 'ovmCREATE => (ovmCALL(ADDRESS_2) => ovmSSTORE) + ovmREVERT, ovmCALL(ADDRESS_2) => ovmSLOAD',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_2',
subSteps: [
{
functionName: 'ovmSLOAD',
functionParams: {
key: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
expectedReturnValue: NON_NULL_BYTES32,
},
{
functionName: 'ovmSSTORE',
functionParams: {
key: NON_NULL_BYTES32,
value: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
},
],
},
expectedReturnStatus: true,
},
{
functionName: 'ovmREVERT',
revertData: DUMMY_REVERT_DATA,
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INTENTIONAL_REVERT,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: true,
expectedReturnValue: {
address: constants.AddressZero,
revertData: DUMMY_REVERT_DATA,
},
},
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_2',
subSteps: [
{
functionName: 'ovmSLOAD',
functionParams: {
key: NON_NULL_BYTES32,
},
expectedReturnStatus: true,
expectedReturnValue: NON_NULL_BYTES32,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCREATE => ovmCALL(ADDRESS_NONEXIST)',
expectInvalidStateAccess: true,
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_3',
calldata: '0x',
},
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INVALID_STATE_ACCESS,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INVALID_STATE_ACCESS,
},
},
],
},
{
name: 'ovmCALL => ovmCREATE => ovmCREATE',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_2',
subSteps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmCREATE',
functionParams: {
bytecode: '0x', // this will still succeed with empty bytecode
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_BY_2_2,
},
],
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_CONTRACT_BY_2_1,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCREATE => ovmCREATE => ovmCALL(ADDRESS_NONEXIST)',
expectInvalidStateAccess: true,
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_3',
calldata: '0x',
},
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INVALID_STATE_ACCESS,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INVALID_STATE_ACCESS,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INVALID_STATE_ACCESS,
onlyValidateFlag: true,
},
},
],
},
{
name: 'OZ-AUDIT: ovmCREATE => ((ovmCREATE => ovmADDRESS), ovmREVERT)',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'ovmADDRESS',
expectedReturnValue: NESTED_CREATED_CONTRACT,
},
],
},
expectedReturnStatus: true,
expectedReturnValue: NESTED_CREATED_CONTRACT,
},
{
functionName: 'ovmREVERT',
revertData: DUMMY_REVERT_DATA,
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.INTENTIONAL_REVERT,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: true,
expectedReturnValue: {
address: constants.AddressZero,
revertData: DUMMY_REVERT_DATA,
},
},
],
},
{
name: 'ovmCREATE => OUT_OF_GAS',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [
{
functionName: 'evmINVALID',
},
],
},
expectedReturnStatus: true,
expectedReturnValue: constants.AddressZero,
},
],
},
{
name: 'ovmCREATE(UNSAFE_CODE)',
steps: [
{
functionName: 'ovmCREATE',
functionParams: {
bytecode: UNSAFE_BYTECODE,
},
expectedReturnStatus: true,
expectedReturnValue: {
address: constants.AddressZero,
revertData: encodeSolidityError(
'Constructor attempted to deploy unsafe bytecode.'
),
},
},
],
},
],
subTests: [
{
name: 'Deployer whitelist tests',
preState: {
StateManager: {
accounts: {
[NON_WHITELISTED_DEPLOYER]: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
[WHITELISTED_DEPLOYER]: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
[CREATED_BY_WHITELISTED_DEPLOYER]: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
},
contractStorage: {
[predeploys.OVM_DeployerWhitelist]: {
// initialized? true, allowArbitraryDeployment? false
'0x0000000000000000000000000000000000000000000000000000000000000000':
getStorageXOR(
'0x0000000000000000000000000000000000000000000000000000000000000001'
),
// non-whitelisted deployer is whitelisted? false
[NON_WHITELISTED_DEPLOYER_KEY]: getStorageXOR(
ethers.constants.HashZero
),
// whitelisted deployer is whitelisted? true
[WHITELISTED_DEPLOYER_KEY]: getStorageXOR(
'0x' + '00'.repeat(31) + '01'
),
},
},
verifiedContractStorage: {
[predeploys.OVM_DeployerWhitelist]: {
'0x0000000000000000000000000000000000000000000000000000000000000000': 1,
[NON_WHITELISTED_DEPLOYER_KEY]: 1,
[WHITELISTED_DEPLOYER_KEY]: 1,
},
},
},
},
parameters: [
{
name: 'ovmCREATE by WHITELISTED_DEPLOYER',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT / 2,
target: WHITELISTED_DEPLOYER,
subSteps: [
{
functionName: 'ovmCREATE',
functionParams: {
bytecode: DUMMY_BYTECODE,
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_BY_WHITELISTED_DEPLOYER,
},
],
},
expectedReturnStatus: true,
},
],
},
{
name: 'ovmCREATE by NON_WHITELISTED_DEPLOYER',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT / 2,
target: NON_WHITELISTED_DEPLOYER,
subSteps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [],
},
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.CREATOR_NOT_ALLOWED,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: true,
expectedReturnValue: {
ovmSuccess: false,
returnData: '0x',
},
},
],
},
{
name: 'ovmCREATE2 by NON_WHITELISTED_DEPLOYER',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT / 2,
target: NON_WHITELISTED_DEPLOYER,
subSteps: [
{
functionName: 'ovmCREATE2',
functionParams: {
salt: ethers.constants.HashZero,
bytecode: '0x',
},
expectedReturnStatus: false,
expectedReturnValue: {
flag: REVERT_FLAGS.CREATOR_NOT_ALLOWED,
onlyValidateFlag: true,
},
},
],
},
expectedReturnStatus: true,
expectedReturnValue: {
ovmSuccess: false,
returnData: '0x',
},
},
],
},
],
},
{
name: 'Deployer whitelist tests',
preState: {
StateManager: {
accounts: {
[NON_WHITELISTED_DEPLOYER]: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
[WHITELISTED_DEPLOYER]: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
[CREATED_BY_NON_WHITELISTED_DEPLOYER]: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
},
contractStorage: {
[predeploys.OVM_DeployerWhitelist]: {
// initialized? true, allowArbitraryDeployment? true
'0x0000000000000000000000000000000000000000000000000000000000000000':
getStorageXOR(
'0x0000000000000000000000000000000000000000000000000000000000000101'
),
// non-whitelisted deployer is whitelisted? false
[NON_WHITELISTED_DEPLOYER_KEY]: getStorageXOR(
ethers.constants.HashZero
),
// whitelisted deployer is whitelisted? true
[WHITELISTED_DEPLOYER_KEY]: getStorageXOR(
'0x' + '00'.repeat(31) + '01'
),
},
},
verifiedContractStorage: {
[predeploys.OVM_DeployerWhitelist]: {
'0x0000000000000000000000000000000000000000000000000000000000000000': 1,
[NON_WHITELISTED_DEPLOYER_KEY]: 1,
[WHITELISTED_DEPLOYER_KEY]: 1,
},
},
},
},
subTests: [
{
name: 'when arbitrary contract deployment is enabled',
parameters: [
{
name: 'ovmCREATE by NON_WHITELISTED_DEPLOYER',
steps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT / 2,
target: NON_WHITELISTED_DEPLOYER,
subSteps: [
{
functionName: 'ovmCREATE',
functionParams: {
subSteps: [],
},
expectedReturnStatus: true,
expectedReturnValue:
CREATED_BY_NON_WHITELISTED_DEPLOYER,
},
],
},
expectedReturnStatus: true,
},
],
},
],
},
],
},
],
}
const runner = new ExecutionManagerTestRunner()
runner.run(test_ovmCREATE)
...@@ -71,7 +71,7 @@ const test_ovmCREATEEOA: TestDefinition = { ...@@ -71,7 +71,7 @@ const test_ovmCREATEEOA: TestDefinition = {
}, },
expectedReturnStatus: true, expectedReturnStatus: true,
expectedReturnValue: fromHexString( expectedReturnValue: fromHexString(
getContractDefinition('OVM_ProxyEOA', true).deployedBytecode getContractDefinition('OVM_ProxyEOA').deployedBytecode
).length, ).length,
}, },
], ],
......
/* Internal Imports */
import { constants } from 'ethers'
import {
ExecutionManagerTestRunner,
TestDefinition,
OVM_TX_GAS_LIMIT,
NON_NULL_BYTES32,
VERIFIED_EMPTY_CONTRACT_HASH,
} from '../../../../helpers'
const GAS_METADATA_ADDRESS = '0x06a506a506a506a506a506a506a506a506a506a5'
enum GasMetadataKey {
CURRENT_EPOCH_START_TIMESTAMP,
CUMULATIVE_SEQUENCER_QUEUE_GAS,
CUMULATIVE_L1TOL2_QUEUE_GAS,
PREV_EPOCH_SEQUENCER_QUEUE_GAS,
PREV_EPOCH_L1TOL2_QUEUE_GAS,
}
const keyToBytes32 = (key: GasMetadataKey): string => {
return '0x' + `0${key}`.padStart(64, '0')
}
const test_run: TestDefinition = {
name: 'Basic tests for ovmCALL',
preState: {
ExecutionManager: {
ovmStateManager: '$OVM_STATE_MANAGER',
ovmSafetyChecker: '$OVM_SAFETY_CHECKER',
messageRecord: {
nuisanceGasLeft: OVM_TX_GAS_LIMIT,
},
},
StateManager: {
owner: '$OVM_EXECUTION_MANAGER',
accounts: {
$DUMMY_OVM_ADDRESS_1: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
$DUMMY_OVM_ADDRESS_2: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_CALL_HELPER',
},
$DUMMY_OVM_ADDRESS_3: {
codeHash: VERIFIED_EMPTY_CONTRACT_HASH,
ethAddress: '0x' + '00'.repeat(20),
},
},
contractStorage: {
[GAS_METADATA_ADDRESS]: {
[keyToBytes32(GasMetadataKey.CURRENT_EPOCH_START_TIMESTAMP)]: 1,
[keyToBytes32(GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS)]: 0,
[keyToBytes32(GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS)]: 0,
[keyToBytes32(GasMetadataKey.PREV_EPOCH_SEQUENCER_QUEUE_GAS)]: 0,
[keyToBytes32(GasMetadataKey.PREV_EPOCH_L1TOL2_QUEUE_GAS)]: 0,
},
},
verifiedContractStorage: {
[GAS_METADATA_ADDRESS]: {
[keyToBytes32(GasMetadataKey.CURRENT_EPOCH_START_TIMESTAMP)]: true,
[keyToBytes32(GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS)]: true,
[keyToBytes32(GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS)]: true,
[keyToBytes32(GasMetadataKey.PREV_EPOCH_SEQUENCER_QUEUE_GAS)]: true,
[keyToBytes32(GasMetadataKey.PREV_EPOCH_L1TOL2_QUEUE_GAS)]: true,
},
},
},
},
parameters: [
{
name: 'run => ovmCALL(ADDRESS_1) => ovmADDRESS',
// TODO: Appears to be failing because of a bug in smock.
skip: true,
steps: [
{
functionName: 'run',
functionParams: {
timestamp: 0,
queueOrigin: 0,
entrypoint: '$OVM_CALL_HELPER',
origin: constants.AddressZero,
msgSender: constants.AddressZero,
gasLimit: OVM_TX_GAS_LIMIT,
subSteps: [
{
functionName: 'ovmCALL',
functionParams: {
gasLimit: OVM_TX_GAS_LIMIT,
target: '$DUMMY_OVM_ADDRESS_1',
subSteps: [
{
functionName: 'ovmADDRESS',
expectedReturnValue: '$DUMMY_OVM_ADDRESS_1',
},
],
},
expectedReturnStatus: true,
},
],
},
},
],
},
// This functionality has moved to the OVM_StateTransitioner,
// but leaving here for future reference on how to use this feature of the EM TestRunner.
// {
// name: 'run with insufficient gas supplied',
// steps: [
// {
// functionName: 'run',
// suppliedGas: OVM_TX_GAS_LIMIT / 2,
// functionParams: {
// timestamp: 0,
// queueOrigin: 0,
// entrypoint: '$OVM_CALL_HELPER',
// origin: constants.AddressZero,
// msgSender: constants.AddressZero,
// gasLimit: OVM_TX_GAS_LIMIT,
// subSteps: [],
// },
// expectedRevertValue: 'Not enough gas to execute deterministically',
// },
// ],
// },
],
}
const runner = new ExecutionManagerTestRunner()
runner.run(test_run)
...@@ -231,24 +231,21 @@ export class ExecutionManagerTestRunner { ...@@ -231,24 +231,21 @@ export class ExecutionManagerTestRunner {
const DeployerWhitelist = await getContractFactory( const DeployerWhitelist = await getContractFactory(
'OVM_DeployerWhitelist', 'OVM_DeployerWhitelist',
AddressManager.signer, AddressManager.signer
true
).deploy() ).deploy()
this.contracts.OVM_DeployerWhitelist = DeployerWhitelist this.contracts.OVM_DeployerWhitelist = DeployerWhitelist
const OvmEth = await getContractFactory( const OvmEth = await getContractFactory(
'OVM_ETH', 'OVM_ETH',
AddressManager.signer, AddressManager.signer
true
).deploy() ).deploy()
this.contracts.OVM_ETH = OvmEth this.contracts.OVM_ETH = OvmEth
this.contracts.OVM_ProxyEOA = await getContractFactory( this.contracts.OVM_ProxyEOA = await getContractFactory(
'OVM_ProxyEOA', 'OVM_ProxyEOA',
AddressManager.signer, AddressManager.signer
true
).deploy() ).deploy()
this.contracts.OVM_ExecutionManager = await ( this.contracts.OVM_ExecutionManager = await (
......
module.exports = {
extends: '../../.eslintrc.js',
}
module.exports = {
...require('../../.prettierrc.js'),
};
\ No newline at end of file
(The MIT License)
Copyright 2020-2021 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.
# @eth-optimism/hardhat-ovm
A plugin that brings OVM compiler support to Hardhat projects.
## Installation
```
yarn add --dev @eth-optimism/hardhat-ovm
```
Next, import the plugin inside your `hardhat.config.js`:
```js
// hardhat.config.js
require("@eth-optimism/hardhat-ovm")
```
Or if using TypeScript:
```ts
// hardhat.config.ts
import "@eth-optimism/hardhat-ovm"
```
## Configuration
**By default, this plugin will use OVM compiler version 0.7.6**.
Configure this plugin by adding an `ovm` field to your Hardhat config:
```js
// hardhat.config.js
require("@eth-optimism/hardhat-ovm")
module.exports = {
ovm: {
solcVersion: 'X.Y.Z' // Your version goes here.
}
}
```
This package also has typings so it won't break your Hardhat config if you're using TypeScript.
/* Imports: External */
import * as fs from 'fs'
import * as path from 'path'
import fetch from 'node-fetch'
import { ethers } from 'ethers'
import { subtask, extendEnvironment } from 'hardhat/config'
import {
HardhatNetworkHDAccountsConfig,
HardhatNetworkAccountUserConfig,
} from 'hardhat/types/config'
import { getCompilersDir } from 'hardhat/internal/util/global-dir'
import { Artifacts } from 'hardhat/internal/artifacts'
import {
TASK_COMPILE_SOLIDITY_RUN_SOLCJS,
TASK_COMPILE_SOLIDITY_RUN_SOLC,
} from 'hardhat/builtin-tasks/task-names'
/* Imports: Internal */
import './type-extensions'
const OPTIMISM_SOLC_VERSION_URL =
'https://api.github.com/repos/ethereum-optimism/solc-bin/git/refs/heads/gh-pages'
const OPTIMISM_SOLC_BIN_URL =
'https://raw.githubusercontent.com/ethereum-optimism/solc-bin/gh-pages/bin'
// I figured this was a reasonably modern default, but not sure if this is too new. Maybe we can
// default to 0.6.X instead?
const DEFAULT_OVM_SOLC_VERSION = '0.7.6'
// Poll the node every 50ms, to override ethers.js's default 4000ms causing OVM
// tests to be slow.
const OVM_POLLING_INTERVAL = 50
/**
* Find or generate an OVM soljson.js compiler file and return the path of this file.
* We pass the path to this file into hardhat.
*
* @param version Solidity compiler version to get a path for in the format `X.Y.Z`.
* @return Path to the downloaded soljson.js file.
*/
const getOvmSolcPath = async (version: string): Promise<string> => {
// If __DANGEROUS_OVM_IGNORE_ERRORS__ env var is not undefined we append the -no-errors suffix to the solc version.
if (process.env.__DANGEROUS_OVM_IGNORE_ERRORS__) {
console.log('\n\n__DANGEROUS_OVM_IGNORE_ERRORS__ IS ENABLED!\n\n')
version += '-no_errors'
}
// First, check to see if we've already downloaded this file. Hardhat gives us a folder to use as
// a compiler cache, so we'll just be nice and use an `ovm` subfolder.
const ovmCompilersCache = path.join(await getCompilersDir(), 'ovm')
// Need to create the OVM compiler cache folder if it doesn't already exist.
if (!fs.existsSync(ovmCompilersCache)) {
fs.mkdirSync(ovmCompilersCache, { recursive: true })
}
// Pull information about the latest commit in the solc-bin repo. We'll use this to invalidate
// our compiler cache if necessary.
const remoteCompilerVersion = await (
await fetch(OPTIMISM_SOLC_VERSION_URL)
).text()
// Pull the locally stored info about the latest commit. If this differs from the remote info
// then we know to invalidate our cache.
let cachedCompilerVersion = ''
const cachedCompilerVersionPath = path.join(
ovmCompilersCache,
`version-info-${version}.json`
)
if (fs.existsSync(cachedCompilerVersionPath)) {
cachedCompilerVersion = fs
.readFileSync(cachedCompilerVersionPath)
.toString()
}
// Check to see if we already have this compiler version downloaded. We store the cached files at
// `X.Y.Z.js`. If it already exists, just return that instead of downloading a new one.
const cachedCompilerPath = path.join(ovmCompilersCache, `${version}.js`)
if (
remoteCompilerVersion === cachedCompilerVersion &&
fs.existsSync(cachedCompilerPath)
) {
return cachedCompilerPath
}
console.log(`Downloading OVM compiler version ${version}`)
// We don't have a cache, so we'll download this file from GitHub. Currently stored at
// ethereum-optimism/solc-bin.
const compilerContentResponse = await fetch(
OPTIMISM_SOLC_BIN_URL + `/soljson-v${version}.js`
)
// Throw if this request failed, e.g., 404 because of an invalid version.
if (!compilerContentResponse.ok) {
throw new Error(
`Unable to download OVM compiler version ${version}. Are you sure that version exists?`
)
}
// Otherwise, write the content to the cache. We probably want to do some sort of hash
// verification against these files but it's OK for now. The real "TODO" here is to instead
// figure out how to properly extend and/or hack Hardat's CompilerDownloader class.
const compilerContent = await compilerContentResponse.text()
fs.writeFileSync(cachedCompilerPath, compilerContent)
fs.writeFileSync(cachedCompilerVersionPath, remoteCompilerVersion)
return cachedCompilerPath
}
// TODO: implement a more elegant fix for this.
// Hardhat on M1 Macbooks does not run TASK_COMPILE_SOLIDITY_RUN_SOLC, but instead this runs one,
// TASK_COMPILE_SOLIDITY_RUN_SOLCJS. We reroute this task back to the solc task in the case
// of OVM compilation.
subtask(TASK_COMPILE_SOLIDITY_RUN_SOLCJS, async (args, hre, runSuper) => {
const argsAny = args as any
if (argsAny.real || hre.network.ovm !== true) {
for (const file of Object.keys(argsAny.input.sources)) {
// Ignore any contract that has this tag or in ignore list
if (
argsAny.input.sources[file].content.includes('// @unsupported: evm') &&
hre.network.ovm !== true
) {
delete argsAny.input.sources[file]
}
}
return runSuper(args)
} else {
return hre.run(TASK_COMPILE_SOLIDITY_RUN_SOLC, {
...argsAny,
solcPath: argsAny.solcJsPath,
})
}
})
subtask(
TASK_COMPILE_SOLIDITY_RUN_SOLC,
async (args: { input: any; solcPath: string }, hre, runSuper) => {
const ignoreRxList = hre.network.config.ignoreRxList || []
const ignore = (filename: string) =>
ignoreRxList.reduce(
(ignored: boolean, rx: string | RegExp) =>
ignored || new RegExp(rx).test(filename),
false
)
if (hre.network.ovm !== true) {
// Separate the EVM and OVM inputs.
for (const file of Object.keys(args.input.sources)) {
// Ignore any contract that has this tag or in ignore list
if (
args.input.sources[file].content.includes('// @unsupported: evm') ||
ignore(file)
) {
delete args.input.sources[file]
} else {
//console.log(file + ' included');
}
}
return runSuper(args)
}
// Just some silly sanity checks, make sure we have a solc version to download. Our format is
// `X.Y.Z` (for now).
let ovmSolcVersion = DEFAULT_OVM_SOLC_VERSION
if (hre.config?.ovm?.solcVersion) {
ovmSolcVersion = hre.config.ovm.solcVersion
}
// Get a path to a soljson file.
const ovmSolcPath = await getOvmSolcPath(ovmSolcVersion)
// These objects get fed into the compiler. We're creating two of these because we need to
// throw one into the OVM compiler and another into the EVM compiler. Users are able to prevent
// certain files from being compiled by the OVM compiler by adding "// @unsupported: ovm"
// somewhere near the top of their file.
const ovmInput = {
language: 'Solidity',
sources: {},
settings: args.input.settings,
}
// Separate the EVM and OVM inputs.
for (const file of Object.keys(args.input.sources)) {
// Ignore any contract that has this tag or in ignore list
if (
!args.input.sources[file].content.includes('// @unsupported: ovm') &&
!ignore(file)
) {
ovmInput.sources[file] = args.input.sources[file]
}
}
if (Object.keys(ovmInput.sources).length === 0) {
return {}
}
// Build both inputs separately.
const ovmOutput = await hre.run(TASK_COMPILE_SOLIDITY_RUN_SOLCJS, {
input: ovmInput,
solcJsPath: ovmSolcPath,
real: true,
})
// Just doing this to add some extra useful information to any errors in the OVM compiler output.
ovmOutput.errors = (ovmOutput.errors || []).map((error: any) => {
if (error.severity === 'error') {
error.formattedMessage = `OVM Compiler Error (insert "// @unsupported: ovm" if you don't want this file to be compiled for the OVM):\n ${error.formattedMessage}`
}
return error
})
return ovmOutput
}
)
extendEnvironment(async (hre) => {
if (hre.network.config.ovm) {
hre.network.ovm = hre.network.config.ovm
let artifactsPath = hre.config.paths.artifacts
if (!artifactsPath.endsWith('-ovm')) {
artifactsPath = artifactsPath + '-ovm'
}
let cachePath = hre.config.paths.cache
if (!cachePath.endsWith('-ovm')) {
cachePath = cachePath + '-ovm'
}
// Forcibly update the artifacts object.
hre.config.paths.artifacts = artifactsPath
hre.config.paths.cache = cachePath
;(hre as any).artifacts = new Artifacts(artifactsPath)
// if typechain is present, send the typed bindings to an ovm-specific
// directory
if ((hre.config as any).typechain) {
if (!(hre as any).config.typechain.outDir.endsWith('-ovm')) {
;(hre as any).config.typechain.outDir += '-ovm'
}
}
// if ethers is present and the node is running, override the polling interval to not wait the full
// duration in tests
if ((hre as any).ethers) {
const interval = hre.network.config.interval || OVM_POLLING_INTERVAL
if ((hre as any).ethers.provider.pollingInterval === interval) {
return
}
// override the provider polling interval
const provider = new ethers.providers.JsonRpcProvider(
(hre as any).ethers.provider.url || (hre as any).network.config.url
)
provider.pollingInterval = interval
// the gas price is overriden to the user provided gasPrice or to 0.
provider.getGasPrice = async () =>
ethers.BigNumber.from(hre.network.config.gasPrice || 0)
// if the node is up, override the getSigners method's signers
try {
let signers: ethers.Signer[]
const accounts = hre.network.config.accounts as
| HardhatNetworkHDAccountsConfig
| HardhatNetworkAccountUserConfig[]
if (Array.isArray(accounts)) {
signers = (accounts as HardhatNetworkAccountUserConfig[]).map(
(account) =>
new ethers.Wallet(
typeof account === 'string' ? account : account.privateKey
).connect(provider)
)
} else if (accounts) {
const indices = Array.from(Array(20).keys()) // generates array of [0, 1, 2, ..., 18, 19]
signers = indices.map((i) =>
ethers.Wallet.fromMnemonic(
accounts.mnemonic,
`${accounts.path}/${i}`
).connect(provider)
)
} else {
signers = await (hre as any).ethers.getSigners()
signers = signers.map((s: any) => {
s._signer.provider.pollingInterval = interval
return s
})
}
;(hre as any).ethers.getSigners = () => signers
// eslint-disable-next-line no-empty
} catch (e) {}
// Update the provider at the very end to avoid any weird issues.
;(hre as any).ethers.provider = provider
}
}
})
import 'hardhat/types/config'
declare module 'hardhat/types/config' {
interface HardhatUserConfig {
ovm?: {
solcVersion?: string
}
}
interface HardhatConfig {
ovm?: {
solcVersion?: string
}
}
interface HardhatNetworkUserConfig {
ovm?: boolean
ignoreRxList?: string[]
}
interface HttpNetworkUserConfig {
ovm?: boolean
ignoreRxList?: string[]
}
interface HardhatNetworkConfig {
ovm: boolean
ignoreRxList: string[]
interval?: number
}
interface HttpNetworkConfig {
ovm: boolean
ignoreRxList: string[]
interval?: number
}
}
declare module 'hardhat/types/runtime' {
interface Network {
ovm: boolean
ignoreRxList: string[]
}
}
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"extends": "../../tsconfig.json"
}
...@@ -2606,10 +2606,10 @@ ...@@ -2606,10 +2606,10 @@
dependencies: dependencies:
"@types/tz-offset" "*" "@types/tz-offset" "*"
"@types/node-fetch@^2.5.10", "@types/node-fetch@^2.5.5": "@types/node-fetch@^2.5.5", "@types/node-fetch@^2.5.8":
version "2.5.12" version "2.5.10"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.10.tgz#9b4d4a0425562f9fcea70b12cb3fcdd946ca8132"
integrity sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw== integrity sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
form-data "^3.0.0" form-data "^3.0.0"
......
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