Commit 80d78bea authored by Matthew Slipper's avatar Matthew Slipper

integration-tests-bedrock: Remove superfluous packages

parent 8ddb6997
...@@ -77,7 +77,6 @@ Refer to the Directory Structure section below to understand which packages are ...@@ -77,7 +77,6 @@ Refer to the Directory Structure section below to understand which packages are
~~ BEDROCK upgrade - Not production-ready yet, part of next major upgrade ~~ ~~ BEDROCK upgrade - Not production-ready yet, part of next major upgrade ~~
├── <a href="./packages">packages</a> ├── <a href="./packages">packages</a>
│ ├── <a href="./packages/integration-tests-bedrock">integration-tests-bedrock</a>: Bedrock integration tests.
│ └── <a href="./packages/contracts-bedrock">contracts-bedrock</a>: Bedrock smart contracts. To be merged with ./packages/contracts. │ └── <a href="./packages/contracts-bedrock">contracts-bedrock</a>: Bedrock smart contracts. To be merged with ./packages/contracts.
├── <a href="./op-bindings">op-bindings</a>: Go bindings for Bedrock smart contracts. ├── <a href="./op-bindings">op-bindings</a>: Go bindings for Bedrock smart contracts.
├── <a href="./op-batcher">op-batcher</a>: L2-Batch Submitter, submits bundles of batches to L1 ├── <a href="./op-batcher">op-batcher</a>: L2-Batch Submitter, submits bundles of batches to L1
......
# @eth-optimism/integration-tests-bedrock
## 0.5.12
### Patch Changes
- 7215f4ce: Bump ethers to 5.7.0 globally
- 206f6033: Fix outdated references to 'withdrawal contract'
## 0.5.11
### Patch Changes
- 29ff7462: Revert es target back to 2017
## 0.5.10
### Patch Changes
- ef7758a9: Bump integration test dependencies to latest for changesets
- d18ae135: Updates all ethers versions in response to BN.js bug
pragma solidity ^0.8.10;
contract Counter {
uint256 public value = 0;
constructor() {}
function getValue() public view returns (uint256) {
return value;
}
function incValue() public {
value++;
}
}
\ No newline at end of file
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract ERC20 {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
uint256 constant private MAX_UINT256 = 2**256 - 1;
mapping (address => uint256) public balances;
mapping (address => mapping (address => uint256)) public allowed;
/*
NOTE:
The following variables are OPTIONAL vanities. One does not have to include them.
They allow one to customise the token contract & in no way influences the core functionality.
Some wallets/interfaces might not even bother to look at this information.
*/
string public name; //fancy name: eg OVM Coin
uint8 public decimals; //How many decimals to show.
string public symbol; //An identifier: eg OVM
uint256 public totalSupply;
constructor(
uint256 _initialAmount,
string memory _tokenName,
uint8 _decimalUnits,
string memory _tokenSymbol
) public {
balances[msg.sender] = _initialAmount; // Give the creator all initial tokens
totalSupply = _initialAmount; // Update total supply
name = _tokenName; // Set the name for display purposes
decimals = _decimalUnits; // Amount of decimals for display purposes
symbol = _tokenSymbol; // Set the symbol for display purposes
}
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balances[msg.sender] >= _value, "insufficient balance");
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
uint256 allowance = allowed[_from][msg.sender];
require(balances[_from] >= _value && allowance >= _value, "bad allowance");
balances[_to] += _value;
balances[_from] -= _value;
if (allowance < MAX_UINT256) {
allowed[_from][msg.sender] -= _value;
}
emit Transfer(_from, _to, _value);
return true;
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
function approve(address _spender, uint256 _value) public returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
function destroy() public {
selfdestruct(payable(msg.sender));
}
}
pragma solidity 0.8.10;
interface DepositFeed {
function depositTransaction(
address _to,
uint256 _value,
uint64 _gasLimit,
bool _isCreation,
bytes memory _data
) external payable;
}
contract MultiDepositor {
DepositFeed df = DepositFeed(0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001);
constructor(address _df) {
df = DepositFeed(_df);
}
function deposit(address to) external payable {
for (uint i = 0; i < 3; i++) {
df.depositTransaction{value : 1000000000}(
to,
1000,
3000000,
false,
""
);
}
}
}
\ No newline at end of file
pragma solidity 0.8.10;
contract Reverter {
string constant public revertMessage = "This is a simple reversion.";
function doRevert() public pure {
revert(revertMessage);
}
}
\ No newline at end of file
[profile.default]
src = 'contracts'
out = 'forge-artifacts'
optimizer = true
optimizer_runs = 999999
extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout']
bytecode_hash = "none"
{
"private": true,
"name": "@eth-optimism/integration-tests-bedrock",
"version": "0.5.12",
"description": "[Optimism] Bedrock Integration tests",
"scripts": {
"lint": "yarn lint:fix && yarn lint:check",
"lint:fix": "yarn lint:check --fix",
"lint:check": "eslint . --max-warnings=0",
"build:contracts": "forge build",
"test": "echo 'no unit tests'",
"test:actor": "IS_LIVE_NETWORK=true ts-node actor-tests/lib/runner.ts",
"test:integration:live": "NO_NETWORK=true IS_LIVE_NETWORK=true hardhat --network optimism test",
"clean": "rimraf cache artifacts foundry-artifacts"
},
"keywords": [
"optimism",
"ethereum",
"integration",
"tests"
],
"homepage": "https://github.com/ethereum-optimism/optimism/tree/develop/packages/integration-tests-bedrock#readme",
"license": "MIT",
"author": "Optimism PBC",
"repository": {
"type": "git",
"url": "https://github.com/ethereum-optimism/optimism.git"
},
"devDependencies": {
"@eth-optimism/contracts": "0.5.38",
"@eth-optimism/core-utils": "0.11.0",
"@eth-optimism/sdk": "1.6.10",
"@ethersproject/abstract-provider": "^5.7.0",
"chai-as-promised": "^7.1.1",
"chai": "^4.3.4",
"dotenv": "^10.0.0",
"envalid": "^7.1.0",
"ethereum-waffle": "^3.3.0",
"ethers": "^5.7.0",
"rimraf": "^3.0.2",
"ts-node": "^10.7.0"
},
"dependencies": {
"rlp": "^3.0.0",
"winston": "^3.7.2"
}
}
// Named 000 in order to run first since the output submitter
// can fall behind.
/* Imports: External */
import {
BigNumber,
constants,
Contract,
ContractReceipt,
utils,
Wallet,
} from 'ethers'
import { awaitCondition } from '@eth-optimism/core-utils'
import * as rlp from 'rlp'
import { Block } from '@ethersproject/abstract-provider'
import winston from 'winston'
import { predeploys } from '@eth-optimism/contracts'
import env from './shared/env'
import { expect } from './shared/setup'
import l2ToL1MessagePasserArtifact from '../../contracts-bedrock/artifacts/contracts/L2/L2ToL1MessagePasser.sol/L2ToL1MessagePasser.json'
import l2OOracleArtifact from '../../contracts-bedrock/artifacts/contracts/L1/L2OutputOracle.sol/L2OutputOracle.json'
/**
* Calculates the target output timestamp to make the withdrawal proof against. ie. the first
* output with a timestamp greater than the burn block timestamp.
*
* @param {Contract} oracle Address of the L2 Output Oracle.
* @param {number} withdrawalTimestamp L2 timestamp of the block the withdrawal was made in.
*/
const getTargetOutput = async (
oracle: Contract,
withdrawalTimestamp: number
) => {
const submissionInterval = (await oracle.SUBMISSION_INTERVAL()).toNumber()
const startingTimestamp = (await oracle.STARTING_TIMESTAMP()).toNumber()
const nextTimestamp = (await oracle.nextTimestamp()).toNumber()
let targetOutputTimestamp
if (withdrawalTimestamp < nextTimestamp) {
// Just use the next timestamp
targetOutputTimestamp = nextTimestamp
} else {
// Calculate the first timestamp greater than the burnBlock which will be appended.
targetOutputTimestamp =
Math.ceil(
(withdrawalTimestamp - startingTimestamp) / submissionInterval
) *
submissionInterval +
startingTimestamp
}
return targetOutputTimestamp
}
describe('Withdrawals', () => {
let logger: winston.Logger
let portal: Contract
let withdrawer: Contract
let recipient: Wallet
before(async () => {
logger = env.logger
portal = env.optimismPortal
withdrawer = new Contract(
predeploys.OVM_L2ToL1MessagePasser,
l2ToL1MessagePasserArtifact.abi
)
})
describe('simple withdrawals', () => {
let nonce: BigNumber
let burnBlock: Block
let withdrawalHash: string
const value = utils.parseEther('1')
const gasLimit = 3000000
before(async function () {
this.timeout(60_000)
recipient = Wallet.createRandom().connect(env.l2Provider)
withdrawer = withdrawer.connect(recipient)
logger.info('Generated new wallet', {
recipient: recipient.address,
})
logger.info('Depositing to new address on L2')
let tx = await portal
.connect(env.l1Wallet)
.depositTransaction(
recipient.address,
utils.parseEther('1.337'),
gasLimit,
false,
[],
{
value: utils.parseEther('1.337'),
}
)
await tx.wait()
await awaitCondition(async () => {
const bal = await recipient.getBalance()
return bal.eq(tx.value)
})
logger.info('Transferring funds on L1')
tx = await env.l1Wallet.sendTransaction({
to: recipient.address,
value,
})
await tx.wait()
})
it('should create a withdrawal on L2', async () => {
nonce = await withdrawer.nonce()
const tx = await withdrawer.initiateWithdrawal(
recipient.address,
gasLimit,
[],
{
value,
}
)
const receipt: ContractReceipt = await tx.wait()
expect(receipt.events!.length).to.eq(1)
expect(receipt.events![0].args).to.deep.eq([
nonce,
recipient.address,
recipient.address,
value,
BigNumber.from(gasLimit),
'0x',
])
burnBlock = await env.l2Provider.getBlock(receipt.blockHash)
withdrawalHash = utils.keccak256(
utils.defaultAbiCoder.encode(
['uint256', 'address', 'address', 'uint256', 'uint256', 'bytes'],
[
utils.hexZeroPad(nonce.toHexString(), 32),
recipient.address,
recipient.address,
value,
gasLimit,
'0x',
]
)
)
const included = await withdrawer.sentMessages(withdrawalHash)
expect(included).to.be.true
})
// TODO(tynes): refactor this test. the awaitCondition hangs
// forever in its current state
it.skip('should verify the withdrawal on L1', async function () {
recipient = recipient.connect(env.l1Provider)
portal = portal.connect(recipient)
const oracle = new Contract(
await portal.L2_ORACLE(),
l2OOracleArtifact.abi
).connect(recipient)
const targetOutputTimestamp = await getTargetOutput(
oracle,
burnBlock.timestamp
)
// Set the timeout based on the diff between latest output and target output timestamp.
let latestBlockTimestamp = (
await oracle.latestBlockTimestamp()
).toNumber()
let difference = targetOutputTimestamp - latestBlockTimestamp
this.timeout(difference * 5000)
let output: string
await awaitCondition(
async () => {
const proposal = await oracle.getL2Output(targetOutputTimestamp)
output = proposal.outputRoot
latestBlockTimestamp = (
await oracle.latestBlockTimestamp()
).toNumber()
if (targetOutputTimestamp - latestBlockTimestamp < difference) {
// Only log when a new output has been appended
difference = targetOutputTimestamp - latestBlockTimestamp
logger.info('Waiting for output submission', {
targetTimestamp: targetOutputTimestamp,
latestOracleTS: latestBlockTimestamp,
difference,
output,
})
}
return output !== constants.HashZero
},
2000,
2 * difference
)
// suppress compilation errors since Typescript cannot detect
// that awaitCondition above will throw if it times out.
output = output!
const blocksSinceBurn = Math.floor(
(targetOutputTimestamp - burnBlock.timestamp) / 2
)
const targetBlockNum = burnBlock.number + blocksSinceBurn + 1
const targetBlockNumHex = utils.hexValue(targetBlockNum)
const storageSlot = '00'.repeat(31) + '01' // i.e the second variable declared in the contract
const proof = await env.l2Provider.send('eth_getProof', [
predeploys.OVM_L2ToL1MessagePasser,
[utils.keccak256(withdrawalHash + storageSlot)],
targetBlockNumHex,
])
const { stateRoot: targetStateRoot, hash: targetHash } =
await env.l2Provider.send('eth_getBlockByNumber', [
targetBlockNumHex,
false,
])
const finalizationPeriod = (await portal.FINALIZATION_PERIOD()).toNumber()
logger.info('Waiting finalization period', {
seconds: finalizationPeriod,
})
await new Promise((resolve) =>
setTimeout(resolve, finalizationPeriod * 1000)
)
logger.info('Finalizing withdrawal')
const initialBal = await recipient.getBalance()
const tx = await portal.finalizeWithdrawalTransaction(
nonce,
recipient.address,
recipient.address,
value,
gasLimit,
'0x',
targetOutputTimestamp,
{
version: constants.HashZero,
stateRoot: targetStateRoot,
messagePasserStorageRoot: proof.storageHash,
latestBlockhash: targetHash,
},
rlp.encode(proof.storageProof[0].proof),
{
gasLimit,
}
)
await tx.wait()
const finalBal = await recipient.getBalance()
expect(finalBal.gte(initialBal)).to.be.true
}).timeout(180_000)
})
})
/* Imports: External */
import { Contract, ContractFactory, utils, Wallet } from 'ethers'
import { awaitCondition } from '@eth-optimism/core-utils'
/* Imports: Internal */
import { defaultTransactionFactory } from './shared/utils'
import env from './shared/env'
import counterArtifact from '../forge-artifacts/Counter.sol/Counter.json'
import multiDepositorArtifact from '../forge-artifacts/MultiDepositor.sol/MultiDepositor.json'
describe('Deposits', () => {
let portal: Contract
before(() => {
portal = env.optimismPortal.connect(env.l1Wallet)
})
it('should deposit value', async () => {
const recipWallet = Wallet.createRandom().connect(env.l2Provider)
const tx = defaultTransactionFactory()
tx.value = utils.parseEther('1.337')
tx.to = recipWallet.address
const result = await portal.depositTransaction(
tx.to,
tx.value,
'3000000',
false,
[],
{
value: tx.value,
}
)
await result.wait()
await awaitCondition(async () => {
const bal = await recipWallet.getBalance()
return bal.eq(tx.value)
})
})
it('should support multiple deposits in a single tx', async () => {
const recipWallet = Wallet.createRandom().connect(env.l2Provider)
const value = utils.parseEther('0.1')
const factory = new ContractFactory(
multiDepositorArtifact.abi,
multiDepositorArtifact.bytecode.object
).connect(env.l1Wallet)
const contract = await factory.deploy(portal.address)
await contract.deployed()
const tx = await contract.deposit(recipWallet.address, {
value,
})
await tx.wait()
await awaitCondition(async () => {
const bal = await recipWallet.getBalance()
return bal.eq('3000')
})
}).timeout(60_000)
it.skip('should deposit a contract creation', async () => {
const value = utils.parseEther('0.1')
const factory = new ContractFactory(
counterArtifact.abi,
counterArtifact.bytecode.object
)
const tx = await factory.getDeployTransaction()
const result = await portal.depositTransaction(
`0x${'0'.repeat(40)}`,
'0',
'3000000',
true,
tx.data,
{
value,
}
)
await result.wait()
const l2Nonce = await env.l2Wallet.getTransactionCount()
const addr = utils.getContractAddress({
from: env.l2Wallet.address,
nonce: l2Nonce,
})
await awaitCondition(async () => {
const code = await env.l2Provider.getCode(addr)
return code === counterArtifact.bytecode.object
})
})
})
/* Imports: External */
import { ContractFactory, Wallet } from 'ethers'
/* Imports: Internal */
import { expect } from './shared/setup'
import { defaultTransactionFactory } from './shared/utils'
import env from './shared/env'
import counterArtifact from '../artifacts/Counter.sol/Counter.json'
describe('RPCs', () => {
let wallet: Wallet
before(async () => {
wallet = env.l2Wallet
})
it('eth_chainId', async () => {
const network = await env.l2Provider.getNetwork()
expect(network.chainId).to.equal(901)
})
describe('eth_sendRawTransaction', () => {
it('should correctly process a funds transfer', async () => {
const altWallet = await Wallet.createRandom().connect(env.l2Provider)
const tx = defaultTransactionFactory()
tx.to = altWallet.address
const nonce = await wallet.getTransactionCount()
const result = await wallet.sendTransaction(tx)
expect(result.from).to.equal(wallet.address)
expect(result.nonce).to.equal(nonce)
expect(result.gasLimit.toNumber()).to.equal(tx.gasLimit)
expect(result.data).to.equal(tx.data)
expect(await altWallet.getBalance()).to.equal(tx.value)
})
it('should correctly process a contract creation', async () => {
const factory = new ContractFactory(
counterArtifact.abi,
counterArtifact.bytecode.object
).connect(wallet)
const counter = await factory.deploy({
gasLimit: 1_000_000,
})
await counter.deployed()
expect(await env.l2Provider.getCode(counter.address)).not.to.equal('0x')
})
})
})
/* Imports: External */
import { Wallet, providers, Contract } from 'ethers'
import { bool, cleanEnv, num, str } from 'envalid'
import dotenv from 'dotenv'
import winston from 'winston'
const { combine, timestamp, printf, colorize, align } = winston.format
/* Imports: Internal */
import portalArtifact from '../../../contracts-bedrock/artifacts/contracts/L1/OptimismPortal.sol/OptimismPortal.json'
dotenv.config()
const procEnv = cleanEnv(process.env, {
L1_URL: str({ default: 'http://localhost:8545' }),
L1_POLLING_INTERVAL: num({ default: 10 }),
L2_URL: str({ default: 'http://localhost:9545' }),
L2_POLLING_INTERVAL: num({ default: 1 }),
OPTIMISM_PORTAL_ADDRESS: str(),
PRIVATE_KEY: str({
default: 'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
}),
MOCHA_TIMEOUT: num({
default: 120_000,
}),
MOCHA_BAIL: bool({
default: false,
}),
LOG_LEVEL: str({
default: 'info',
}),
})
/// Helper class for instantiating a test environment with a funded account
export class OptimismEnv {
// The wallets
l1Wallet: Wallet
l2Wallet: Wallet
// The providers
l1Provider: providers.JsonRpcProvider
l2Provider: providers.JsonRpcProvider
// Contracts
optimismPortal: Contract
logger: winston.Logger
constructor() {
const l1Provider = new providers.JsonRpcProvider(procEnv.L1_URL)
l1Provider.pollingInterval = procEnv.L1_POLLING_INTERVAL
const l2Provider = new providers.JsonRpcProvider(procEnv.L2_URL)
l2Provider.pollingInterval = procEnv.L2_POLLING_INTERVAL
const l1Wallet = new Wallet(procEnv.PRIVATE_KEY, l1Provider)
const l2Wallet = new Wallet(procEnv.PRIVATE_KEY, l2Provider)
if (!procEnv.OPTIMISM_PORTAL_ADDRESS) {
throw new Error('Must define an OptimismPortal address.')
}
this.l1Wallet = l1Wallet
this.l2Wallet = l2Wallet
this.l1Provider = l1Provider
this.l2Provider = l2Provider
this.optimismPortal = new Contract(
procEnv.OPTIMISM_PORTAL_ADDRESS,
portalArtifact.abi
)
this.logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: combine(
{
transform: (info) => {
// @ts-ignore
const args = info[Symbol.for('splat')]
const meta = args ? args[0] : null
const suffix = meta ? ` ${keyify(meta)}` : ''
info.message = `${info.message}${suffix}`
return info
},
},
colorize({ all: true }),
timestamp({
format: 'YYYY-MM-DD hh:mm:ss.SSS A',
}),
align(),
printf((info) => `[${info.timestamp}] ${info.level}: ${info.message}`)
),
transports: [
new winston.transports.Stream({
stream: process.stderr,
}),
],
})
}
}
const keyify = (kv: object): string => {
const out = []
for (const [k, v] of Object.entries(kv)) {
out.push(`${k}=${v}`)
}
return out.join(' ')
}
const env = new OptimismEnv()
export default env
/* External Imports */
import chai = require('chai')
import chaiAsPromised from 'chai-as-promised'
import { solidity } from 'ethereum-waffle'
chai.use(solidity)
chai.use(chaiAsPromised)
const expect = chai.expect
export { expect }
import { BigNumber } from 'ethers'
export const defaultTransactionFactory = () => {
return {
to: '0x' + '1234'.repeat(10),
gasLimit: 8_000_000,
data: '0x',
value: BigNumber.from(0),
}
}
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": [
"src/**/*",
"./test",
"./artifacts/**/*.json",
"./tasks/**/*.ts",
"./package.json"
]
}
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