Commit c826fddb authored by smartcontracts's avatar smartcontracts Committed by GitHub

Merge pull request #2152 from ethereum-optimism/sc/sdk-integration-2

feat: use SDK for bridge integration tests
parents fd6f47d3 748c04ab
---
'@eth-optimism/sdk': patch
---
Updates the SDK to include default bridges for the local Optimism network (31337)
---
'@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;
contract FakeL2StandardERC20 {
address public immutable l1Token;
address public immutable l2Bridge;
constructor(address _l1Token) {
constructor(address _l1Token, address _l2Bridge) {
l1Token = _l1Token;
l2Bridge = _l2Bridge;
}
// 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 () => {
const receipt = await env.messenger.waitForMessageReceipt(transaction)
console.log(await env.messenger.l2Signer.getAddress())
expect(receipt.transactionReceipt.status).to.equal(1)
expect(await L2SimpleStorage.msgSender()).to.equal(
env.messenger.contracts.l2.L2CrossDomainMessenger.address
......
import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers'
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 { OptimismEnv } from './shared/env'
import { withdrawalTest } from './shared/utils'
import { Direction } from './shared/watcher-utils'
describe('Bridged tokens', () => {
let env: OptimismEnv
before(async () => {
env = await OptimismEnv.new()
})
let otherWalletL1: Wallet
let otherWalletL2: Wallet
let L1Factory__ERC20: ContractFactory
let L1__ERC20: Contract
let L2Factory__ERC20: ContractFactory
let L2__ERC20: Contract
before(async () => {
env = await OptimismEnv.new()
const other = Wallet.createRandom()
otherWalletL1 = other.connect(env.l1Wallet.provider)
otherWalletL2 = other.connect(env.l2Wallet.provider)
let tx = await env.l1Wallet.sendTransaction({
const tx1 = await env.l1Wallet.sendTransaction({
to: otherWalletL1.address,
value: utils.parseEther('0.01'),
})
await tx.wait()
tx = await env.l2Wallet.sendTransaction({
await tx1.wait()
const tx2 = await env.l2Wallet.sendTransaction({
to: otherWalletL2.address,
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)
L2Factory__ERC20 = new ethers.ContractFactory(
L2Artifact.abi,
L2Artifact.bytecode
)
L2Factory__ERC20 = L2Factory__ERC20.connect(env.l2Wallet)
L2Factory__ERC20 = getContractFactory('L2StandardERC20', 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')
await L1__ERC20.deployed()
})
it('should deploy a paired token on L2', async () => {
// Deploy the L2 ERC20
L2__ERC20 = await L2Factory__ERC20.deploy(
'0x4200000000000000000000000000000000000010',
L1__ERC20.address,
......@@ -56,22 +59,21 @@ describe('Bridged tokens', () => {
'OVM'
)
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)
await tx.wait()
})
it('should deposit tokens into L2', async () => {
const tx = await env.l1Bridge.depositERC20(
L1__ERC20.address,
L2__ERC20.address,
1000,
2000000,
'0x'
await env.messenger.waitForMessageReceipt(
await env.messenger.depositERC20(
L1__ERC20.address,
L2__ERC20.address,
1000
)
)
await env.waitForXDomainTransaction(tx, Direction.L1ToL2)
expect(await L1__ERC20.balanceOf(env.l1Wallet.address)).to.deep.equal(
BigNumber.from(999000)
)
......@@ -83,6 +85,7 @@ describe('Bridged tokens', () => {
it('should transfer tokens on L2', async () => {
const tx = await L2__ERC20.transfer(otherWalletL1.address, 500)
await tx.wait()
expect(await L2__ERC20.balanceOf(env.l2Wallet.address)).to.deep.equal(
BigNumber.from(500)
)
......@@ -94,14 +97,22 @@ describe('Bridged tokens', () => {
withdrawalTest(
'should withdraw tokens from L2 to the depositor',
async () => {
const tx = await env.l2Bridge.withdraw(
const tx = await env.messenger.withdrawERC20(
L1__ERC20.address,
L2__ERC20.address,
500,
2000000,
'0x'
500
)
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(
BigNumber.from(999500)
)
......@@ -114,11 +125,25 @@ describe('Bridged tokens', () => {
withdrawalTest(
'should withdraw tokens from L2 to the transfer recipient',
async () => {
const tx = await env.l2Bridge
.connect(otherWalletL2)
.withdraw(L2__ERC20.address, 500, 2000000, '0x')
await env.relayXDomainMessages(tx)
await env.waitForXDomainTransaction(tx, Direction.L2ToL1)
const tx = await env.messenger.withdrawERC20(
L1__ERC20.address,
L2__ERC20.address,
500,
{
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(
BigNumber.from(500)
)
......@@ -134,46 +159,52 @@ describe('Bridged tokens', () => {
withdrawalTest(
'should not allow an arbitrary L2 token to be withdrawn in exchange for a legitimate L1 token',
async () => {
before(async () => {
// First deposit some of the L1 token to L2, so that there is something which could be stolen.
const depositTx = await env.l1Bridge
.connect(env.l1Wallet)
.depositERC20(
L1__ERC20.address,
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)
// First deposit some of the L1 token to L2, so that there is something which could be stolen.
await env.messenger.waitForMessageReceipt(
await env.messenger.depositERC20(
L1__ERC20.address,
L2__ERC20.address,
1000
)
})
)
expect(await L2__ERC20.balanceOf(env.l2Wallet.address)).to.deep.equal(
BigNumber.from(1000)
)
// Deploy a Fake L2 token, which:
// - returns the address of a legitimate L1 token from its l1Token() getter.
// - allows the L2 bridge to call its burn() function.
const fakeToken = await (
await ethers.getContractFactory('FakeL2StandardERC20', env.l2Wallet)
).deploy(L1__ERC20.address)
).deploy(
L1__ERC20.address,
env.messenger.contracts.l2.L2StandardBridge.address
)
await fakeToken.deployed()
const balBefore = await L1__ERC20.balanceOf(otherWalletL1.address)
// Withdraw some of the Fake L2 token, hoping to receive the same amount of the legitimate
// token on L1.
const withdrawalTx = await env.l2Bridge
.connect(otherWalletL2)
.withdrawTo(
fakeToken.address,
otherWalletL1.address,
500,
1_000_000,
'0x'
)
await env.relayXDomainMessages(withdrawalTx)
await env.waitForXDomainTransaction(withdrawalTx, Direction.L2ToL1)
const withdrawalTx = await env.messenger.withdrawERC20(
L1__ERC20.address,
fakeToken.address,
500,
{
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(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.
expect(await L1__ERC20.balanceOf(otherWalletL1.address)).to.deep.equal(
......
......@@ -172,6 +172,18 @@ export const BRIDGE_ADAPTER_DATA: {
l2Bridge: predeploys.L2StandardBridge,
},
},
31337: {
Standard: {
Adapter: StandardBridgeAdapter,
l1Bridge: CONTRACT_ADDRESSES[31337].l1.L1StandardBridge,
l2Bridge: predeploys.L2StandardBridge,
},
ETH: {
Adapter: ETHBridgeAdapter,
l1Bridge: CONTRACT_ADDRESSES[31337].l1.L1StandardBridge,
l2Bridge: predeploys.L2StandardBridge,
},
},
}
// TODO: PR is big enough as-is, will add support for SNX in another PR
......
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