A production-ready cross-chain bridge that enables secure token transfers from Solana (using Light Protocol) to Ethereum using zero-knowledge proofs.
Solana (Light Protocol) → ZK Circuit → Ethereum Bridge Contract
↓ ↓ ↓
Compressed Account → SNARK Proof → Token Transfer
- Verifies Light Protocol compressed account inclusion
- Generates unique nullifiers to prevent double spending
- Creates commitments binding all transaction parameters
- Outputs ZK-SNARK proof for Ethereum verification
- Generated from Circom circuit using snarkjs
- Verifies Groth16 proofs on-chain
- BN254 elliptic curve pairing verification
- Main contract for processing withdrawals
- Validates deposit records against ZK proofs
- Prevents replay attacks using nullifiers
- Transfers ERC20 tokens to recipients
✅ Replay Protection - Unique nullifiers prevent double spending
✅ Amount Binding - ZK circuit ensures exact amount matching
✅ State Verification - Only valid Solana deposits can be processed
✅ Privacy - Sensitive data remains hidden in ZK proof
✅ Fail-Safe - Multiple validation layers with emergency controls
# Install dependencies
cd evm-bridge && npm install
cd ../circom && npm install
# Install Circom
npm install -g circom
From your Light Protocol deposit data:
cd circom/scripts
npx ts-node generateInput.ts
This creates input.json
from your proof.json
, account.json
, and record.json
.
cd circom
# Compile circuit
circom solDepositProof.circom --r1cs --wasm --sym
# Generate witness
node solDepositProof_js/generate_witness.js solDepositProof_js/solDepositProof.wasm input.json witness.wtns
# Setup ceremony (development only)
snarkjs powersoftau new bn128 12 pot12_0000.ptau -v
snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="First contribution" -v
snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau -v
# Generate proving/verification keys
snarkjs groth16 setup solDepositProof.r1cs pot12_final.ptau circuit_0000.zkey
snarkjs zkey contribute circuit_0000.zkey circuit_final.zkey --name="1st Contributor" -v
# Generate proof
snarkjs groth16 prove circuit_final.zkey witness.wtns proof.json public.json
# Export Solidity verifier
snarkjs zkey export solidityverifier circuit_final.zkey verifier.sol
cd evm-bridge
# Deploy verifier and bridge
npx hardhat run scripts/deploy.ts --network <your-network>
# Set contract addresses
export BRIDGE_CONTRACT_ADDRESS="0x..."
export VERIFIER_CONTRACT_ADDRESS="0x..."
# Process withdrawal
npx hardhat run scripts/processWithdrawal.ts --network <your-network>
Your record.json
:
{
"owner": "Ea9KnXpSXdRKfJAUhrqqWhuBMK3RKPWGQGFto6gvhVco",
"source_chain_id": 1,
"dest_chain_id": 41312,
"dest_chain_addr": "2Uk4AtEZ3mbEVqZQ7En7c4cLuc4Q",
"dest_chain_mint_addr": "",
"mint": "svCXW2ivW3L7yBuFLapYKqdeKCcdAEnFQEXpZEF9CUw",
"amount": "64",
"timestamp": "6852bbce",
"deposit_id": "01"
}
- Map destination address to Ethereum address:
bridge.mapAddress("2Uk4AtEZ3mbEVqZQ7En7c4cLuc4Q", "0xYourEthereumAddress");
-
Set ERC20 token contract address in
dest_chain_mint_addr
-
Deposit tokens to bridge for liquidity:
bridge.depositTokens("0xTokenContract", "64");
- Update state root with Light Protocol root:
bridge.updateStateRoot("0xStateRoot", blockHeight);
// Process withdrawal with ZK proof
function processWithdrawal(DepositRecord record, ZKProof proof)
// Admin functions
function mapAddress(string base58Addr, address ethAddr)
function updateStateRoot(uint256 stateRoot, uint256 blockHeight)
function depositTokens(address tokenContract, uint256 amount)
// View functions
function isNullifierUsed(uint256 nullifier) → bool
function getTokenBalance(address tokenContract) → uint256
cd circom
circom solDepositProof.circom --r1cs --wasm --sym
# Check circuit info
snarkjs r1cs info solDepositProof.r1cs
cd evm-bridge
npx hardhat test
npx hardhat coverage
- Use production ceremony for trusted setup
- Audit ZK circuit and contracts
- Set up multi-sig for admin functions
- Configure proper state root oracle
- Set withdrawal limits and rate limiting
- Monitor for unusual activity
- Prepare emergency pause mechanisms
- Generate production trusted setup
- Deploy contracts with proper access controls
- Set up relayer infrastructure
- Configure monitoring and alerting
- Coordinate with Light Protocol team for state root sync
Circuit compilation fails:
- Ensure circom 2.1.8+ is installed
- Check circomlib is in node_modules
Proof verification fails:
- Verify circuit inputs match expected format
- Check public signals order matches contract
- Ensure verifying key matches proving key
Transaction reverts:
- Check nullifier not already used
- Verify state root is valid
- Ensure sufficient bridge token balance
- Confirm address mapping is set
- Fork the repository
- Create feature branch
- Add tests for new functionality
- Submit pull request
MIT License - see LICENSE file for details.
For security issues, please email [email protected]
Do not create public GitHub issues for security vulnerabilities.