Skip to content

Commit

Permalink
fix: provide updated manual deposit for both ETH and non-ETH chains (#…
Browse files Browse the repository at this point in the history
…1808)

## What ❔

Updated manual deposit for rich accounts to account for Bridgehub
changes.
Added support for non-ETH based chains.

## Why ❔

Old API is no longer supported by the bridgehub.

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [x] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [ ] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated.
- [x] Code has been formatted via `zk fmt` and `zk lint`.
- [ ] Spellcheck has been run via `zk spellcheck`.
- [ ] Linkcheck has been run via `zk linkcheck`.

---------

Co-authored-by: Raid Ateir <ra@matterlabs.dev>
  • Loading branch information
Raid5594 and Raid Ateir authored May 2, 2024
1 parent fde85f4 commit 1d3e7a6
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 26 deletions.
69 changes: 43 additions & 26 deletions infrastructure/local-setup-preparation/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { utils } from 'zksync-ethers';
import { ethers } from 'ethers';
import { getEthersProvider, getWalletKeys } from './utils';
import { getEthersProvider, getWalletKeys, isOperator } from './utils';

// 10**12 ether
const AMOUNT_TO_DEPOSIT = ethers.utils.parseEther('1000000000000');
const CALLDATA = '0x';

async function depositWithRichAccounts() {
const ethProvider = getEthersProvider();

const chainId = process.env.CHAIN_ETH_ZKSYNC_NETWORK_ID!;
const wallets = getWalletKeys().map((wk) => new ethers.Wallet(wk.privateKey, ethProvider));
const isEthBasedChain = process.env.CONTRACTS_BASE_TOKEN_ADDR === utils.ETH_ADDRESS_IN_CONTRACTS;

const handles: Promise<any>[] = [];

Expand All @@ -31,34 +33,49 @@ async function depositWithRichAccounts() {
);

for (const wallet of wallets) {
const contract = new ethers.Contract(process.env.CONTRACTS_BRIDGEHUB_PROXY_ADDR, utils.BRIDGEHUB_ABI, wallet);
if (!(await isOperator(chainId, wallet.address))) {
const contract = new ethers.Contract(
process.env.CONTRACTS_BRIDGEHUB_PROXY_ADDR,
utils.BRIDGEHUB_ABI,
wallet
);

const overrides = {
// TODO(EVM-565): expected cost calculation seems to be off, understand why and then remove the second add.
value: AMOUNT_TO_DEPOSIT.add(expectedCost).add(expectedCost)
};
const overrides = {
value: AMOUNT_TO_DEPOSIT.add(expectedCost)
};

const balance = await wallet.getBalance();
console.log(`Wallet ${wallet.address} balance is ${ethers.utils.formatEther(balance)} ETH`);
if (!isEthBasedChain) {
const baseTokenContract = new ethers.Contract(
process.env.CONTRACTS_BASE_TOKEN_ADDR,
utils.IERC20,
wallet
);
const sharedBridge = await contract.sharedBridge();
await (await baseTokenContract.approve(sharedBridge, ethers.constants.MaxUint256)).wait();
const l1Erc20ABI = ['function mint(address to, uint256 amount)'];
const l1Erc20Contract = new ethers.Contract(baseTokenContract.address, l1Erc20ABI, wallet);
await (await l1Erc20Contract.mint(wallet.address, AMOUNT_TO_DEPOSIT.mul(2))).wait();
}

// TODO: Currently we're providing zero as an operator fee, which works right now,
// but will be changed in the future.
handles.push(
// We have to implement the deposit manually because we run this script before running the server,
// deposit method from wallet requires a running server
// TODO(EVM-566): this is broken - as BRIDGEHUB no longer exposes 'requestL2transaction'
contract.requestL2Transaction(
chainId,
wallet.address,
AMOUNT_TO_DEPOSIT,
'0x',
DEPOSIT_L2_GAS_LIMIT,
utils.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT,
[],
wallet.address,
overrides
)
);
handles.push(
// We have to implement the deposit manually because we run this script before running the server,
// deposit method from wallet requires a running server
contract.requestL2TransactionDirect(
{
chainId,
mintValue: overrides.value,
l2Contract: wallet.address,
l2Value: AMOUNT_TO_DEPOSIT,
l2Calldata: CALLDATA,
l2GasLimit: DEPOSIT_L2_GAS_LIMIT,
l2GasPerPubdataByteLimit: utils.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT,
factoryDeps: [],
refundRecipient: wallet.address
},
isEthBasedChain ? overrides : {}
)
);
}
}

const depositHandles = (await Promise.all(handles)).map((h) => h.wait());
Expand Down
50 changes: 50 additions & 0 deletions infrastructure/local-setup-preparation/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,62 @@
import { utils } from 'zksync-ethers';
import { ethers } from 'ethers';
import * as fs from 'fs';
import * as path from 'path';
import { ValidatorTimelockFactory } from '../../../contracts/l1-contracts/typechain/ValidatorTimelockFactory';
import { StateTransitionManagerFactory } from '../../../contracts/l1-contracts/typechain/StateTransitionManagerFactory';

interface WalletKey {
address: string;
privateKey: string;
}

// Cache object for storing contract instances
const contractCache = {
contractMain: null,
stm: null,
validatorTimelock: null
};

// Function to get contract instances
async function getContractInstances() {
const ethProvider = getEthersProvider();

if (!contractCache.contractMain) {
contractCache.contractMain = new ethers.Contract(
process.env.CONTRACTS_DIAMOND_PROXY_ADDR,
utils.ZKSYNC_MAIN_ABI,
ethProvider
);
}

if (!contractCache.stm) {
const stateTransitionManagerAddr = await contractCache.contractMain.getStateTransitionManager();
contractCache.stm = StateTransitionManagerFactory.connect(stateTransitionManagerAddr, ethProvider);
}

if (!contractCache.validatorTimelock) {
const validatorTimelockAddr = await contractCache.stm.validatorTimelock();
contractCache.validatorTimelock = ValidatorTimelockFactory.connect(validatorTimelockAddr, ethProvider);
}

return {
contractMain: contractCache.contractMain,
stm: contractCache.stm,
validatorTimelock: contractCache.validatorTimelock
};
}

export async function isOperator(chainId: string, walletAddress: string): Promise<boolean> {
try {
const { validatorTimelock } = await getContractInstances();
const isOperator = await validatorTimelock.validators(chainId, walletAddress);
return isOperator;
} catch (error) {
console.error('Error checking if address is an operator:', error);
throw error;
}
}

export function getWalletKeys(): WalletKey[] {
const testConfigPath = path.join(process.env.ZKSYNC_HOME as string, `etc/test_config/constant`);
const ethTestConfig = JSON.parse(fs.readFileSync(`${testConfigPath}/eth.json`, { encoding: 'utf-8' }));
Expand Down

0 comments on commit 1d3e7a6

Please sign in to comment.