It might be a bit surprising to our readers that crypto hacks caused over $3 billion lost of funds in 2022. However, a majority of the lost was on cross-chain bridges (e.g., Ronin Network, Wormhole, Nomad, BNB Token Hub, Horizon, Qubit).
Why are cross-chain bridges so vulnerable? Are they not designed or implemented carefully? On the contrary, due to their high value they are developed with the highest possible standards by some of the best engineers (e.g., leoluk). The real reason is that cross-chain bridges are just too complex to get right, involving too many technical subtleties.
In this article series, we will elaborate the internals of cross-chain bridges, how they are implemented and what their caveats are from the user’s perspective. We will use a state-of-the-art bridge Wormhole as an example.
A cross-chain bridge is just a (virtual) link between two blockchains for message communication. The message can essentially be any bit sequence (such as transferring a token or an NFT from Chain A to Chain B).
Suppose you want to transfer a bitcoin from Ethereum to Solana, you need to do at least two operations:
However, because these two chains do not directly communicate (in a technical term: there is no way to touch both chains in a single transaction), you need a man-in-the-middle who owns bitcoins on both chains and who can help you with two steps:
A cross-chain bridge is such a man-in-the-middle. There are several challenges here:
Web3 researchers have developed multiple different solutions to address these challenges (with different trade-offs). For example, multi-sig validators, multi-party computation (MPC), rollup and optimistic bridges, etc. See the Interoperability Trilemma for a nice summary.
We will focus on explaining a representative solution based on guardians (i.e., a type of multi-sig validators) used by Wormhole.
As of Jan 2023, Wormhole bridges 20 different chains including Ethereum, Solana, Binance Smart Chain, Polygon, Aptos, and so on.
It achieves this by operating a network of 19 nodes called guardians (see all the 19 guardian addresses), and a number of smart contracts deployed on each chain (including a core bridge contract, a token bridge contract and an NFT bridge contract). The core bridge contract provides functions for emitting messages, verifying guardian signatures, and so on. The token and NFT bridge contracts are responsible for transferring tokens and NFT, respectively.
The 19 guardians each observe messages emitted by the Wormhole core bridge contracts continuously, and sign on the messages (e.g., a message like “Alice just sent a bitcoin to Wormhole on Ethereum, and she wanted Wormhole to send a bitcoin to Bob on Solana).
The guardians each hold equal weight. When a super-majority (2/3) of them sign a message, the guardian network produces a Validator Action Approval (VAA), which serves as a proof for Wormhole to deliver the same message on the target chain (e.g., send a bitcoin to Bob on Solana).
VAAs are at the heart of all Wormhole technical details. There are a number of questions on VAAs that keen readers may wonder:
Next, we will answer these questions one by one (with code examples whenever necessary).
Each VAA is encoded as a byte array with two parts - a header and a body.
In particular, sequence is an important piece of information to ensure that each VAA is unique for a message (i.e., any two different messages would have different VAAs even if they have the same message content).
The sequence number is incremented by 1 in the useSequence function for every publishMessage call:
This is critical to guarantee the same message will never be delivered twice. We will elaborate this point further in the next section.
The payload byte array contains the message content. For example, for a token Transfer, it includes the transfer amount, token address, token chain, the recipient address, the target chain ID, transfer fee, etc:
Once a VAA is produced (i.e., a message that has been signed by 2/3 guardians), it will be stored in the guardian network (likely for a long time or even permanently).
Each VAA is uniquely indexed by its emitterChain, emittedAddress and sequence, and can be obtained by querying a guardian node (via an RPC API) with this information:
For example, an RPC query https://wormhole-v2-mainnet-api.certus.one/v1/signed_vaa/2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/99139 with
returns the following VAA bytes:
corresponding to a transfer of 0.1 WETH from Ethereum to Solana ($128.15):
Anyone can query a guardian node, and the returned VAA bytes can be submitted by anyone to the target chain to complete the message (e.g., mint a bitcoin to the recipient address encoded in the VAA).
Consider the message in Figure 1 “a token transfer of 0.1 WETH from Ethereum to Solana”. From the user’s perspective, there are actually five on-chain transactions involved (one on Ethereum and four on Solana) in the following order:
The user 0x4f98 sends 0.1 WETH to the Wormhole Token Bridge 0x3ee1 by calling wrapAndTransferETH with parameters specifying the recipient chain (Solana 0x01), recipient (0xfdca, base58 encode as 7vfC on Solana), arbiterFee (i.e., the relayer fee if used) and nonce:
Tx1 invokes Wormhole Core Bridge 0x98f3 internally and emits a message containing sequence, nonce, payload and consistencyLevel as below:
The guardians observe the message shown above and produce a VAA (AQAA…) as shown in Figure 1.
Next, the VAA is retrieved from the guardian network and used to call Wormhole core bridge contract on Solana
The VerifySignatures function on the Solana Wormhole core bridge is invoked by a signer HZBb with the VAA to create a SignatureSet 58Ui:
This transaction also invokes the precompiled Secp256k1 SigVerify program to verify the guardian signatures in the VAA
The VAA contains 13 signatures in total. Due to the compute limit on Solana, Wormhole splits verifying these signatures into two transactions.
After all signatures in the VAA are verified, the PostVAA function can be invoked to create a message account 31Np, which uniquely identifies transferred message:
Two other transactions 3goi and ZpYN also invoke PostVAA successfully, however, because the message account is a PDA, it is only initialized once by Tx4 (5AoD)
The 2/3 quorum is checked in the PostVAA function:
Finally, the CompleteWrapped function on the Wormhole Token Bridge (wormDTUJ) is invoked to complete the transfer.
The recipient 0xfdca to receive the corresponding WETH token (ETH — Ether (Portal) 7vfC) is actually an associated token account (PDA) on Solana owned by 4Kt8. If the recipient does not exist yet, then it has to be created because Tx5 can be executed. The account 0xfdca was created in Tx sSjG on Solana.
Verifying the guardian signatures is absolutely critical for the security of any cross-chain bridges and not surprisingly it is a complex task. We will elaborate in Part 2.
Anyone can retrieve VAAs and perform the downstream transactions. It would be straightforward for the message sender to do so (e.g., the users who initiate the token transfer on the source chain). However, what if a user does not have an account on the target chain or a user has insufficient balances to pay for the transaction fees?
To address this issue, Wormhole allows bridgerelayers to deliver the messages and earn fees. The fee can be specified in the source tranaction, and is encoded into the VAA payload:
The transferred token on the target chain must be the same or equivalent to the token transferred on the source chain. For example, either both are USDC, or one is Wrapped Ether (WETH) on Ethereum and the other is ETH — Ether (Portal) on Solana. But it could not be WETH on Ethereum and USDC on Solana. We will discuss this part in Part 3.
This is a subtle point and entails a careful design on the target chain. Essentially, a global state is required to flag each delivered message and reject transactions that attempt to re-deliver the same message. We will explain this part further in Part 4.
sec3 is a security research firm that prepares Solana projects for millions of users. sec3’s Launch Audit is a rigorous, researcher-led code examination that investigates and certifies mainnet-grade smart contracts; sec3’s continuous auditing software platform, X-ray, integrates with Github to progressively scan pull requests, helping projects fortify code before deployment; and sec3’s post-deployment security solution, WatchTower, ensures funds stay safe. sec3 is building technology-based scalable solutions for Web3 projects to ensure protocols stay safe as they scale.
To learn more about sec3, please visit https://www.sec3.dev