# Bridge ERC-20 Tokens

MegaETH's canonical bridge supports ERC-20 token bridging via the OP Stack [Standard Bridge](https://docs.optimism.io/app-developers/guides/bridging/standard-bridge). Bridging locks tokens in the `L1StandardBridge` on Ethereum and mints a paired `OptimismMintableERC20` on MegaETH.

## Prerequisites

* [Foundry](https://getfoundry.sh/) installed (`forge` and `cast`)
* A wallet funded with ETH on both L1 (for deployment and bridging gas) and L2 (for registration gas)
* An ERC-20 contract ready to deploy, or an existing L1 token address

## Contract Addresses

{% tabs %}
{% tab title="Mainnet" %}

| Contract                     | Chain                        | Address                                      |
| ---------------------------- | ---------------------------- | -------------------------------------------- |
| L1StandardBridge             | Ethereum (chain 1)           | `0x0CA3A2FBC3D770b578223FBB6b062fa875a2eE75` |
| OptimismMintableERC20Factory | Ethereum (chain 1)           | `0xF875030B9464001fC0f964E47546b0AFEEbD7C61` |
| L2StandardBridge             | MegaETH Mainnet (chain 4326) | `0x4200000000000000000000000000000000000010` |
| OptimismMintableERC20Factory | MegaETH Mainnet (chain 4326) | `0x4200000000000000000000000000000000000012` |
| {% endtab %}                 |                              |                                              |

{% tab title="Testnet (Sepolia)" %}

| Contract                     | Chain                             | Address                                      |
| ---------------------------- | --------------------------------- | -------------------------------------------- |
| L1StandardBridge             | Ethereum Sepolia (chain 11155111) | `0x8033d50c753b3f19748f239ac8cf915b2888cd32` |
| OptimismMintableERC20Factory | Ethereum Sepolia (chain 11155111) | `0x11f008caa3083aa8a3b6f9f06f923e98a28fa286` |
| L2StandardBridge             | MegaETH Testnet (chain 6343)      | `0x4200000000000000000000000000000000000010` |
| OptimismMintableERC20Factory | MegaETH Testnet (chain 6343)      | `0x4200000000000000000000000000000000000012` |
| {% endtab %}                 |                                   |                                              |
| {% endtabs %}                |                                   |                                              |

## Steps

{% stepper %}
{% step %}

#### Deploy your ERC-20 on L1

Deploy your token contract on Ethereum (or Sepolia for testing). The example below uses a Foundry script; adapt it for your own token.

```bash
forge script script/Deploy.s.sol \
  --rpc-url $L1_RPC \
  --broadcast \
  --private-key $PRIVATE_KEY
```

Save the deployed token address — you will need it in the next step.
{% endstep %}

{% step %}

#### Register the L2 counterpart

Call `createOptimismMintableERC20` on the `OptimismMintableERC20Factory` **on MegaETH**. This deploys a bridgeable ERC-20 on L2 that is linked to your L1 token. Replace `"MyToken"` and `"MTK"` with your token's name and symbol.

```bash
cast send $L2_MINTABLE_FACTORY \
  "createOptimismMintableERC20(address,string,string)" \
  $L1_TOKEN "MyToken" "MTK" \
  --rpc-url $L2_RPC \
  --private-key $PRIVATE_KEY
```

The factory emits an `OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer)` event. Parse the `localToken` field from the receipt to get your L2 token address.

```bash
# Extract the L2 token address from the event logs
# topics[0] is keccak256("OptimismMintableERC20Created(address,address,address)")
# topics[1] is the L2 token address ABI-encoded as a 32-byte padded value; [26:] strips the leading zeros
cast receipt $TX_HASH --rpc-url $L2_RPC --json \
  | jq -r '.logs[] | select(.topics[0] == "0x52fe89dd5930f343d25650b62fd367bae47088bcddffd2a88350a6ecdd620cdb") | "0x" + .topics[1][26:]'
```

{% endstep %}

{% step %}

#### Approve the L1 bridge

Approve `L1StandardBridge` to spend the tokens you want to bridge. Set `$AMOUNT` in wei (e.g. `100000000000000000000` for 100 tokens with 18 decimals).

```bash
cast send $L1_TOKEN \
  "approve(address,uint256)" \
  $L1_BRIDGE $AMOUNT \
  --rpc-url $L1_RPC \
  --private-key $PRIVATE_KEY
```

{% endstep %}

{% step %}

#### Bridge tokens to MegaETH

Call `bridgeERC20` on `L1StandardBridge`. Pass both the L1 and L2 token addresses, the amount in wei, a minimum gas limit for L2 execution, and empty extra data.

```bash
cast send $L1_BRIDGE \
  "bridgeERC20(address,address,uint256,uint32,bytes)" \
  $L1_TOKEN \
  $L2_TOKEN \
  $AMOUNT \
  200000 \
  0x \
  --rpc-url $L1_RPC \
  --private-key $PRIVATE_KEY
```

`200000` is sufficient for most standard ERC-20 tokens. The bridge transaction locks tokens on L1 and relays a message to MegaETH to mint the equivalent amount on L2.
{% endstep %}

{% step %}

#### Verify the L2 balance

After the L1 transaction is finalized and relayed (\~1–2 minutes), check the balance on MegaETH.

```bash
cast call $L2_TOKEN \
  "balanceOf(address)(uint256)" \
  $(cast wallet address --private-key $PRIVATE_KEY) \
  --rpc-url $L2_RPC
```

{% hint style="info" %}
The deposit takes approximately 1–2 minutes to appear on MegaETH — one L1 block for finality, plus sequencer relay time. You can track the L1 transaction on [Etherscan](https://etherscan.io) (mainnet) or [Sepolia Etherscan](https://sepolia.etherscan.io) (testnet), and the L2 deposit on [MegaETH Blockscout](https://megaeth.blockscout.com) (mainnet) or the [testnet explorer](https://megaeth-testnet-v2.blockscout.com).
{% endhint %}
{% endstep %}
{% endstepper %}

## Withdrawals (L2 → L1)

Withdrawing tokens back to Ethereum requires initiating a withdrawal on L2 and then proving and finalizing it on L1 after the challenge period. This follows the standard OP Stack withdrawal flow — see the [OP Stack withdrawal guide](https://docs.optimism.io/app-developers/guides/bridging/standard-bridge#withdrawing-erc-20-tokens) for details.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.megaeth.com/developer-docs/bridge-erc20.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
