This repository implements a StarkNet-to-Ethereum bridge specifically designed for local development. It facilitates the transfer of ERC20 tokens between the StarkNet L2 and Ethereum L1 environments.
The bridge allows a native StarkNet token ($STRK) to be bridged from StarkNet, creating a wrapped representation ($aSTRK) on Ethereum. This enables $STRK tokens to be used across Ethereum's ecosystem, unlocking additional use cases and utility.
Our goal with this repository is to provide a comprehensive, step-by-step tutorial that guides developers through the complete implementation of a StarkNet-to-Ethereum bridge. Unlike many existing resources that focus on production-level code, this repository emphasizes foundational guidance and detailed explanations. It aims to help new developers understand and execute cross-layer messaging while focusing on the fundamentals of L2-to-L1 communication.
We chose a bridge model that mints a representation of the StarkNet token on Ethereum, allowing developers to explore StarkNet's unique features while leveraging Ethereum’s broad capabilities. This guide is intended as a starting point, highlighting initial steps toward building a production bridge by covering core concepts, environment setup, and essential cross-chain messaging. It also allows custom implementations of $STRK on Ethereum for potential use cases like vaults or other DeFi applications, inspiring further development toward production-ready solutions.
Although not intended as a production-level implementation, this repository provides the groundwork that developers can build upon, with flexibility to integrate unique features as they progress. By bridging $STRK tokens to access Ethereum-based applications, new interactions can be created, driving activity on the StarkNet network.
This tutorial and implementation have been inspired by the Starknet Messaging Dev Repository and aim to contribute to the StarkNet ecosystem by providing a structured, accessible guide emphasizing transparency, usability, and practical understanding. For additional details, troubleshooting, and FAQs, please refer to the Q&A file included in this repository.
To bridge tokens from StarkNet (L2) to Ethereum (L1), the bridge must be authorized to transfer a specified amount of
tokens from the balance by calling the approve
function on the L2 Token contract. Once authorized, the transfer is
initiated by invoking the deposit
function on the L2 Bridge contract, which locks the $STRK tokens on StarkNet and
sends a message to the Ethereum network.
The message has been recorded on the Starknet Core Contract. Once the transaction is processed and settled on L1,
the $aSTRK tokens can be claimed by calling the withdraw
function on the L1 Bridge contract. The same values supplied
to the deposit
function on L2 must be used when calling withdraw
; otherwise, the L1 transaction will fail.
When bridging tokens back from Ethereum (L1) to StarkNet (L2), the process starts by calling the initiate_withdraw
function. This function burns the $aSTRK tokens on Ethereum and sends a corresponding message to the StarkNet network.
The message is relayed through the StarkNet sequencer and processed by the L2 Bridge contract. Once the message is
received on StarkNet, the L2 Bridge releases the equivalent amount of $STRK tokens from the locked tokens and transfers
them to the StarkNet account, completing the bridge process.
- 1. Requirements
- 2. Setup Ethereum Contracts
- 3. Setup Starknet Contracts
- 4. Bridge Tokens
- 5. Limitations
Before starting, the following must be installed:
- scarb to build Cairo contracts.
- starkli to interact with Katana.
- katana to install Katana, part of Dojo.
- foundry to interact with Anvil.
For first-time cloning of the repository, install Forge dependencies as follows:
cd solidity
forge install
forge install OpenZeppelin/openzeppelin-contracts --no-commit
To set up the Ethereum component for local testing, follow these steps:
-
Start Anvil in a new terminal:
anvil
-
In another terminal, navigate to the Solidity directory:
cd solidity
-
Copy the
anvil.env
file to.env
, load environment variables, and build the contracts:cp anvil.env .env source .env forge build
-
Deploy the
StarknetMessagingLocal
contract:forge script script/Setup.s.sol:LocalSetup --broadcast --rpc-url ${ETH_RPC_URL}
-
Deploy the
BridgedERC20
token contract:forge create --rpc-url ${ETH_RPC_URL} --private-key <ACCOUNT_PRIVATE_KEY> src/BridgedERC20.sol:BridgedERC20 --constructor-args <ACCOUNT_ADDRESS>
-
Update the
L1_TOKEN_ADDRESS
in theanvil.env
file with the deployed token contract address:L1_TOKEN_ADDRESS=<Deployed Token Contract Address>
-
Deploy the
L1Bridge
contract:forge create --rpc-url ${ETH_RPC_URL} --private-key <ACCOUNT_PRIVATE_KEY> src/L1Bridge.sol:L1Bridge --constructor-args <SN_MESSAGING_ADDRESS> <L1_TOKEN_ADDRESS>
-
Update the
L1_BRIDGE_ADDRESS
in theanvil.env
file with the deployed bridge contract address:L1_BRIDGE_ADDRESS=<Deployed Bridge Contract Address>
-
Transfer ownership of the token to the bridge contract:
cast send <L1_TOKEN_ADDRESS> "transferOwnership(address)" <L1_BRIDGE_ADDRESS> --rpc-url ${ETH_RPC_URL} --private-key <ACCOUNT_PRIVATE_KEY>
To set up the StarkNet contracts, follow these steps:
-
Update Katana to version 1.0.0-alpha.0:
starkliup dojoup -v 1.0.0-alpha.0
-
Start Katana in a new terminal:
katana --messaging anvil.messaging.json
-
In another terminal, navigate to the Cairo folder and build the Cairo contracts:
cd cairo source katana.env scarb build
-
Declare and deploy the main token on L2:
starkli declare ./target/dev/bridge_tutor_strk_token.contract_class.json --compiler-version 2.8.2 --keystore-password "" starkli deploy <CLASS_HASH> 0x537461726b6e6574546f6b656e 0x5354524b 18 --salt 0x1234 --keystore-password ""
-
Update the
L2_TOKEN_ADDRESS
in theanvil.env
file with the deployed L2 token contract address:L2_TOKEN_ADDRESS=<Deployed L2 Token>
-
Declare and deploy the
l2bridge
contract:starkli declare ./target/dev/bridge_tutor_l2bridge.contract_class.json --compiler-version 2.8.2 --keystore-password "" starkli deploy <CLASS_HASH> <L1_BRIDGE_ADDRESS> <L2_TOKEN_ADDRESS> --salt 0x1234 --keystore-password ""
-
Update the
L2_BRIDGE_ADDRESS
in theanvil.env
file with the deployed L2 bridge contract address:L2_BRIDGE_ADDRESS=<Deployed L2 Bridge>
-
Mint tokens on L2 for testing:
starkli invoke <L2_TOKEN_ADDRESS> mint <L2_ACCOUNT> u256:200 --keystore-password ""
When sending a message from StarkNet (L2) to Ethereum (L1), the process is slightly different from L1 to L2 messaging. Sending messages from Ethereum to StarkNet (L1 → L2) is handled automatically by the StarkNet sequencer. However, sending messages from StarkNet to Ethereum (L2 → L1) requires manually consuming the message on L1.
For more details, refer to the StarkNet messaging documentation.
-
Approve the L2 bridge to transfer tokens:
starkli invoke <L2_TOKEN_ADDRESS> approve <L2_BRIDGE_ADDRESS> u256:5 --keystore-password ""
-
Initiate the token bridge by invoking the
deposit
function on the L2 bridge contract:starkli invoke <L2_BRIDGE_ADDRESS> deposit <ACCOUNT_FELT> 5 --keystore-password ""
-
Verify token balances on L2:
starkli call <L2_TOKEN_ADDRESS> balance_of <L2_ACCOUNT> starkli call <L2_TOKEN_ADDRESS> balance_of <L2_BRIDGE_ADDRESS>
-
Update the environment variables in
anvil.env
and reload them:cp anvil.env .env source .env
-
Consume the message on L1 to finalize the token transfer:
forge script script/ConsumeMessage.s.sol:ConsumeMessage --broadcast -vvvv --rpc-url ${ETH_RPC_URL}
-
Verify token balances on L1:
cast call <L1_TOKEN_ADDRESS> "balanceOf(address)" <ACCOUNT_ADDRESS> --rpc-url ${ETH_RPC_URL}
-
Initiate the bridge from L1 to L2:
forge script script/SendMessage.s.sol:BridgeTokens --broadcast -vvvv --rpc-url ${ETH_RPC_URL}
-
Verify token balance on L1:
cast call <L1_TOKEN_ADDRESS> "balanceOf(address)" <ACCOUNT_ADDRESS> --rpc-url ${ETH_RPC_URL}
-
Verify token balance on L2:
starkli call <L2_TOKEN_ADDRESS> balance_of <L2_ACCOUNT> starkli call <L2_TOKEN_ADDRESS> balance_of <L2_BRIDGE_ADDRESS>
This repository is intended for local development only and should not be used in production environments. It operates in conjunction with development tools like Katana and Anvil, simulating cross-chain interactions between StarkNet and Ethereum.