Commit 9c63e9bd authored by Maurelian's avatar Maurelian Committed by Kelvin Fichter

test(contracts): Add full benchmarking of ETH and ERC20 deposits

parent 99a9ab1f
---
'@eth-optimism/contracts': patch
---
Add gas benchmarks on deposits
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract, constants } from 'ethers'
import { smoddit } from '@eth-optimism/smock'
/* Internal Imports */
import {
makeAddressManager,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
L2_GAS_DISCOUNT_DIVISOR,
ENQUEUE_GAS_COST,
NON_ZERO_ADDRESS,
NON_NULL_BYTES32,
} from '../../../helpers'
import { expect } from '../../../setup'
// Still have some duplication from CanonicalTransactionChain.spec.ts, but it's so minimal that
// this is probably cleaner for now. Particularly since we're planning to move all of this out into
// core-utils soon anyway.
const MAX_GAS_LIMIT = 8_000_000
const INITIAL_TOTAL_L1_SUPPLY = 5000
const FINALIZATION_GAS = 1_200_000
describe('[GAS BENCHMARK] Depositing via the standard bridge', () => {
let sequencer: Signer
let alice: Signer
before(async () => {
;[sequencer] = await ethers.getSigners()
;[alice] = await ethers.getSigners()
})
let AddressManager: Contract
before('Deploy address manager and register sequencer', async () => {
AddressManager = await makeAddressManager()
await AddressManager.setAddress(
'OVM_Sequencer',
await sequencer.getAddress()
)
})
let CanonicalTransactionChain: Contract
let Factory__ChainStorageContainer: ContractFactory
before('Init CTC and Storage Container contracts.', async () => {
CanonicalTransactionChain = await (
await ethers.getContractFactory('CanonicalTransactionChain')
).deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
MAX_GAS_LIMIT,
L2_GAS_DISCOUNT_DIVISOR,
ENQUEUE_GAS_COST
)
Factory__ChainStorageContainer = await ethers.getContractFactory(
'ChainStorageContainer'
)
const batches = await Factory__ChainStorageContainer.deploy(
AddressManager.address,
'CanonicalTransactionChain'
)
const queue = await Factory__ChainStorageContainer.deploy(
AddressManager.address,
'CanonicalTransactionChain'
)
await AddressManager.setAddress(
'ChainStorageContainer-CTC-batches',
batches.address
)
await AddressManager.setAddress(
'ChainStorageContainer-CTC-queue',
queue.address
)
await AddressManager.setAddress(
'CanonicalTransactionChain',
CanonicalTransactionChain.address
)
})
// 3 Messenger
let L1CrossDomainMessenger: Contract
before('Deploy Messenger proxy and implementation', async () => {
// Deploy the implementation contract first
const xDomainMessengerImpl = await (
await ethers.getContractFactory('L1CrossDomainMessenger')
).deploy()
await AddressManager.setAddress(
'L1CrossDomainMessenger',
xDomainMessengerImpl.address
)
// Deploy and initialize the Proxy Messenger
const proxy = await (
await ethers.getContractFactory('Lib_ResolvedDelegateProxy')
).deploy(AddressManager.address, 'L1CrossDomainMessenger')
L1CrossDomainMessenger = xDomainMessengerImpl.attach(proxy.address)
await L1CrossDomainMessenger.initialize(AddressManager.address)
})
// 4 Bridge
let L1ERC20: Contract
let L1StandardBridge: Contract
before('Deploy the bridge and setup the token', async () => {
// Deploy the Bridge
L1StandardBridge = await (
await ethers.getContractFactory('L1StandardBridge')
).deploy()
await L1StandardBridge.initialize(
L1CrossDomainMessenger.address,
NON_ZERO_ADDRESS
)
L1ERC20 = await (
await smoddit('@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20')
).deploy('L1ERC20', 'ERC')
const aliceAddress = await alice.getAddress()
await L1ERC20.smodify.put({
_totalSupply: INITIAL_TOTAL_L1_SUPPLY,
_balances: {
[aliceAddress]: INITIAL_TOTAL_L1_SUPPLY,
},
})
})
describe('[GAS BENCHMARK] L1 to L2 Deposit costs', async () => {
const depositAmount = 1_000
before(async () => {
// Load a transaction into the queue first to 'dirty' the buffer's length slot
await CanonicalTransactionChain.enqueue(
NON_ZERO_ADDRESS,
FINALIZATION_GAS,
'0x1234'
)
})
it('cost to deposit ETH', async () => {
// Alice calls deposit on the bridge and the L1 bridge calls transferFrom on the token.
const res = await L1StandardBridge.connect(alice).depositETH(
FINALIZATION_GAS,
NON_NULL_BYTES32,
{
value: depositAmount,
gasPrice: 0,
}
)
const receipt = await res.wait()
console.log(' - Gas used:', receipt.gasUsed.toNumber())
// Sanity check that the message was enqueued.
expect(await CanonicalTransactionChain.getQueueLength()).to.equal(2)
})
it('cost to deposit an ERC20', async () => {
await L1ERC20.connect(alice).approve(
L1StandardBridge.address,
depositAmount
)
// Alice calls deposit on the bridge and the L1 bridge calls transferFrom on the token.
const res = await L1StandardBridge.connect(alice).depositERC20(
L1ERC20.address,
NON_ZERO_ADDRESS,
depositAmount,
FINALIZATION_GAS,
NON_NULL_BYTES32
)
const receipt = await res.wait()
console.log(' - Gas used:', receipt.gasUsed.toNumber())
// Sanity check that the message was enqueued.
expect(await CanonicalTransactionChain.getQueueLength()).to.equal(3)
})
})
})
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