---
title: "Enter Signet"
url: "/docs/build-on-signet/transfers/enter-signet/index.md"
description: "Move ETH and ERC-20 tokens from Ethereum to Signet via Passage"
--- [Passage](https://github.com/init4tech/zenith/blob/main/src/passage/Passage.sol) is the bridge contract on Ethereum that moves assets into Signet. Deposits arrive on the rollup in the same block they're submitted. Passage has two entry points: one for ETH (sent as `msg.value`) and one for ERC-20 tokens (requires a prior token approval). Both take a `rollupRecipient` address that receives the tokens on Signet. > **Supported assets:** Signet currently supports bridging **ETH**, **USDC**, **USDT**, and **WBTC** from Ethereum. Contact the Signet team to add support for additional assets. The Signet node watches for `Enter` and `EnterToken` events on the Passage contract. If the event fired, the deposit was processed -- no additional confirmation is needed on the rollup side. 

## TypeScript

This page assumes you've [set up your clients](/docs/build-on-signet/getting-started/index.md) . See [Parmigiana testnet](/docs/build-on-signet/parmigiana/index.md#host-system-contracts) for contract addresses.
## Enter with ETH ```typescript import { passageAbi } from '@signet-sh/sdk/abi'; import { PARMIGIANA } from '@signet-sh/sdk/constants'; import { parseEther } from 'viem'; // 1. Deposit ETH into Signet via Passage on Ethereum const hash = await hostWalletClient.writeContract({ address: PARMIGIANA.hostPassage, abi: passageAbi, functionName: 'enter', args: [userAddress], value: parseEther('1'), }); // 2. Wait for the Ethereum transaction to confirm await hostPublicClient.waitForTransactionReceipt({ hash }); // 3. Tokens are on Signet, check the balance const balance = await signetPublicClient.getBalance({ address: userAddress }); ``` **Without the SDK** ```typescript import { parseEther } from 'viem'; const passageAbi = [ { name: 'enter', type: 'function', stateMutability: 'payable', inputs: [{ name: 'rollupRecipient', type: 'address' }], outputs: [], }, ] as const; const hash = await hostWalletClient.writeContract({ address: '`0x28524D2a753925Ef000C3f0F811cDf452C6256aF` ', abi: passageAbi, functionName: 'enter', args: [userAddress], value: parseEther('1'), }); await hostPublicClient.waitForTransactionReceipt({ hash }); const balance = await signetPublicClient.getBalance({ address: userAddress }); ``` ## Enter with ERC-20 tokens Approve Passage to spend the token, then call enterToken:
```typescript import { passageAbi } from '@signet-sh/sdk/abi'; import { PARMIGIANA } from '@signet-sh/sdk/constants'; import { getTokenAddress } from '@signet-sh/sdk/tokens'; import { erc20Abi } from 'viem'; // 1. Approve Passage to spend the token await hostWalletClient.writeContract({ address: tokenAddress, abi: erc20Abi, functionName: 'approve', args: [PARMIGIANA.hostPassage, amount], }); // 2. Deposit into Signet const hash = await hostWalletClient.writeContract({ address: PARMIGIANA.hostPassage, abi: passageAbi, functionName: 'enterToken', args: [userAddress, tokenAddress, amount], }); // 3. Wait, then check the rollup balance await hostPublicClient.waitForTransactionReceipt({ hash }); const rollupToken = getTokenAddress('WETH', PARMIGIANA.rollupChainId, PARMIGIANA); const balance = await signetPublicClient.readContract({ address: rollupToken, abi: erc20Abi, functionName: 'balanceOf', args: [userAddress], }); ``` **Without the SDK** ```typescript import { erc20Abi } from 'viem'; const enterTokenAbi = [ { name: 'enterToken', type: 'function', stateMutability: 'nonpayable', inputs: [ { name: 'rollupRecipient', type: 'address' }, { name: 'token', type: 'address' }, { name: 'amount', type: 'uint256' }, ], outputs: [], }, ] as const; await hostWalletClient.writeContract({ address: tokenAddress, abi: erc20Abi, functionName: 'approve', args: ['`0x28524D2a753925Ef000C3f0F811cDf452C6256aF` ', amount], }); const hash = await hostWalletClient.writeContract({ address: '`0x28524D2a753925Ef000C3f0F811cDf452C6256aF` ', abi: enterTokenAbi, functionName: 'enterToken', args: [userAddress, tokenAddress, amount], }); await hostPublicClient.waitForTransactionReceipt({ hash }); const balance = await signetPublicClient.readContract({ address: rollupTokenAddress, abi: erc20Abi, functionName: 'balanceOf', args: [userAddress], }); ``` For error handling and common issues, see [Troubleshooting](/docs/build-on-signet/advanced/troubleshooting/index.md) .

## Rust

This page assumes you've [set up your providers](/docs/build-on-signet/getting-started/index.md) . See [Parmigiana testnet](/docs/build-on-signet/parmigiana/index.md#host-system-contracts) for contract addresses.
## Enter with ETH ```rust use signet_zenith::Passage; use signet_constants::parmigiana; use alloy::primitives::utils::parse_ether; let passage = Passage::new(parmigiana::HOST_PASSAGE, &host_provider); // Deposit ETH into Signet let tx = passage .enter(rollup_recipient) .value(parse_ether("1")?) .send() .await?; let receipt = tx.get_receipt().await?; ``` ## Enter with ERC-20 tokens Approve Passage to spend the token, then call enterToken:
```rust use signet_zenith::Passage; use signet_constants::parmigiana; let passage = Passage::new(parmigiana::HOST_PASSAGE, &host_provider); // 1. Approve Passage to spend the token let approve_tx = token_contract .approve(parmigiana::HOST_PASSAGE, amount) .send() .await?; approve_tx.get_receipt().await?; // 2. Bridge tokens to Signet let enter_tx = passage .enterToken(rollup_recipient, token_address, amount) .send() .await?; enter_tx.get_receipt().await?; ``` For error handling and common issues, see [Troubleshooting](/docs/build-on-signet/advanced/troubleshooting/index.md) .

## Solidity

This page assumes you've completed the [getting started](/docs/build-on-signet/getting-started/index.md) setup. See [Parmigiana testnet](/docs/build-on-signet/parmigiana/index.md#host-system-contracts) for the deployed Passage address.
## Enter with ETH Call enter on the Passage contract with ETH attached:
```solidity import {Passage} from "zenith/src/passage/Passage.sol"; Passage passage = Passage(PASSAGE_ADDRESS); // Deposit ETH into Signet -- rollupRecipient receives it on the rollup passage.enter{value: 1 ether}(rollupRecipient); ``` Passage also accepts plain ETH transfers via receive(). Any ETH sent directly to the contract is bridged to msg.sender on Signet.
## Enter with ERC-20 tokens Approve Passage to spend the token, then call enterToken:
```solidity import {Passage} from "zenith/src/passage/Passage.sol"; import {IERC20} from "forge-std/interfaces/IERC20.sol"; IERC20 token = IERC20(TOKEN_ADDRESS); Passage passage = Passage(PASSAGE_ADDRESS); // 1. Approve Passage to spend the token token.approve(PASSAGE_ADDRESS, amount); // 2. Bridge tokens to Signet passage.enterToken(rollupRecipient, address(token), amount); ``` ## Contract integration A minimal contract that wraps Passage for ETH and ERC-20 deposits:
```solidity contract YourContract { Passage public passage; IERC20 public token; constructor(address _passage, IERC20 _token) { passage = Passage(_passage); token = _token; token.approve(_passage, type(uint256).max); } function bridgeETH() external payable { passage.enter{value: msg.value}(msg.sender); } function bridgeToken(uint256 amount) external { token.transferFrom(msg.sender, address(this), amount); passage.enterToken(msg.sender, address(token), amount); } } ``` The constructor approves Passage for the max token allowance so bridgeToken doesn't need a per-call approval.
## Source [Passage.sol](https://github.com/init4tech/zenith/blob/main/src/passage/Passage.sol) source code ABIs available on the [Parmigiana quickstart](/docs/build-on-signet/parmigiana/index.md#abis) For error handling and common issues, see [Troubleshooting](/docs/build-on-signet/advanced/troubleshooting/index.md) .

## Terminal

This page assumes you've completed the [getting started](/docs/build-on-signet/getting-started/index.md) setup. See [Parmigiana testnet](/docs/build-on-signet/parmigiana/index.md#host-system-contracts) for contract addresses.
## Enter with ETH Send ETH directly to the Passage contract:
```bash cast send $PASSAGE_ADDRESS \ "enter(address)" \ $YOUR_ADDRESS \ --value 1ether \ --rpc-url $HOST_RPC \ --private-key $PRIVATE_KEY ``` Verify the deposit arrived on Signet:
```bash cast balance $YOUR_ADDRESS --rpc-url $SIGNET_RPC ``` ## Enter with ERC-20 tokens Entering with tokens requires two transactions – approve, then bridge:
```bash # 1. Approve Passage to spend tokens cast send $TOKEN_ADDRESS \ "approve(address,uint256)" \ $PASSAGE_ADDRESS $AMOUNT \ --rpc-url $HOST_RPC \ --private-key $PRIVATE_KEY # 2. Bridge tokens to Signet cast send $PASSAGE_ADDRESS \ "enterToken(address,address,uint256)" \ $YOUR_ADDRESS $TOKEN_ADDRESS $AMOUNT \ --rpc-url $HOST_RPC \ --private-key $PRIVATE_KEY ``` For error handling and common issues, see [Troubleshooting](/docs/build-on-signet/advanced/troubleshooting/index.md) .

