A production-ready Solana smart contract for bridging assets between Solana and multiple EVM chains (Ethereum, Arbitrum, and BSC).
- Lock Tokens: Lock native SPL tokens on Solana to bridge to external chains
- Unlock Tokens: Release previously locked tokens when bridging back from external chains
- Mint Wrapped Tokens: Create wrapped SPL tokens representing assets from external chains
- Burn Wrapped Tokens: Burn wrapped tokens to release assets on the origin chain
- Multi-signature Validation: Configurable validator set with threshold signatures (default: 3-of-5)
- Multi-signature Admin: Admin operations require multiple signatures for enhanced security
- Replay Protection: Nonce-based transaction tracking prevents double-spending
- Emergency Pause: Circuit breaker mechanism for emergency situations
- Token Whitelisting: Only approved token pairs can be bridged
- Add/remove validators and admins dynamically
- Update validator and admin thresholds
- Configure bridge fees (percentage-based with minimum fee)
- Enable/disable specific token pairs
- Update fee collector address
programs/taskmaster-bridge/src/
├── lib.rs # Main program entry point
├── constants.rs # Program constants and configuration
├── errors.rs # Custom error definitions
├── state/ # Account structures
│ ├── bridge.rs # Main bridge configuration
│ ├── validator.rs # Validator set management
│ ├── admin.rs # Admin set management
│ ├── token_pair.rs # Token pair mappings
│ └── bridge_transaction.rs # Transaction records
└── instructions/ # Instruction handlers
├── initialize.rs # Bridge initialization
├── lock_tokens.rs # Lock native tokens
├── unlock_tokens.rs # Unlock native tokens
├── mint_wrapped.rs # Mint wrapped tokens
├── burn_wrapped.rs # Burn wrapped tokens
├── verify_transaction.rs # Multi-sig verification
├── pause.rs # Emergency pause/unpause
├── update_validators.rs # Validator management
├── register_token_pair.rs # Token pair registration
└── update_fee.rs # Fee management
- Solana (Chain ID: 0)
- Ethereum (Chain ID: 1)
- BSC (Chain ID: 56)
- Arbitrum (Chain ID: 42161)
- Validator Threshold: 3 out of 5 validators required
- Admin Threshold: 3 out of 5 admins required
- Bridge Fee: 0.1% (10 basis points)
- Minimum Fee: 0.001 SOL (1,000,000 lamports)
- Maximum Fee: 5% (500 basis points)
- Max Validators: 10
- Max Admins: 10
initialize(
initial_validators: Vec<Pubkey>, // List of validator public keys
validator_threshold: u8, // Number of signatures required (e.g., 3)
initial_admins: Vec<Pubkey>, // List of admin public keys
admin_threshold: u8, // Number of admin signatures required (e.g., 3)
fee_basis_points: u16, // Fee in basis points (e.g., 10 = 0.1%)
)register_native_token_pair(
external_chain_id: u64, // Target chain ID (1=Ethereum, 56=BSC, 42161=Arbitrum)
external_token_address: String, // Token address on external chain (e.g., "0x...")
)register_wrapped_token_pair(
external_chain_id: u64, // Source chain ID
external_token_address: String, // Token address on external chain
decimals: u8, // Token decimals
)lock_tokens(
nonce: u64, // Current bridge nonce
amount: u64, // Amount to lock (in token units)
destination_chain_id: u64, // Target chain ID
recipient_address: String, // Recipient address on external chain
)burn_wrapped(
nonce: u64, // Current bridge nonce
amount: u64, // Amount to burn
destination_chain_id: u64, // Target chain ID
recipient_address: String, // Recipient address on external chain
)- Validator initiates unlock:
unlock_tokens(
nonce: u64, // Current bridge nonce
amount: u64, // Amount to unlock
source_chain_id: u64, // Source chain ID
external_tx_hash: String, // Transaction hash on external chain
recipient: Pubkey, // Recipient on Solana
)- Other validators verify:
verify_transaction(tx_nonce: u64)- Execute once verified:
execute_unlock(tx_nonce: u64)- Validator initiates mint:
mint_wrapped(
nonce: u64,
amount: u64,
source_chain_id: u64,
external_tx_hash: String,
recipient: Pubkey,
)- Other validators verify:
verify_transaction(tx_nonce: u64)- Execute once verified:
execute_mint_wrapped(tx_nonce: u64)pause_bridge() // Emergency stop
unpause_bridge() // Resume operationsadd_validator(new_validator: Pubkey)
remove_validator(validator_to_remove: Pubkey)
update_validator_threshold(new_threshold: u8)add_admin(new_admin: Pubkey)
remove_admin(admin_to_remove: Pubkey)update_fee(
new_fee_basis_points: Option<u16>,
new_min_fee_lamports: Option<u64>,
)
update_fee_collector(new_fee_collector: Pubkey)toggle_token_pair() // Enable/disable a specific token pair- All cross-chain transactions (unlock/mint) require validator signatures
- Threshold-based approval (default: 3 out of 5)
- Duplicate signature prevention
- Unique nonce for each transaction
- Transaction history tracking
- State transition validation
- Admin-only operations protected by multi-sig
- Validator-only transaction initiation
- PDA-based account ownership
- Bridge can be paused by any admin
- Paused state prevents all bridging operations
- Individual token pairs can be deactivated
anchor buildanchor test# Deploy to devnet
anchor deploy --provider.cluster devnet
# Deploy to mainnet
anchor deploy --provider.cluster mainnet- Seeds:
["bridge"] - Stores: Configuration, fees, pause state, global nonce
- Seeds:
["validator_set", bridge_pubkey] - Stores: List of validators, threshold
- Seeds:
["admin_set", bridge_pubkey] - Stores: List of admins, threshold
- Seeds:
["token_pair", bridge_pubkey, mint_pubkey, chain_id] - Stores: Token mapping, activity status, totals
- Seeds:
["bridge_tx", bridge_pubkey, nonce] - Stores: Transaction details, signatures, status
- Seeds:
["vault", bridge_pubkey, mint_pubkey] - Stores: Locked native tokens (SPL Token Account)
- Seeds:
["wrapped_mint", bridge_pubkey, external_address, chain_id] - Stores: Wrapped token mint (controlled by bridge)
- User calls
lock_tokensorburn_wrapped - Tokens are locked/burned, fee is collected
- Transaction is recorded with status
Executed - Relayers monitor and process on external chain
- Validator detects external chain transaction
- Validator calls
unlock_tokensormint_wrapped(status:Pending) - Other validators call
verify_transactionto add signatures - Once threshold is met, status changes to
Verified - Anyone can call
execute_unlockorexecute_mint_wrapped - Tokens are released/minted, status changes to
Executed
- Calculated as:
(amount * fee_basis_points) / 10000 - Default: 0.1% (10 basis points)
- Configurable by admins
- Ensures minimum fee is collected even on small transactions
- Default: 0.001 SOL (1,000,000 lamports)
- Fees collected in the same token being bridged
- Sent to designated fee collector account
See src/errors.rs for complete list of error codes:
BridgePaused: Bridge operations are pausedUnauthorized: Caller lacks required permissionsInvalidValidatorThreshold: Invalid threshold configurationInsufficientSignatures: Not enough validator signaturesTokenPairNotRegistered: Token pair not whitelistedTransactionAlreadyProcessed: Replay attack detected- And more...
This project is licensed under the terms specified in the LICENSE file.
Contributions are welcome! Please ensure:
- All tests pass
- Code follows Rust best practices
- Security considerations are documented
For issues, questions, or contributions, please open an issue on the project repository.