Skip to content

Selithrarion/mini-wormhole-bridge

 
 

Repository files navigation

cross-chain token bridge (a mini-wormhole/layerzero)

took a simple proof-of-concept bridge. decided to take it as a base and try to build something closer to a production-ready system, focusing on fixing the major security and centralization issues i found.

ended up adding decentralized validation, a separate relayer/validator system, economic incentives, and a proper lock&mint model. here's how it evolved

1. decentralized validation (M-of-N)

  • problem: the original bridge had a single validator. a huge single point of failure and completely centralized.
  • solution: added a ValidatorManager contract. now a group of independent validators have to sign off on every transaction. it's an m-of-n setup, so if one validator goes offline, the bridge keeps working.

2. separation of concerns: validators and relayers

  • problem: one script was doing everything - listening, signing, and sending transactions. it was a mess and mixed up responsibilities.
  • solution: split these roles:
    • validators: they just listen for events (Lock, BurnWrapped) and submit signatures to an api. cheap and simple.
    • relayers: anyone can run a relayer. they just poll the api for enough signatures and submit the final transaction to the destination chain, paying the gas.

3. economic sustainability: relayer incentives

  • problem: why would anyone run a relayer and spend their own money on gas? without an incentive, the system wouldn't work.
  • solution: added a relayerFee. when a user locks tokens, they pay a small extra fee. this fee goes to the relayer who successfully processes their transaction. this creates a real, market-driven incentive for a permissionless relayer network.

4. enhanced security & state management

  • NonceManager.sol: created a separate contract just to handle nonces. this prevents replay attacks and keeps the main bridge contract cleaner. the bridge is the owner of the nonce manager, so only it can change the state.
  • claimFailedLock function: a safety net for users. if a transaction gets stuck and isn't processed within 24 hours, the user can get all their funds back, including the fee. this way, user funds are never lost.
  • standard stuff: used openzeppelin's Pausable for an emergency stop and ReentrancyGuard to prevent re-entrancy attacks.

core system flow (lock -> mint)

  1. lock (source chain):
    • a user calls lock(), paying amount + relayerFee. the bridge locks the tokens and emits an event.
  2. validate & sign (off-chain):
    • validators see the event, sign the message, and send their signatures to the api server.
  3. relay (off-chain):
    • a relayer polls the api. once enough signatures are collected, it grabs them.
  4. mint (destination chain):
    • the relayer calls mint() with the signatures. the destination bridge verifies everything, mints tokens to the user, and sends the relayerFee to the relayer.

the reverse process (burnWrapped -> unlock) works the same way.

future improvements

this is still just a foundation, to make it truly production-ready, here's what i'd do next:

  • decentralized signature aggregation:

    • the api server is a single point of failure. i'd replace it with a p2p gossip protocol so validators can talk to each other directly, like how wormhole's guardians work.
  • decentralized governance (Multisig):

    • the admin functions are currently unprotected. need to use a multisig wallet (gnosis safe)
  • persistent & scalable off-chain storage:

    • the api server's in-memory "db" is just for testing. for a real system, i'd use something like postgresql + redis with replication to make sure signatures aren't lost on a server restart.
  • advanced relayer logic:

    • build a smarter relayer that analyzes gas prices and profitability to decide which transactions to process first.
  • alerting:

    • set up a monitoring system (prometheus/grafana?) to send alerts
  • upgradability:

    • use uups
  • support more tokens and more chains:

    • refactor the contracts to support any erc20/erc721s.

local development & testing

to run the full end-to-end environment locally.

  1. run two local blockchain nodes (required foundry setup).
  2. deploy the contracts to both.
  3. start all the off-chain services.
  4. run the initiateLock.js script to kick off a transfer.

also can run hardhat test

terminal setup

Terminal 1 (wsl, ubuntu)

anvil --port 8545 --chain-id 31337

Terminal 2 (wsl, ubuntu)

anvil --port 9545 --chain-id 31338

Terminal 3

pnpm run deploy:all

Terminal 4

pnpm run dev

Terminal 5

npx hardhat run scripts/initiateLock.js --network chain1

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 71.8%
  • Solidity 28.2%