Skip to content

Commit

Permalink
feat: allow using era's legacy interface for testing (#384)
Browse files Browse the repository at this point in the history
Co-authored-by: Stanislav Breadless <[email protected]>
  • Loading branch information
ly0va and StanislavBreadless authored Apr 22, 2024
1 parent b0c1aa5 commit 06d4311
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 13 deletions.
16 changes: 16 additions & 0 deletions l1-contracts/contracts/dev-contracts/DummyL1ERC20Bridge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

import {L1ERC20Bridge} from "../bridge/L1ERC20Bridge.sol";
import {IL1SharedBridge} from "../bridge/interfaces/IL1SharedBridge.sol";

contract DummyL1ERC20Bridge is L1ERC20Bridge {
constructor(IL1SharedBridge _l1SharedBridge) L1ERC20Bridge(_l1SharedBridge) {}

function setValues(address _l2Bridge, address _l2TokenBeacon, bytes32 _l2TokenProxyBytecodeHash) external {
l2Bridge = _l2Bridge;
l2TokenBeacon = _l2TokenBeacon;
l2TokenProxyBytecodeHash = _l2TokenProxyBytecodeHash;
}
}
70 changes: 67 additions & 3 deletions l1-contracts/scripts/upgrade-shared-bridge-era.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { Deployer } from "../src.ts/deploy";
import { formatUnits, parseUnits, Interface } from "ethers/lib/utils";
import { web3Provider, GAS_MULTIPLIER } from "./utils";
import { deployedAddressesFromEnv } from "../src.ts/deploy-utils";
import { ethTestConfig } from "../src.ts/utils";
import { ethTestConfig, getAddressFromEnv } from "../src.ts/utils";
import { hashL2Bytecode } from "../../l2-contracts/src/utils";
import { Provider } from "zksync-web3";
import beaconProxy = require("../../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json");

const provider = web3Provider();

Expand All @@ -18,7 +21,6 @@ async function main() {

program
.option("--private-key <private-key>")
.option("--chain-id <chain-id>")
.option("--gas-price <gas-price>")
.option("--nonce <nonce>")
.option("--owner-address <owner-address>")
Expand Down Expand Up @@ -57,12 +59,56 @@ async function main() {
await deployer.deploySharedBridgeImplementation(create2Salt, { nonce });

const proxyAdminInterface = new Interface(hardhat.artifacts.readArtifactSync("ProxyAdmin").abi);
const calldata = proxyAdminInterface.encodeFunctionData("upgrade(address,address)", [
let calldata = proxyAdminInterface.encodeFunctionData("upgrade(address,address)", [
deployer.addresses.Bridges.SharedBridgeProxy,
deployer.addresses.Bridges.SharedBridgeImplementation,
]);

await deployer.executeUpgrade(deployer.addresses.TransparentProxyAdmin, 0, calldata);

// deploy a dummy erc20 bridge to set the storage values
await deployer.deployERC20BridgeImplementation(create2Salt, {}, true);

// upgrade to dummy bridge
calldata = proxyAdminInterface.encodeFunctionData("upgrade(address,address)", [
deployer.addresses.Bridges.ERC20BridgeProxy,
deployer.addresses.Bridges.ERC20BridgeImplementation,
]);

await deployer.executeUpgrade(deployer.addresses.TransparentProxyAdmin, 0, calldata);
console.log("Upgraded ERC20Bridge to 'dummy' implementation");

const dummyBridgeAbi = hardhat.artifacts.readArtifactSync("DummyL1ERC20Bridge").abi;
const dummyBridge = new ethers.Contract(
deployer.addresses.Bridges.ERC20BridgeProxy,
dummyBridgeAbi,
deployWallet
);

const l2SharedBridgeAddress = getAddressFromEnv("CONTRACTS_L2_SHARED_BRIDGE_ADDR");
const l2TokenBytecodeHash = hashL2Bytecode(beaconProxy.bytecode);
const l2Provider = new Provider(process.env.API_WEB3_JSON_RPC_HTTP_URL);
// For the server to start up.
console.log("Waiting for server to start up");
await waitForServer(l2Provider);

const l2SharedBridge = new ethers.Contract(
l2SharedBridgeAddress,
["function l2TokenBeacon() view returns (address)"],
l2Provider
);
const l2TokenBeacon = await l2SharedBridge.l2TokenBeacon();

console.log("Retrieved storage values for TestERC20Bridge:");
console.log("l2SharedBridgeAddress:", l2SharedBridgeAddress);
console.log("l2TokenBeacon:", l2TokenBeacon);
console.log("l2TokenBytecodeHash:", ethers.utils.hexlify(l2TokenBytecodeHash));

// set storage values
const tx = await dummyBridge.setValues(l2SharedBridgeAddress, l2TokenBeacon, l2TokenBytecodeHash);
await tx.wait();

console.log("Set storage values for TestERC20Bridge");
});

await program.parseAsync(process.argv);
Expand All @@ -74,3 +120,21 @@ main()
console.error("Error:", err);
process.exit(1);
});

async function waitForServer(provider: Provider) {
let iter = 0;
while (iter < 60) {
try {
await provider.getBlockNumber();
return;
} catch (_) {
await sleep(2);
iter += 1;
}
}
throw new Error("Server didn't start up in time. Exiting.");
}

async function sleep(seconds: number) {
return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}
8 changes: 6 additions & 2 deletions l1-contracts/src.ts/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,14 @@ export class Deployer {
this.addresses.StateTransition.Verifier = contractAddress;
}

public async deployERC20BridgeImplementation(create2Salt: string, ethTxOptions: ethers.providers.TransactionRequest) {
public async deployERC20BridgeImplementation(
create2Salt: string,
ethTxOptions: ethers.providers.TransactionRequest,
dummy: boolean = false
) {
ethTxOptions.gasLimit ??= 10_000_000;
const contractAddress = await this.deployViaCreate2(
"L1ERC20Bridge",
dummy ? "DummyL1ERC20Bridge" : "L1ERC20Bridge",
[this.addresses.Bridges.SharedBridgeProxy],
create2Salt,
ethTxOptions
Expand Down
3 changes: 2 additions & 1 deletion l1-contracts/test/unit_tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ export async function depositERC20(
const neededValue = await bridgehubContract.l2TransactionBaseCost(chainId, gasPrice, l2GasLimit, gasPerPubdata);
const ethIsBaseToken = (await bridgehubContract.baseToken(chainId)) == ADDRESS_ONE;

await bridge["deposit(address,address,uint256,uint256,uint256,address)"](
const deposit = await bridge["deposit(address,address,uint256,uint256,uint256,address)"](
l2Receiver,
l1Token,
amount,
Expand All @@ -391,6 +391,7 @@ export async function depositERC20(
value: ethIsBaseToken ? neededValue : 0,
}
);
await deposit.wait();
}

export function buildL2CanonicalTransaction(tx: Partial<L2CanonicalTransaction>): L2CanonicalTransaction {
Expand Down
3 changes: 2 additions & 1 deletion l1-contracts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"compilerOptions": {
"types": ["node", "mocha"],
"downlevelIteration": true
"downlevelIteration": true,
"resolveJsonModule": true
}
}
23 changes: 17 additions & 6 deletions l2-contracts/src/deploy-shared-bridge-on-l2-through-l1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ export async function publishL2SharedBridgeDependencyBytecodesOnL2(
}
}

export async function deploySharedBridgeImplOnL2ThroughL1(deployer: Deployer, chainId: string, gasPrice: BigNumberish) {
export async function deploySharedBridgeImplOnL2ThroughL1(
deployer: Deployer,
chainId: string,
gasPrice: BigNumberish,
chainIdHack: boolean = false
) {
if (deployer.verbose) {
console.log("Deploying L2SharedBridge Implementation");
}
Expand All @@ -66,7 +71,7 @@ export async function deploySharedBridgeImplOnL2ThroughL1(deployer: Deployer, ch
const l2SharedBridgeImplAddress = computeL2Create2Address(
deployer.deployWallet,
L2_SHARED_BRIDGE_IMPLEMENTATION_BYTECODE,
defaultAbiCoder.encode(["uint256"], [eraChainId]),
defaultAbiCoder.encode(["uint256"], [chainIdHack ? 0 : eraChainId]),
ethers.constants.HashZero
);
deployer.addresses.Bridges.L2SharedBridgeImplementation = l2SharedBridgeImplAddress;
Expand All @@ -84,7 +89,7 @@ export async function deploySharedBridgeImplOnL2ThroughL1(deployer: Deployer, ch
chainId,
deployer.deployWallet,
L2_SHARED_BRIDGE_IMPLEMENTATION_BYTECODE,
defaultAbiCoder.encode(["uint256"], [eraChainId]),
defaultAbiCoder.encode(["uint256"], [chainIdHack ? 0 : eraChainId]),
ethers.constants.HashZero,
priorityTxMaxGasLimit,
gasPrice,
Expand Down Expand Up @@ -174,9 +179,14 @@ export async function initializeChainGovernance(deployer: Deployer, chainId: str
}
}

export async function deploySharedBridgeOnL2ThroughL1(deployer: Deployer, chainId: string, gasPrice: BigNumberish) {
export async function deploySharedBridgeOnL2ThroughL1(
deployer: Deployer,
chainId: string,
gasPrice: BigNumberish,
chainIdHack: boolean = false
) {
await publishL2SharedBridgeDependencyBytecodesOnL2(deployer, chainId, gasPrice);
await deploySharedBridgeImplOnL2ThroughL1(deployer, chainId, gasPrice);
await deploySharedBridgeImplOnL2ThroughL1(deployer, chainId, gasPrice, chainIdHack);
await deploySharedBridgeProxyOnL2ThroughL1(deployer, chainId, gasPrice);
await initializeChainGovernance(deployer, chainId);
}
Expand All @@ -189,6 +199,7 @@ async function main() {
program
.option("--private-key <private-key>")
.option("--chain-id <chain-id>")
.option("--chain-id-hack")
.option("--gas-price <gas-price>")
.option("--nonce <nonce>")
.option("--erc20-bridge <erc20-bridge>")
Expand Down Expand Up @@ -216,7 +227,7 @@ async function main() {
: (await provider.getGasPrice()).mul(GAS_MULTIPLIER);
console.log(`Using gas price: ${formatUnits(gasPrice, "gwei")} gwei`);

await deploySharedBridgeOnL2ThroughL1(deployer, chainId, gasPrice);
await deploySharedBridgeOnL2ThroughL1(deployer, chainId, gasPrice, cmd.chainIdHack);
});

await program.parseAsync(process.argv);
Expand Down

0 comments on commit 06d4311

Please sign in to comment.