Commit 748c04ab authored by Kelvin Fichter's avatar Kelvin Fichter

feat: use SDK for bridge integration tests

parent f08c06a8
---
'@eth-optimism/integration-tests': patch
---
Updates integration tests to use the SDK for bridged token tests
...@@ -4,9 +4,11 @@ pragma solidity ^0.8.9; ...@@ -4,9 +4,11 @@ pragma solidity ^0.8.9;
contract FakeL2StandardERC20 { contract FakeL2StandardERC20 {
address public immutable l1Token; address public immutable l1Token;
address public immutable l2Bridge;
constructor(address _l1Token) { constructor(address _l1Token, address _l2Bridge) {
l1Token = _l1Token; l1Token = _l1Token;
l2Bridge = _l2Bridge;
} }
// Burn will be called by the L2 Bridge to burn the tokens we are bridging to L1 // Burn will be called by the L2 Bridge to burn the tokens we are bridging to L1
......
...@@ -118,7 +118,6 @@ describe('Basic L1<>L2 Communication', async () => { ...@@ -118,7 +118,6 @@ describe('Basic L1<>L2 Communication', async () => {
const receipt = await env.messenger.waitForMessageReceipt(transaction) const receipt = await env.messenger.waitForMessageReceipt(transaction)
console.log(await env.messenger.l2Signer.getAddress())
expect(receipt.transactionReceipt.status).to.equal(1) expect(receipt.transactionReceipt.status).to.equal(1)
expect(await L2SimpleStorage.msgSender()).to.equal( expect(await L2SimpleStorage.msgSender()).to.equal(
env.messenger.contracts.l2.L2CrossDomainMessenger.address env.messenger.contracts.l2.L2CrossDomainMessenger.address
......
import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers' import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers'
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import * as L2Artifact from '@eth-optimism/contracts/artifacts/contracts/standards/L2StandardERC20.sol/L2StandardERC20.json' import { getContractFactory } from '@eth-optimism/contracts'
import { MessageStatus } from '@eth-optimism/sdk'
import { sleep } from '@eth-optimism/core-utils'
import { expect } from './shared/setup' import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
import { withdrawalTest } from './shared/utils' import { withdrawalTest } from './shared/utils'
import { Direction } from './shared/watcher-utils'
describe('Bridged tokens', () => { describe('Bridged tokens', () => {
let env: OptimismEnv let env: OptimismEnv
before(async () => {
env = await OptimismEnv.new()
})
let otherWalletL1: Wallet let otherWalletL1: Wallet
let otherWalletL2: Wallet let otherWalletL2: Wallet
let L1Factory__ERC20: ContractFactory
let L1__ERC20: Contract
let L2Factory__ERC20: ContractFactory
let L2__ERC20: Contract
before(async () => { before(async () => {
env = await OptimismEnv.new()
const other = Wallet.createRandom() const other = Wallet.createRandom()
otherWalletL1 = other.connect(env.l1Wallet.provider) otherWalletL1 = other.connect(env.l1Wallet.provider)
otherWalletL2 = other.connect(env.l2Wallet.provider) otherWalletL2 = other.connect(env.l2Wallet.provider)
let tx = await env.l1Wallet.sendTransaction({
const tx1 = await env.l1Wallet.sendTransaction({
to: otherWalletL1.address, to: otherWalletL1.address,
value: utils.parseEther('0.01'), value: utils.parseEther('0.01'),
}) })
await tx.wait() await tx1.wait()
tx = await env.l2Wallet.sendTransaction({ const tx2 = await env.l2Wallet.sendTransaction({
to: otherWalletL2.address, to: otherWalletL2.address,
value: utils.parseEther('0.01'), value: utils.parseEther('0.01'),
}) })
await tx.wait() await tx2.wait()
})
let L1Factory__ERC20: ContractFactory
let L2Factory__ERC20: ContractFactory
before(async () => {
L1Factory__ERC20 = await ethers.getContractFactory('ERC20', env.l1Wallet) L1Factory__ERC20 = await ethers.getContractFactory('ERC20', env.l1Wallet)
L2Factory__ERC20 = new ethers.ContractFactory( L2Factory__ERC20 = getContractFactory('L2StandardERC20', env.l2Wallet)
L2Artifact.abi,
L2Artifact.bytecode
)
L2Factory__ERC20 = L2Factory__ERC20.connect(env.l2Wallet)
}) })
it('should deploy an ERC20 on L1', async () => { // This is one of the only stateful integration tests in which we don't set up a new contract
// before each test. We do this because the test is more of an "actor-based" test where we're
// going through a series of actions and confirming that the actions are performed correctly at
// every step.
let L1__ERC20: Contract
let L2__ERC20: Contract
before(async () => {
// Deploy the L1 ERC20
L1__ERC20 = await L1Factory__ERC20.deploy(1000000, 'OVM Test', 8, 'OVM') L1__ERC20 = await L1Factory__ERC20.deploy(1000000, 'OVM Test', 8, 'OVM')
await L1__ERC20.deployed() await L1__ERC20.deployed()
})
it('should deploy a paired token on L2', async () => { // Deploy the L2 ERC20
L2__ERC20 = await L2Factory__ERC20.deploy( L2__ERC20 = await L2Factory__ERC20.deploy(
'0x4200000000000000000000000000000000000010', '0x4200000000000000000000000000000000000010',
L1__ERC20.address, L1__ERC20.address,
...@@ -56,22 +59,21 @@ describe('Bridged tokens', () => { ...@@ -56,22 +59,21 @@ describe('Bridged tokens', () => {
'OVM' 'OVM'
) )
await L2__ERC20.deployed() await L2__ERC20.deployed()
})
it('should approve the bridge', async () => { // Approve the L1 ERC20 to spend our money
const tx = await L1__ERC20.approve(env.l1Bridge.address, 1000000) const tx = await L1__ERC20.approve(env.l1Bridge.address, 1000000)
await tx.wait() await tx.wait()
}) })
it('should deposit tokens into L2', async () => { it('should deposit tokens into L2', async () => {
const tx = await env.l1Bridge.depositERC20( await env.messenger.waitForMessageReceipt(
L1__ERC20.address, await env.messenger.depositERC20(
L2__ERC20.address, L1__ERC20.address,
1000, L2__ERC20.address,
2000000, 1000
'0x' )
) )
await env.waitForXDomainTransaction(tx, Direction.L1ToL2)
expect(await L1__ERC20.balanceOf(env.l1Wallet.address)).to.deep.equal( expect(await L1__ERC20.balanceOf(env.l1Wallet.address)).to.deep.equal(
BigNumber.from(999000) BigNumber.from(999000)
) )
...@@ -83,6 +85,7 @@ describe('Bridged tokens', () => { ...@@ -83,6 +85,7 @@ describe('Bridged tokens', () => {
it('should transfer tokens on L2', async () => { it('should transfer tokens on L2', async () => {
const tx = await L2__ERC20.transfer(otherWalletL1.address, 500) const tx = await L2__ERC20.transfer(otherWalletL1.address, 500)
await tx.wait() await tx.wait()
expect(await L2__ERC20.balanceOf(env.l2Wallet.address)).to.deep.equal( expect(await L2__ERC20.balanceOf(env.l2Wallet.address)).to.deep.equal(
BigNumber.from(500) BigNumber.from(500)
) )
...@@ -94,14 +97,22 @@ describe('Bridged tokens', () => { ...@@ -94,14 +97,22 @@ describe('Bridged tokens', () => {
withdrawalTest( withdrawalTest(
'should withdraw tokens from L2 to the depositor', 'should withdraw tokens from L2 to the depositor',
async () => { async () => {
const tx = await env.l2Bridge.withdraw( const tx = await env.messenger.withdrawERC20(
L1__ERC20.address,
L2__ERC20.address, L2__ERC20.address,
500, 500
2000000,
'0x'
) )
await env.relayXDomainMessages(tx)
await env.waitForXDomainTransaction(tx, Direction.L2ToL1) // TODO: Maybe this should be built into the SDK
let status: MessageStatus
while (status !== MessageStatus.READY_FOR_RELAY) {
status = await env.messenger.getMessageStatus(tx)
await sleep(1000)
}
await env.messenger.finalizeMessage(tx)
await env.messenger.waitForMessageReceipt(tx)
expect(await L1__ERC20.balanceOf(env.l1Wallet.address)).to.deep.equal( expect(await L1__ERC20.balanceOf(env.l1Wallet.address)).to.deep.equal(
BigNumber.from(999500) BigNumber.from(999500)
) )
...@@ -114,11 +125,25 @@ describe('Bridged tokens', () => { ...@@ -114,11 +125,25 @@ describe('Bridged tokens', () => {
withdrawalTest( withdrawalTest(
'should withdraw tokens from L2 to the transfer recipient', 'should withdraw tokens from L2 to the transfer recipient',
async () => { async () => {
const tx = await env.l2Bridge const tx = await env.messenger.withdrawERC20(
.connect(otherWalletL2) L1__ERC20.address,
.withdraw(L2__ERC20.address, 500, 2000000, '0x') L2__ERC20.address,
await env.relayXDomainMessages(tx) 500,
await env.waitForXDomainTransaction(tx, Direction.L2ToL1) {
signer: otherWalletL2,
}
)
// TODO: Maybe this should be built into the SDK
let status: MessageStatus
while (status !== MessageStatus.READY_FOR_RELAY) {
status = await env.messenger.getMessageStatus(tx)
await sleep(1000)
}
await env.messenger.finalizeMessage(tx)
await env.messenger.waitForMessageReceipt(tx)
expect(await L1__ERC20.balanceOf(otherWalletL1.address)).to.deep.equal( expect(await L1__ERC20.balanceOf(otherWalletL1.address)).to.deep.equal(
BigNumber.from(500) BigNumber.from(500)
) )
...@@ -134,46 +159,52 @@ describe('Bridged tokens', () => { ...@@ -134,46 +159,52 @@ describe('Bridged tokens', () => {
withdrawalTest( withdrawalTest(
'should not allow an arbitrary L2 token to be withdrawn in exchange for a legitimate L1 token', 'should not allow an arbitrary L2 token to be withdrawn in exchange for a legitimate L1 token',
async () => { async () => {
before(async () => { // First deposit some of the L1 token to L2, so that there is something which could be stolen.
// First deposit some of the L1 token to L2, so that there is something which could be stolen. await env.messenger.waitForMessageReceipt(
const depositTx = await env.l1Bridge await env.messenger.depositERC20(
.connect(env.l1Wallet) L1__ERC20.address,
.depositERC20( L2__ERC20.address,
L1__ERC20.address, 1000
L2__ERC20.address,
1000,
2000000,
'0x'
)
await env.waitForXDomainTransaction(depositTx, Direction.L1ToL2)
expect(await L2__ERC20.balanceOf(env.l2Wallet.address)).to.deep.equal(
BigNumber.from(1000)
) )
}) )
expect(await L2__ERC20.balanceOf(env.l2Wallet.address)).to.deep.equal(
BigNumber.from(1000)
)
// Deploy a Fake L2 token, which: // Deploy a Fake L2 token, which:
// - returns the address of a legitimate L1 token from its l1Token() getter. // - returns the address of a legitimate L1 token from its l1Token() getter.
// - allows the L2 bridge to call its burn() function. // - allows the L2 bridge to call its burn() function.
const fakeToken = await ( const fakeToken = await (
await ethers.getContractFactory('FakeL2StandardERC20', env.l2Wallet) await ethers.getContractFactory('FakeL2StandardERC20', env.l2Wallet)
).deploy(L1__ERC20.address) ).deploy(
L1__ERC20.address,
env.messenger.contracts.l2.L2StandardBridge.address
)
await fakeToken.deployed() await fakeToken.deployed()
const balBefore = await L1__ERC20.balanceOf(otherWalletL1.address) const balBefore = await L1__ERC20.balanceOf(otherWalletL1.address)
// Withdraw some of the Fake L2 token, hoping to receive the same amount of the legitimate // Withdraw some of the Fake L2 token, hoping to receive the same amount of the legitimate
// token on L1. // token on L1.
const withdrawalTx = await env.l2Bridge const withdrawalTx = await env.messenger.withdrawERC20(
.connect(otherWalletL2) L1__ERC20.address,
.withdrawTo( fakeToken.address,
fakeToken.address, 500,
otherWalletL1.address, {
500, signer: otherWalletL2,
1_000_000, }
'0x' )
)
await env.relayXDomainMessages(withdrawalTx) // TODO: Maybe this should be built into the SDK
await env.waitForXDomainTransaction(withdrawalTx, Direction.L2ToL1) let status: MessageStatus
while (status !== MessageStatus.READY_FOR_RELAY) {
status = await env.messenger.getMessageStatus(withdrawalTx)
await sleep(1000)
}
await env.messenger.finalizeMessage(withdrawalTx)
await env.messenger.waitForMessageReceipt(withdrawalTx)
// Ensure that the L1 recipient address has not received any additional L1 token balance. // Ensure that the L1 recipient address has not received any additional L1 token balance.
expect(await L1__ERC20.balanceOf(otherWalletL1.address)).to.deep.equal( expect(await L1__ERC20.balanceOf(otherWalletL1.address)).to.deep.equal(
......
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