A demonstration of a cross-chain bridge that transfers tokens between two test networks using Rust, Solidity, and Ethers.js.
- Solidity Contracts: Bridge and Token contracts deployed on both chains
- Rust Backend: Relayer service that monitors events and processes cross-chain transfers
- Frontend Dashboard: Web interface built with Ethers.js for monitoring and initiating transfers
solid/
├── contracts/ # Solidity smart contracts
│ ├── Bridge.sol # Bridge contract for locking/unlocking tokens
│ └── Token.sol # ERC20 token contract with faucet
├── rust-bridge/ # Rust relayer service
│ └── src/
│ └── main.rs # Event monitoring and relaying logic
├── frontend/ # Dashboard UI
│ ├── index.html
│ └── main.js # Ethers.js integration
├── scripts/ # Deployment scripts
│ ├── deploy-chain1.js
│ ├── deploy-chain2.js
│ ├── link-bridges.js
│ └── start-nodes.js # Start both Hardhat nodes
└── README.md
- Node.js (v18+)
- Rust (latest stable)
- Hardhat
- MetaMask (for testing)
# Install Node.js dependencies
npm install
# Install frontend dependencies
cd frontend && npm install && cd ..In Terminal 1, start both Hardhat nodes:
npm run nodesThis will start:
- Chain 1 on
http://localhost:8545 - Chain 2 on
http://localhost:8546
Keep this terminal running!
In Terminal 2, deploy contracts to both chains:
# Compile contracts
npm run compile
# Deploy to Chain 1
npm run deploy:chain1
# Deploy to Chain 2
npm run deploy:chain2After deployment, copy the bridge addresses from the output.
Create a .env file in the root directory:
# Chain 1 Configuration
CHAIN1_RPC_URL=http://localhost:8545
CHAIN1_BRIDGE_ADDRESS=<from deployment output>
CHAIN1_TOKEN_ADDRESS=<from deployment output>
# Chain 2 Configuration
CHAIN2_RPC_URL=http://localhost:8546
CHAIN2_BRIDGE_ADDRESS=<from deployment output>
CHAIN2_TOKEN_ADDRESS=<from deployment output>
# Wallet (for Rust relayer) - Use Hardhat's first default account
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80Create a .env file in the frontend directory:
VITE_CHAIN1_RPC=http://localhost:8545
VITE_CHAIN2_RPC=http://localhost:8546
VITE_CHAIN1_BRIDGE=<from deployment output>
VITE_CHAIN2_BRIDGE=<from deployment output>
VITE_API_URL=http://localhost:8080In Terminal 2, link the bridges:
npm run linkIn Terminal 3, start the Rust relayer:
cd rust-bridge
cargo runThe relayer will:
- Monitor Lock events on both chains
- Process transfers and call unlock on the target chain
- Serve an API at
http://localhost:8080
Keep this terminal running!
In Terminal 4, start the frontend:
npm run frontendThe dashboard will be available at http://localhost:3000 (or the port shown in the terminal).
-
Open the Dashboard: Navigate to
http://localhost:3000in your browser -
Connect MetaMask:
- Click "Connect Wallet" in the header
- Approve the connection in MetaMask
- Add the local Hardhat networks to MetaMask if prompted
- Note: The same wallet address will appear for both chains - this is correct! Your wallet works on both networks.
-
Get Test Tokens:
- Click "Get Tokens (Chain 1)" to receive 1000 BTC1 tokens
- Click "Get Tokens (Chain 2)" to receive 1000 BTC2 tokens
- Note: MetaMask may show a security warning. Click "I understand" - this is safe for local test networks.
-
Initiate Transfer:
- Select source chain (Chain 1 or Chain 2)
- Enter recipient address
- Enter amount
- Click "Initiate Transfer"
- Approve the transaction in MetaMask
-
Monitor Transfers: View all recent transfers in the transfer history section
- Lock: User calls
lock()on the source chain bridge, burning tokens - Event: Bridge emits a
Lockevent with transfer details - Relay: Rust relayer detects the event and calls
unlock()on target chain - Unlock: Target chain bridge mints tokens to the recipient
npm run compilenpm testcd rust-bridge
cargo build --releasenpm run setupThis will compile, deploy to both chains, and link the bridges.
- Make sure you've deployed contracts and updated
.envfiles - Restart the frontend after updating
.envfiles
- Make sure both Hardhat nodes are running (
npm run nodes) - Check that Chain 1 is on port 8545 and Chain 2 is on port 8546
- Use the faucet buttons to get test tokens
- Make sure you're on the correct chain in MetaMask
- This is normal for unverified contracts on local networks
- Click "I understand" to proceed - it's safe for local testing
For production use, you would need:
- Proper cryptographic proofs (e.g., Merkle proofs)
- Multi-signature oracles
- Economic security mechanisms
- Comprehensive testing and audits
- Rate limiting and access controls
MIT