The ChainBridge smart contract is deployed on Stellar's Soroban platform and serves as the core protocol for trustless cross-chain atomic swaps. It implements the Hash Time-Locked Contract (HTLC) pattern to ensure atomicity - either both sides of a swap complete, or both parties can recover their funds.
Contract ID: [To be deployed on mainnet]
Networks: Stellar Mainnet, Stellar Testnet
/// Initialize the cross-chain bridge protocol
/// # Arguments
/// * `admin` - Address of the admin who can manage chain configuration
fn init(env: Env, admin: Address) -> Result<(), Error>/// Create a Hash Time-Locked Contract
/// # Arguments
/// * `sender` - Address creating the HTLC (funds sender)
/// * `receiver` - Address that can claim the HTLC
/// * `amount` - Amount of tokens/asset to lock
/// * `hash_lock` - 32-byte SHA256 hash of the secret
/// * `time_lock` - Unix timestamp when HTLC expires
/// # Returns
/// * `htlc_id` - Unique identifier for the created HTLC
fn create_htlc(
env: Env,
sender: Address,
receiver: Address,
amount: i128,
hash_lock: Bytes,
time_lock: u64,
) -> Result<u64, Error>/// Claim HTLC by revealing the secret
/// # Arguments
/// * `receiver` - Address claiming the HTLC (must be the receiver)
/// * `htlc_id` - ID of the HTLC to claim
/// * `secret` - The preimage that hashes to the hash_lock
fn claim_htlc(
env: Env,
receiver: Address,
htlc_id: u64,
secret: Bytes,
) -> Result<(), Error>/// Refund HTLC after timelock expires
/// # Arguments
/// * `sender` - Original creator of the HTLC
/// * `htlc_id` - ID of the HTLC to refund
fn refund_htlc(
env: Env,
sender: Address,
htlc_id: u64,
) -> Result<(), Error>/// Get complete HTLC information
fn get_htlc(env: Env, htlc_id: u64) -> Result<HTLC, Error>
/// Get current HTLC status
fn get_htlc_status(env: Env, htlc_id: u64) -> Result<HTLCStatus, Error>
/// Get revealed secret (only available after claim)
fn get_secret(env: Env, htlc_id: u64) -> Result<Option<Bytes>, Error>/// Create a swap order in the order book
/// # Arguments
/// * `creator` - Address creating the order
/// * `from_chain` - Source chain for the swap
/// * `to_chain` - Destination chain for the swap
/// * `from_asset` - Asset to send (e.g., "XLM", "BTC")
/// * `to_asset` - Asset to receive
/// * `from_amount` - Amount to send
/// * `to_amount` - Amount desired in return
/// * `expiry` - Unix timestamp when order expires
fn create_order(
env: Env,
creator: Address,
from_chain: Chain,
to_chain: Chain,
from_asset: String,
to_asset: String,
from_amount: i128,
to_amount: i128,
expiry: u64,
) -> Result<u64, Error>/// Match and execute a swap order
/// # Arguments
/// * `counterparty` - Address matching the order
/// * `order_id` - ID of the order to match
/// # Returns
/// * `swap_id` - ID of the created cross-chain swap
fn match_order(
env: Env,
counterparty: Address,
order_id: u64,
) -> Result<u64, Error>/// Cancel an unmatched order
fn cancel_order(
env: Env,
creator: Address,
order_id: u64,
) -> Result<(), Error>/// Get order details
fn get_order(env: Env, order_id: u64) -> Result<SwapOrder, Error>/// Verify a cross-chain proof
/// # Arguments
/// * `proof` - ChainProof containing chain ID, tx hash, block height, and proof data
/// # Returns
/// * `bool` - True if proof is valid
fn verify_proof(
env: Env,
proof: ChainProof,
) -> Result<bool, Error>/// Complete a cross-chain swap using verified proof
/// # Arguments
/// * `swap_id` - ID of the swap to complete
/// * `proof` - Verified proof from the other chain
fn complete_swap(
env: Env,
swap_id: u64,
proof: ChainProof,
) -> Result<(), Error>fn get_swap(env: Env, swap_id: u64) -> Result<CrossChainSwap, Error>/// Add a new supported blockchain
/// # Arguments
/// * `admin` - Admin address for authorization
/// * `chain_id` - Numeric chain identifier
fn add_chain(
env: Env,
admin: Address,
chain_id: u8,
) -> Result<(), Error>pub enum HTLCStatus {
Active, // HTLC is locked and awaiting claim
Claimed, // HTLC has been claimed with secret
Refunded, // HTLC has been refunded after expiry
Expired, // HTLC expired without action
}pub enum Chain {
Bitcoin, // Chain ID: 0
Ethereum, // Chain ID: 1
Solana, // Chain ID: 2
Polygon, // Chain ID: 3
BSC, // Chain ID: 4
}pub struct HTLC {
pub sender: Address, // HTLC creator
pub receiver: Address, // Intended recipient
pub amount: i128, // Amount locked
pub hash_lock: Bytes, // SHA256(secret)
pub time_lock: u64, // Expiry timestamp
pub status: HTLCStatus, // Current status
pub secret: Option<Bytes>, // Revealed secret (if claimed)
pub created_at: u64, // Creation timestamp
}pub struct SwapOrder {
pub id: u64,
pub creator: Address,
pub from_chain: Chain,
pub to_chain: Chain,
pub from_asset: String,
pub to_asset: String,
pub from_amount: i128,
pub to_amount: i128,
pub expiry: u64,
pub matched: bool,
pub counterparty: Option<Address>,
}pub struct CrossChainSwap {
pub id: u64,
pub stellar_htlc_id: u64,
pub other_chain: Chain,
pub other_chain_tx: String, // Tx hash on other chain
pub stellar_party: Address,
pub other_party: String, // Address on other chain
pub completed: bool,
}pub struct ChainProof {
pub chain: Chain,
pub tx_hash: String,
pub block_height: u64,
pub proof_data: Bytes, // Merkle/SPV proof
}| Code | Error | Description |
|---|---|---|
| 1 | AlreadyInitialized | Contract already initialized |
| 2 | NotInitialized | Contract not initialized |
| 3 | Unauthorized | Caller not authorized |
| 4 | InvalidAmount | Amount must be positive |
| 5 | HTLCNotFound | HTLC does not exist |
| 6 | HTLCExpired | HTLC timelock has passed |
| 7 | HTLCNotExpired | HTLC timelock not yet passed |
| 8 | InvalidSecret | Secret does not match hash |
| 9 | AlreadyClaimed | HTLC already claimed |
| 10 | AlreadyRefunded | HTLC already refunded |
| 11 | InvalidHashLength | Hash must be 32 bytes |
| 12 | InvalidTimelock | Timelock invalid |
| 13 | OrderNotFound | Order does not exist |
| 14 | OrderAlreadyMatched | Order already matched |
| 15 | OrderExpired | Order has expired |
| 16 | InvalidChain | Chain not supported |
| 17 | ProofVerificationFailed | Proof verification failed |
- Initiator generates a random secret
S(32 bytes) - Computes hash
H = SHA256(S) - Calls
create_htlc()with:- Receiver's address
- Amount to lock
- Hash
H - Timeout timestamp (e.g., 24 hours from now)
- Contract stores HTLC and returns HTLC ID
- Receiver observes HTLC creation on Stellar
- Receiver creates corresponding HTLC on destination chain
- Initiator (or relayer) reveals secret
Sby claiming destination HTLC - Receiver detects secret revelation
- Receiver calls
claim_htlc()with secretS - Contract verifies
SHA256(S) == H - If valid, funds are transferred to receiver
- If HTLC is not claimed before timeout
- Initiator calls
refund_htlc() - Contract verifies timelock has passed
- Funds are returned to initiator
enum DataKey {
Admin, // Contract admin address
HTLCCounter, // HTLC ID counter
HTLC(u64), // Individual HTLC data
OrderCounter, // Order ID counter
Order(u64), // Individual order data
SwapCounter, // Swap ID counter
Swap(u64), // Individual swap data
SupportedChain(u8), // Supported chain flag
}- Instance Storage: Admin, counters (frequent access)
- Persistent Storage: HTLCs, Orders, Swaps (larger data)
- Uses SHA256 for hash locking (battle-tested)
- 32-byte secrets provide 256-bit security
- Preimage resistance ensures secret cannot be derived from hash
- Minimum timelock: Recommended 24 hours for Stellar side
- Cascading timeouts: Destination chain timeout < source chain timeout
- Prevents race conditions where counterparty waits until last moment
- All state-changing operations require authentication
require_auth()ensures only designated parties can act- Admin functions protected by admin address verification
- Storage Write: Permanent storage with initial rent
- Compute: Instruction count limits
- Ledger Entry: Persistent data storage
- Use appropriate storage types (instance vs persistent)
- Minimize contract code size
- Batch operations when possible
Run tests with:
cd smartcontract
cargo test- HTLC creation with valid/invalid parameters
- Claim with correct/incorrect secret
- Refund before/after expiry
- Order creation and matching
- Error handling and edge cases
# Build contract
cargo build --release --target wasm32-unknown-unknown
# Deploy to testnet
soroban contract deploy \
--wasm target/wasm32-unknown-unknown/release/chainbridge.wasm \
--network testnet# Deploy to mainnet
soroban contract deploy \
--wasm target/wasm32-unknown-unknown/release/chainbridge.wasm \
--network mainnetThe current contract is not upgradeable. Future versions may implement:
- Proxy pattern for upgradeability
- Migration functions for data transfer
- Governance for parameter updates
The contract emits events for off-chain monitoring:
HTLCCreated: When new HTLC is createdHTLCClaimed: When HTLC is successfully claimedHTLCRefunded: When HTLC is refundedOrderCreated: When new order is placedOrderMatched: When order is matchedSwapCompleted: When cross-chain swap completes
- Relayer monitors events from contract
- When HTLC is created, relayer watches destination chain
- When claim happens, relayer generates proof
- Relayer submits proof to complete Stellar side
- Backend tracks swap status via events
import { Contract, Keypair, Networks } from 'stellar-sdk';
const secret = Keypair.random().random(); // 32 bytes
const hashLock = sha256(secret);
const tx = await contract.invoke({
method: 'create_htlc',
args: [
receiverAddress,
'1000000000', // 10 XLM in stroops
hashLock,
Math.floor(Date.now() / 1000) + 86400 // 24 hours
]
});const tx = await contract.invoke({
method: 'claim_htlc',
args: [
htlcId,
secret // The preimage
]
});