Skip to main content

Overview

Arbitrum-focused template for L2 development. Includes L1-to-L2 and L2-to-L1 bridge messaging contracts, a bidirectional token gateway, and a gas-efficient ERC-20 token. Pre-configured to fork Arbitrum mainnet with Blockscout explorer.
DifficultyIntermediate
CategoryL2
ChainsArbitrum (fork)
ServicesBlockscout (port 4000), Prometheus (port 9090)
LicenseApache-2.0

Quick Start

dokrypt init my-arb --template evm-arbitrum
cd my-arb
dokrypt up
# arbitrum (anvil)   Ready  http://localhost:8545
# blockscout         Ready  http://localhost:4000
# prometheus         Ready  http://localhost:9090

Generated Files

my-arb
dokrypt.yaml
foundry.toml
README.md
contracts
token
ArbitrumToken.sol
bridge
L1ToL2MessageSender.sol
L2ToL1MessageSender.sol
gateway
TokenGateway.sol
test
ArbitrumToken.t.sol
L1ToL2Message.t.sol
TokenGateway.t.sol
scripts
deploy.js
bridge-tokens.js

Contracts

ArbitrumToken.sol

Gas-efficient ERC-20 optimized for Arbitrum. Includes batch transfers and gateway-authorized minting/burning for bridge operations.
FunctionAccessDescription
Standard ERC-20Publictransfer, approve, transferFrom
batchTransfer(recipients[], amounts[])PublicSend tokens to multiple addresses in one tx
mint(to, amount)GatewayMint tokens on L2 (called by gateway during bridging)
burn(from, amount)GatewayBurn tokens on L2 (called during withdrawal)
setGateway(gateway)OwnerAuthorize a gateway contract

Bridge Module

L1ToL2MessageSender.sol

Sends messages from L1 to L2 via Arbitrum’s Delayed Inbox pattern. Creates retryable tickets with configurable gas parameters.
FunctionAccessDescription
sendMessage(target, data, maxGas, gasPriceBid)PublicCreate a retryable ticket to L2
getTicket(ticketId)ViewGet ticket details
getTicketCount()ViewTotal tickets created

L2ToL1MessageSender.sol

Sends messages from L2 to L1 via the ArbSys precompile (0x0000000000000000000000000000000000000064). Includes target allowlisting and nonce tracking.
FunctionAccessDescription
sendMessage(target, data)PublicSend message to allowed L1 target
addAllowedTarget(target)OwnerAdd L1 address to allowlist
removeAllowedTarget(target)OwnerRemove from allowlist
confirmMessage(nonce)OwnerConfirm message delivery

TokenGateway.sol

Bidirectional token bridging using lock-and-mint (L1 to L2) and burn-and-release (L2 to L1) pattern.
FunctionAccessDescription
deposit(l1Token, amount)PublicLock tokens on L1, mint on L2
withdraw(l2Token, amount)PublicBurn tokens on L2, release on L1
finalizeDeposit(l1Token, to, amount, depositId)CounterpartComplete deposit on L2 side
finalizeWithdrawal(l2Token, to, amount, withdrawalId)CounterpartComplete withdrawal on L1 side
mapToken(l1Token, l2Token)OwnerRegister L1/L2 token pair

Deployment

Deploy All Contracts

npx hardhat run scripts/deploy.js --network localhost
Deploys ArbitrumToken, L1ToL2MessageSender, L2ToL1MessageSender, and TokenGateway. Configures gateway linking and token mappings.

Bridge Token Flow

npx hardhat run scripts/bridge-tokens.js --network localhost
Demonstrates a full L1-to-L2 deposit and L2-to-L1 withdrawal cycle.

Testing Workflows

Bridge Testing

# Start Arbitrum fork environment
dokrypt up

# Deploy contracts
npx hardhat run scripts/deploy.js --network localhost

# Run bridge tests
dokrypt test run --filter "bridge"

Token Gateway Testing

# Test full deposit/withdrawal cycle
dokrypt test run --filter "gateway"

# Test with gas report
dokrypt test --gas-report

Fork Testing

# Fork Arbitrum at a specific block
dokrypt fork arbitrum --block 200000000

# Interact with existing Arbitrum contracts
dokrypt exec arbitrum "cast call 0x..."