Skip to content
This repository has been archived by the owner on Jul 3, 2024. It is now read-only.

BUG: ERC-20 deposit / bridge fails to execute #2

Open
3 tasks done
dutterbutter opened this issue Sep 18, 2023 · 3 comments
Open
3 tasks done

BUG: ERC-20 deposit / bridge fails to execute #2

dutterbutter opened this issue Sep 18, 2023 · 3 comments
Labels
bug Something isn't working ethers-v5

Comments

@dutterbutter
Copy link

dutterbutter commented Sep 18, 2023

Description:

When using the zksync-web3 SDK to deposit or bridge funds using ERC-20 tokens, the transaction hangs and fails to execute.

Steps to Reproduce:

1. Scaffold a new project

mkdir deposit-erc20-script && cd deposit-erc20-script
npm init -y 
npm i typescript ts-node ethers@^5.7.2 zksync-web3 dotenv

2. Include the .env file at the project root

Create a .env file in the project root containing your private key and the L1 RPC endpoint.

WALLET_PRIV_KEY=<YOUR_PRIVATE_KEY>
L1_RPC_ENDPOINT=<RPC_URL>

3. Create the deposit ERC-20 tokens script

Click to expand for code snippet!
import { Wallet, Provider, utils } from "zksync-web3";
import * as ethers from "ethers";

// load env file
import dotenv from "dotenv";
dotenv.config();

// HTTP RPC endpoints
const L1_RPC_ENDPOINT = process.env.L1_RPC_ENDPOINT || "";  // or an RPC endpoint from Infura/Chainstack/QuickNode/etc.
const L2_RPC_ENDPOINT = process.env.L2_RPC_ENDPOINT || "https://testnet.era.zksync.dev"; // or the zkSync Era mainnet 

// ERC-20 Token address in L1
const TOKEN_ADDRESS = "<TOKEN_ADDRESS>";

// Amount of tokens 
const AMOUNT = "5";

const WALLET_PRIV_KEY = process.env.WALLET_PRIV_KEY || "";

if (!WALLET_PRIV_KEY ) {
  throw new Error("Wallet private key is not configured in env file");
}

if (!L1_RPC_ENDPOINT) {
  throw new Error(
    "Missing L1 RPC endpoint. Check chainlist.org or an RPC node provider"
  );
}

if (!TOKEN_ADDRESS ) {
  throw new Error("Missing address of the ERC-20 token in L1");
}

async function main() {
  console.log(`Running script to bridge ERC-20 to L2`);

  // Initialize the wallet.
  const l1provider = new Provider(L1_RPC_ENDPOINT);
  const l2provider = new Provider(L2_RPC_ENDPOINT);
  const wallet = new Wallet(WALLET_PRIV_KEY, l2provider, l1provider);

  console.log(`L1 Balance is ${await wallet.getBalanceL1()}`);
  console.log(`L2 Balance is ${await wallet.getBalance()}`);

  // Deposit token to L2
  const depositHandle = await wallet.deposit({
    to: wallet.address,  // can bridge to a different address in L2
    token: TOKEN_ADDRESS,
    amount: ethers.utils.parseEther(AMOUNT), // assumes ERC-20 has 18 decimals
    // performs the ERC-20 approve action
    approveERC20: true,
  });
  console.log(`Deposit transaction sent ${depositHandle.hash}`);
  console.log(`Please wait a few minutes for the deposit to be processed in L2`);
}

main().then().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});

4. Run the script

npx ts-node deposit-erc20.ts

5. Expected Output

Running script to bridge ERC-20 to L2
L1 Balance is 19500035772482145
L2 Balance is 2969807401250000000
Deposit transaction sent 0xffb8e302430b0584e2e0104dd6295a03688c98ba7b6e9279b01dba65188cc444

Actual Output:

Running script to bridge ERC-20 to L2
L1 Balance is 8513092747259571425
L2 Balance is 983733765214875035

Identified Issue: l2TokenAddress call fails during deposit operation

The call to retrieve l2TokenAddress seems to be failing, and this call is made in a few places when we call wallet.deposit.

Example:

const l2WethToken = await bridgeContracts.weth.l2TokenAddress(transaction.token);

This call consistently fails with a CALL_EXCEPTION error.

Error: call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="l2TokenAddress(address)", data="0x", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.7.0)
    at Logger.makeError (/Users/dustinbrickwood/Documents/dev/zk/zksync-era/node_modules/@ethersproject/logger/src.ts/index.ts:269:28)
    at Logger.throwError (/Users/dustinbrickwood/Documents/dev/zk/zksync-era/node_modules/@ethersproject/logger/src.ts/index.ts:281:20)
    at Interface.decodeFunctionResult (/Users/dustinbrickwood/Documents/dev/zk/zksync-era/node_modules/@ethersproject/abi/src.ts/interface.ts:427:23)
    at Contract.<anonymous> (/Users/dustinbrickwood/Documents/dev/zk/zksync-era/node_modules/@ethersproject/contracts/src.ts/index.ts:400:44)
    at step (/Users/dustinbrickwood/Documents/dev/zk/zksync-era/node_modules/@ethersproject/contracts/lib/index.js:48:23)
    at Object.next (/Users/dustinbrickwood/Documents/dev/zk/zksync-era/node_modules/@ethersproject/contracts/lib/index.js:29:53)
    at fulfilled (/Users/dustinbrickwood/Documents/dev/zk/zksync-era/node_modules/@ethersproject/contracts/lib/index.js:20:58)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  reason: null,
  code: 'CALL_EXCEPTION',
  method: 'l2TokenAddress(address)',
  data: '0x',
  errorArgs: null,
  errorName: null,
  errorSignature: null,
  address: '0x0000000000000000000000000000000000000000',
  args: [ '0x07865c6E87B9F70255377e024ace6630C1Eaa37F' ],
  transaction: {
    data: '0xf5f1516800000000000000000000000007865c6e87b9f70255377e024ace6630c1eaa37f',
    to: '0x0000000000000000000000000000000000000000',
    from: '0x42baB21bB7c1E236D67B264685E28fbbeF49C19F'
  }
}

Context

When executing the deposit call from the script:

const depositHandle = await wallet.deposit({
  to: wallet.address, 
  token: TOKEN_ADDRESS,
  amount: ethers.utils.parseEther(AMOUNT),
  approveERC20: true,
});

The function internally references l2TokenAddress in a few places:

By commenting out the lines that invoke l2TokenAddress in the above-referenced locations, the deposit transaction executes as expected and successfully completes. This workaround suggests that the issue may be specifically related to how l2TokenAddress is being called or handled.

Deliverable

To close out this issue:

  • Investigate the issue with l2TokenAddress
  • Test the ERC-20 script above to ensure it works as intended
  • Test using weth as well to ensure that too works as intended
@dutterbutter dutterbutter added the bug Something isn't working label Sep 18, 2023
@danijelTxFusion
Copy link
Collaborator

danijelTxFusion commented Sep 20, 2023

The bug is related to l2TokenAddress method because it throws error for every token expcept for ETH. More precise, l2TokenAddress uses l2WethBridge.l2TokenAddress(token) to get wETHL2 based on provided wETHL1, which returns 0x for every token. This means that current implementation of l2TokenAddress on mainnet and testnet works only for ETH and breaks for any other token.

wETH on Mainnet

{
  "address": "0xf00dad97284d0c6f06dc4db3c32454d4292c6813",
  "l1Address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
  "l2Address": "0xf00dad97284d0c6f06dc4db3c32454d4292c6813",
  "name": "Wrapped Ether",
  "symbol": "WETH",
  "decimals": 18
}
const wETHL1 = await provider.l2TokenAddress("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); // breaks
const wETHL2 = await provider.l1TokenAddress("0xf00dad97284d0c6f06dc4db3c32454d4292c6813"); // breaks

The same bug applies to testnet and local-setup.

@danijelTxFusion
Copy link
Collaborator

danijelTxFusion commented Sep 22, 2023

Here's the PR that fixed the issue. Also the wETH bridges does not work because they always return '0x' when it comes to l1TokenAddress and l2TokenAddress methods.

@mpavlovic-txfusion
Copy link

It looks to me that the root cause of this issue was the fact that the zks_getBridgeContracts RPC method doesn't return the correct l1WethBridge and l2WethBridge addresses and instead it return the zero address.
This RPC method is used by the sdk and the call to l2TokenAddress is sent to the incorrect weth bridge address, causing it to fail.

This is happening on both Testnet and Mainnet:
Mainnet
{"jsonrpc":"2.0","result":{"l1Erc20DefaultBridge":"0x57891966931eb4bb6fb81430e6ce0a03aabde063","l2Erc20DefaultBridge":"0x11f943b2c77b743ab90f4a0ae7d5a4e7fca3e102","l1WethBridge":"0x0000000000000000000000000000000000000000","l2WethBridge":"0x0000000000000000000000000000000000000000"},"id":1}
Testnet
{"jsonrpc":"2.0","result":{"l1Erc20DefaultBridge":"0x927ddfcc55164a59e0f33918d13a2d559bc10ce7","l2Erc20DefaultBridge":"0x00ff932a6d70e2b8f1eb4919e1e09c1923e7e57b","l1WethBridge":"0x0000000000000000000000000000000000000000","l2WethBridge":"0x0000000000000000000000000000000000000000"},"id":1}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working ethers-v5
Projects
None yet
Development

No branches or pull requests

3 participants