Skip to content

Commit

Permalink
add rebasable token e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kovalgek committed Mar 6, 2024
1 parent 66b2501 commit 7badd9e
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 5 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ TESTING_ARB_L2_GATEWAY_ROUTER=0x57f54f87C44d816f60b92864e23b8c0897D4d81D
TESTING_OPT_NETWORK=
TESTING_OPT_L1_TOKEN=0xaF8a2F0aE374b03376155BF745A3421Dac711C12
TESTING_OPT_L2_TOKEN=0xAED5F9aaF167923D34174b8E636aaF040A11f6F7
TESTING_OPT_L1_REBASABLE_TOKEN=0xB82381A3fBD3FaFA77B3a7bE693342618240067b
TESTING_OPT_L2_REBASABLE_TOKEN=0x6696Cb7bb602FC744254Ad9E07EfC474FBF78857
TESTING_OPT_L2_TOKEN_RATE_ORACLE=0x8ea513d1e5Be31fb5FC2f2971897594720de9E70
TESTING_OPT_L1_ERC20_TOKEN_BRIDGE=0x243b661276670bD17399C488E7287ea4D416115b
TESTING_OPT_L2_ERC20_TOKEN_BRIDGE=0x447CD1794d209Ac4E6B4097B34658bc00C4d0a51

Expand Down
152 changes: 152 additions & 0 deletions test/optimism/bridging-rebasable.e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import {
CrossChainMessenger,
MessageStatus,
} from "@eth-optimism/sdk";
import { assert } from "chai";
import { TransactionResponse } from "@ethersproject/providers";

import env from "../../utils/env";
import { wei } from "../../utils/wei";
import network from "../../utils/network";
import optimism from "../../utils/optimism";
import { ERC20Mintable } from "../../typechain";
import { scenario } from "../../utils/testing";
import { sleep } from "../../utils/testing/e2e";
import { LidoBridgeAdapter } from "../../utils/optimism/LidoBridgeAdapter";

let depositTokensTxResponse: TransactionResponse;
let withdrawTokensTxResponse: TransactionResponse;

scenario("Optimism :: Bridging via deposit/withdraw E2E test", ctxFactory)
.step(
"Validate tester has required amount of L1 token",
async ({ l1TokenRebasable, l1Tester, depositAmount }) => {
const balanceBefore = await l1TokenRebasable.balanceOf(l1Tester.address);
if (balanceBefore.lt(depositAmount)) {
try {
await (l1TokenRebasable as ERC20Mintable).mint(
l1Tester.address,
depositAmount
);
} catch {}
const balanceAfter = await l1TokenRebasable.balanceOf(l1Tester.address);
assert.isTrue(
balanceAfter.gte(depositAmount),
"Tester has not enough L1 token"
);
}
}
)

.step("Set allowance for L1LidoTokensBridge to deposit", async (ctx) => {
const allowanceTxResponse = await ctx.crossChainMessenger.approveERC20(
ctx.l1TokenRebasable.address,
ctx.l2TokenRebasable.address,
ctx.depositAmount
);

await allowanceTxResponse.wait();

assert.equalBN(
await ctx.l1TokenRebasable.allowance(
ctx.l1Tester.address,
ctx.l1LidoTokensBridge.address
),
ctx.depositAmount
);
})

.step("Bridge tokens to L2 via depositERC20()", async (ctx) => {
depositTokensTxResponse = await ctx.crossChainMessenger.depositERC20(
ctx.l1TokenRebasable.address,
ctx.l2TokenRebasable.address,
ctx.depositAmount
);
await depositTokensTxResponse.wait();
})

.step("Waiting for status to change to RELAYED", async (ctx) => {
await ctx.crossChainMessenger.waitForMessageStatus(
depositTokensTxResponse.hash,
MessageStatus.RELAYED
);
})

.step("Withdraw tokens from L2 via withdrawERC20()", async (ctx) => {
withdrawTokensTxResponse = await ctx.crossChainMessenger.withdrawERC20(
ctx.l1TokenRebasable.address,
ctx.l2TokenRebasable.address,
ctx.withdrawalAmount
);
await withdrawTokensTxResponse.wait();
})

.step("Waiting for status to change to READY_TO_PROVE", async (ctx) => {
await ctx.crossChainMessenger.waitForMessageStatus(
withdrawTokensTxResponse.hash,
MessageStatus.READY_TO_PROVE
);
})

.step("Proving the L2 -> L1 message", async (ctx) => {
const tx = await ctx.crossChainMessenger.proveMessage(
withdrawTokensTxResponse.hash
);
await tx.wait();
})

.step("Waiting for status to change to IN_CHALLENGE_PERIOD", async (ctx) => {
await ctx.crossChainMessenger.waitForMessageStatus(
withdrawTokensTxResponse.hash,
MessageStatus.IN_CHALLENGE_PERIOD
);
})

.step("Waiting for status to change to READY_FOR_RELAY", async (ctx) => {
await ctx.crossChainMessenger.waitForMessageStatus(
withdrawTokensTxResponse.hash,
MessageStatus.READY_FOR_RELAY
);
})

.step("Finalizing L2 -> L1 message", async (ctx) => {
const finalizationPeriod = await ctx.crossChainMessenger.contracts.l1.L2OutputOracle.FINALIZATION_PERIOD_SECONDS();
await sleep(finalizationPeriod * 1000);
await ctx.crossChainMessenger.finalizeMessage(withdrawTokensTxResponse);
})

.step("Waiting for status to change to RELAYED", async (ctx) => {
await ctx.crossChainMessenger.waitForMessageStatus(
withdrawTokensTxResponse,
MessageStatus.RELAYED
);
})

.run();

async function ctxFactory() {
const networkName = env.network("TESTING_OPT_NETWORK", "sepolia");
const testingSetup = await optimism.testing(networkName).getE2ETestSetup();

return {
depositAmount: wei`0.0025 ether`,
withdrawalAmount: wei`0.0025 ether`,
l1Tester: testingSetup.l1Tester,
l1TokenRebasable: testingSetup.l1TokenRebasable,
l2TokenRebasable: testingSetup.l2TokenRebasable,
l1LidoTokensBridge: testingSetup.l1LidoTokensBridge,
crossChainMessenger: new CrossChainMessenger({
l2ChainId: network.chainId("opt", networkName),
l1ChainId: network.chainId("eth", networkName),
l1SignerOrProvider: testingSetup.l1Tester,
l2SignerOrProvider: testingSetup.l2Tester,
bridges: {
LidoBridge: {
Adapter: LidoBridgeAdapter,
l1Bridge: testingSetup.l1LidoTokensBridge.address,
l2Bridge: testingSetup.l2ERC20TokenBridge.address,
},
},
}),
};
}
43 changes: 39 additions & 4 deletions utils/optimism/LidoBridgeAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,48 @@ export class LidoBridgeAdapter extends StandardBridgeAdapter {
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'L1_TOKEN_REBASABLE',
outputs: [
{
internalType: 'address',
name: '',
type: 'address',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'L2_TOKEN_REBASABLE',
outputs: [
{
internalType: 'address',
name: '',
type: 'address',
},
],
stateMutability: 'view',
type: 'function',
},
], this.messenger.l1Provider);
const allowedL1Token = await l1Bridge.L1_TOKEN_NON_REBASABLE();
if (!(0, hexStringEquals)(allowedL1Token, (0, toAddress)(l1Token))) {

const allowedL1RebasableToken = await l1Bridge.L1_TOKEN_REBASABLE();
const allowedL1NonRebasableToken = await l1Bridge.L1_TOKEN_NON_REBASABLE();

if ((!(0, hexStringEquals)(allowedL1RebasableToken, (0, toAddress)(l1Token))) &&
(!(0, hexStringEquals)(allowedL1NonRebasableToken, (0, toAddress)(l1Token))))
{
return false;
}
const allowedL2Token = await l1Bridge.L2_TOKEN_NON_REBASABLE();
if (!(0, hexStringEquals)(allowedL2Token, (0, toAddress)(l2Token))) {

const allowedL2RebasableToken = await l1Bridge.L2_TOKEN_REBASABLE();
const allowedL2NonRebasableToken = await l1Bridge.L2_TOKEN_NON_REBASABLE();

if ((!(0, hexStringEquals)(allowedL2RebasableToken, (0, toAddress)(l2Token))) &&
(!(0, hexStringEquals)(allowedL2NonRebasableToken, (0, toAddress)(l2Token)))) {
return false;
}
return true;
Expand Down
2 changes: 1 addition & 1 deletion utils/optimism/testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ async function loadDeployedBridges(
l1SignerOrProvider
),
l1TokenRebasable: IERC20__factory.connect(
testingUtils.env.OPT_L1_TOKEN(),
testingUtils.env.OPT_L1_REBASABLE_TOKEN(),
l1SignerOrProvider
),

Expand Down
9 changes: 9 additions & 0 deletions utils/testing/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ export default {
OPT_L2_TOKEN() {
return env.address("TESTING_OPT_L2_TOKEN");
},
OPT_L2_TOKEN_RATE_ORACLE() {
return env.address("TESTING_OPT_L2_TOKEN_RATE_ORACLE");
},
OPT_L1_REBASABLE_TOKEN() {
return env.address("TESTING_OPT_L1_REBASABLE_TOKEN");
},
OPT_L2_REBASABLE_TOKEN() {
return env.address("TESTING_OPT_L2_REBASABLE_TOKEN");
},
OPT_L1_ERC20_TOKEN_BRIDGE() {
return env.address("TESTING_OPT_L1_ERC20_TOKEN_BRIDGE");
},
Expand Down

0 comments on commit 7badd9e

Please sign in to comment.