half dev half degen
half dev half degen

Subscribe to Kunal Arora

Subscribe to Kunal Arora
Share Dialog
Share Dialog


<100 subscribers
<100 subscribers
So many chains, so little noise!
A lot of chains have spun up in the last three years, especially built on different infrastructures like EVM like Ethereum, Avalanche, Binance Smart Chain, or Substrate-based chains like Polkadot, Cosmos-SDK chains like Terra and BNB. This makes it incredibly difficult to communicate between chains. This communication entails not just token transfers but also more generic messaging for applications like cross-chain voting or playing games where you could own assets on one chain and make your moves on another one.
This is where Wormhole comes in. From their docs,
Wormhole is a generic message passing protocol that connects to multiple chains including Ethereum, Solana, Terra, Binance Smart Chain, Polygon, Avalanche, Oasis, and Fantom.
This serves us perfectly. Wormhole operates with the help of a network of nodes called guardians which signs and verifies transactions on the origin chain and with relayers to relay the message to the target chain. More details here:

Wormhole has core bridge contracts deployed on all chains (published list available here). They implement emitVAA() and verifyVAA() functions. VAA or Verifiable Action Approval is a struct containing your message payload along with guardian signatures. emitVAA reads and publishes messages to the “mempool” of VAAs and verifyVAA takes VAA and matches the guardian signatures to make sure the proof is valid. This is the VAA payload:
// head
byte version // VAA Version
u32 guardian_set_index // Indicates which guardian set is signing
u8 len_signatures // Number of signatures stored[][66]byte signatures // Collection of ecdsa signatures
// body
u32 timestamp
u32 nonce
u16 emitter_chain
[32]byte emitter_address
u64 sequence
u8 consistency_level
[]byte payload
Once you send the transactions to the wormhole, each and every guardian will confirm and sign the payload in isolation and these signatures get collectively stored in stored[][66]byte. This is similar to users who independently sign transactions on a Gnosis multi-sig wallet. There are only 19 guardians on the network and most of these are Solana validators.
Upon reaching 2/3rd majority of guardian signatures, the emitVAA the function gets triggered and the VAAs are ready to be picked up from the Wormhole network and submit it to the target chain.
On the target chain, the VAA is processed by the core receiving contract. You can manually go fetch your message from the guardian RPC and submit the VAA on the target chain. Usually, this burden is abstracted away from the user by the dapps built on top of the core Wormhole bridge. In a lot of cases, they use “relayer” which acts as an automation script. Relayers can be run in an untrusted environment and cannot forge VAAs as they aren’t running any cryptographic function and if they taper with the code it gets rejected at the target chain bridge contracts.
Since the transaction is settled on the target chain, gas fees should be paid there. If a user doesn’t have the native currency on the target chain, the bridge lets users pay a portion of the token being transferred via relayers. The relayers then cover the gas expenditure on the target chain. Oftentimes, dapps built on Wormhole will pay on the user’s behalf as meta-transactions to improve ease of use.
In this case, messages on the origin chain may get slashed by a fork. Wormhole attempts to fix this by allowing the message emitting contract on the origin chain to specify the waiting period before sending it to the wormhole guardian network. If you’re on Ethereum, you need to wait for 13 network confirmations before assuming immutability of your transaction and as a dapp builder, you can specify this number as you deploy your contracts.
The token is locked on the origin chain and its wrapped version is minted on the target chain. The origin chain emits a message saying the tokens have been locked in the following structure:
u8 payload_id = 1 Transfer
u256 amount Amount of tokens being transferred.
u8[32] token_address Address on the origin chain.
u16 token_chain Numeric ID for the origin chain.
u8[32] to Address on the destination chain.
u16 to_chain Numeric ID for the destination chain.
u256 fee Portion of amount paid to a relayer.
This event however doesn’t specify the implementation of how the tokens were locked. They could have been locked in a smart contract or in a custody, this is up to the implementation of the token bridge.
Yes. In comparison to trustless liquidity bridges like Connext or light client bridges like LayerZero or Gravity, Wormhole falls in the “External validators” category of bridges which makes it one of the riskier ones and prone to centralization risk especially because these 19 validators are also validators for the Solana network.
This is a valid concern. On Feb 2nd, a hacker was able to spook guardian signatures by calling an outdated version of the Secp256k1 contract for the verify_signatures function on Solana, generating a fake SignatureSet and signing fraudulent VAA to drain 120k ETH on Ethereum, making WETH on Solana worthless. Read more about this hack here. Lock/mint token bridges like the Wormhole Portal essentially behave as massive escrow accounts and aren’t supported by the economic security of the connecting L1s. And operating on multiple chains, they have multiple points of failure. This paints them as big targets for being exploited by hackers.
This is how a user interacts and the bridge user flows:
Say you’ve deployed your contract on Eth mainnet but you want to send a message to Solana. So, using the Wormhole SDK, you can wrap your address in IWormhole and use _wormhole.publishMessage() with:
import "./interfaces/IWormhole.sol";
contract Messenger {
// Hardcode the Wormhole Core Bridge contract address
// In a real contract, we would set this in a constructor
address a = address(0xC89Ce4735882C9F0f0FE26686c53074E09B0D550);
IWormhole _wormhole = IWormhole(a);
function sendStr(bytes memory str, uint32 nonce) public returns (uint64 sequence) {
sequence = _wormhole.publishMessage(nonce, str, 1);
return sequence;
}
function wormhole() public view returns (IWormhole) {
return _wormhole;
}
}
Token transfer from Ethereum to Solana:
// Submit transaction
const receipt = await transferFromEth(
ETH_TOKEN_BRIDGE_ADDRESS, // specified in the doc
signer,
tokenAddress, // WETH token address
amount,
CHAIN_ID_SOLANA,
recipientAddress // already attested address on solana
);
// signedVAA needs to be fetched
const { signedVAA } = await getSignedVAA(
WORMHOLE_RPC_HOST,
CHAIN_ID_ETH,
emitterAddress,
sequence
);
// post signVAA
await postVaaSolana(
connection,
wallet,
SOL_BRIDGE_ADDRESS,
payerAddress,
signedVAA
);
// redeem WETH on Solana
const transaction = await redeemOnSolana(
connection,
SOL_BRIDGE_ADDRESS,
SOL_TOKEN_BRIDGE_ADDRESS,
payerAddress,
signedVAA,
isSolanaNative,
mintAddress
);
How does Wormhole handle multiple chains talking to each other at the same time? If chain A sends a message to chain B and also sends a different message to chain C which then sends it to chain B, which version will be considered to be accurate?

Can Wormhole mitigate its centralization factor? Is there a way to get the counterparty validator set on either side of the bridge to behave as additional members of the guardian network?
How does Wormhole deal with interactions between deterministic vs probabilistic consensus models?
Blockchain bridges by Dmitriy Berenzon
Thanks for reading and following me on Twitter @auroraByKunal. I’ll be publishing how a cross-chain poker app works on Wormhole soon.
So many chains, so little noise!
A lot of chains have spun up in the last three years, especially built on different infrastructures like EVM like Ethereum, Avalanche, Binance Smart Chain, or Substrate-based chains like Polkadot, Cosmos-SDK chains like Terra and BNB. This makes it incredibly difficult to communicate between chains. This communication entails not just token transfers but also more generic messaging for applications like cross-chain voting or playing games where you could own assets on one chain and make your moves on another one.
This is where Wormhole comes in. From their docs,
Wormhole is a generic message passing protocol that connects to multiple chains including Ethereum, Solana, Terra, Binance Smart Chain, Polygon, Avalanche, Oasis, and Fantom.
This serves us perfectly. Wormhole operates with the help of a network of nodes called guardians which signs and verifies transactions on the origin chain and with relayers to relay the message to the target chain. More details here:

Wormhole has core bridge contracts deployed on all chains (published list available here). They implement emitVAA() and verifyVAA() functions. VAA or Verifiable Action Approval is a struct containing your message payload along with guardian signatures. emitVAA reads and publishes messages to the “mempool” of VAAs and verifyVAA takes VAA and matches the guardian signatures to make sure the proof is valid. This is the VAA payload:
// head
byte version // VAA Version
u32 guardian_set_index // Indicates which guardian set is signing
u8 len_signatures // Number of signatures stored[][66]byte signatures // Collection of ecdsa signatures
// body
u32 timestamp
u32 nonce
u16 emitter_chain
[32]byte emitter_address
u64 sequence
u8 consistency_level
[]byte payload
Once you send the transactions to the wormhole, each and every guardian will confirm and sign the payload in isolation and these signatures get collectively stored in stored[][66]byte. This is similar to users who independently sign transactions on a Gnosis multi-sig wallet. There are only 19 guardians on the network and most of these are Solana validators.
Upon reaching 2/3rd majority of guardian signatures, the emitVAA the function gets triggered and the VAAs are ready to be picked up from the Wormhole network and submit it to the target chain.
On the target chain, the VAA is processed by the core receiving contract. You can manually go fetch your message from the guardian RPC and submit the VAA on the target chain. Usually, this burden is abstracted away from the user by the dapps built on top of the core Wormhole bridge. In a lot of cases, they use “relayer” which acts as an automation script. Relayers can be run in an untrusted environment and cannot forge VAAs as they aren’t running any cryptographic function and if they taper with the code it gets rejected at the target chain bridge contracts.
Since the transaction is settled on the target chain, gas fees should be paid there. If a user doesn’t have the native currency on the target chain, the bridge lets users pay a portion of the token being transferred via relayers. The relayers then cover the gas expenditure on the target chain. Oftentimes, dapps built on Wormhole will pay on the user’s behalf as meta-transactions to improve ease of use.
In this case, messages on the origin chain may get slashed by a fork. Wormhole attempts to fix this by allowing the message emitting contract on the origin chain to specify the waiting period before sending it to the wormhole guardian network. If you’re on Ethereum, you need to wait for 13 network confirmations before assuming immutability of your transaction and as a dapp builder, you can specify this number as you deploy your contracts.
The token is locked on the origin chain and its wrapped version is minted on the target chain. The origin chain emits a message saying the tokens have been locked in the following structure:
u8 payload_id = 1 Transfer
u256 amount Amount of tokens being transferred.
u8[32] token_address Address on the origin chain.
u16 token_chain Numeric ID for the origin chain.
u8[32] to Address on the destination chain.
u16 to_chain Numeric ID for the destination chain.
u256 fee Portion of amount paid to a relayer.
This event however doesn’t specify the implementation of how the tokens were locked. They could have been locked in a smart contract or in a custody, this is up to the implementation of the token bridge.
Yes. In comparison to trustless liquidity bridges like Connext or light client bridges like LayerZero or Gravity, Wormhole falls in the “External validators” category of bridges which makes it one of the riskier ones and prone to centralization risk especially because these 19 validators are also validators for the Solana network.
This is a valid concern. On Feb 2nd, a hacker was able to spook guardian signatures by calling an outdated version of the Secp256k1 contract for the verify_signatures function on Solana, generating a fake SignatureSet and signing fraudulent VAA to drain 120k ETH on Ethereum, making WETH on Solana worthless. Read more about this hack here. Lock/mint token bridges like the Wormhole Portal essentially behave as massive escrow accounts and aren’t supported by the economic security of the connecting L1s. And operating on multiple chains, they have multiple points of failure. This paints them as big targets for being exploited by hackers.
This is how a user interacts and the bridge user flows:
Say you’ve deployed your contract on Eth mainnet but you want to send a message to Solana. So, using the Wormhole SDK, you can wrap your address in IWormhole and use _wormhole.publishMessage() with:
import "./interfaces/IWormhole.sol";
contract Messenger {
// Hardcode the Wormhole Core Bridge contract address
// In a real contract, we would set this in a constructor
address a = address(0xC89Ce4735882C9F0f0FE26686c53074E09B0D550);
IWormhole _wormhole = IWormhole(a);
function sendStr(bytes memory str, uint32 nonce) public returns (uint64 sequence) {
sequence = _wormhole.publishMessage(nonce, str, 1);
return sequence;
}
function wormhole() public view returns (IWormhole) {
return _wormhole;
}
}
Token transfer from Ethereum to Solana:
// Submit transaction
const receipt = await transferFromEth(
ETH_TOKEN_BRIDGE_ADDRESS, // specified in the doc
signer,
tokenAddress, // WETH token address
amount,
CHAIN_ID_SOLANA,
recipientAddress // already attested address on solana
);
// signedVAA needs to be fetched
const { signedVAA } = await getSignedVAA(
WORMHOLE_RPC_HOST,
CHAIN_ID_ETH,
emitterAddress,
sequence
);
// post signVAA
await postVaaSolana(
connection,
wallet,
SOL_BRIDGE_ADDRESS,
payerAddress,
signedVAA
);
// redeem WETH on Solana
const transaction = await redeemOnSolana(
connection,
SOL_BRIDGE_ADDRESS,
SOL_TOKEN_BRIDGE_ADDRESS,
payerAddress,
signedVAA,
isSolanaNative,
mintAddress
);
How does Wormhole handle multiple chains talking to each other at the same time? If chain A sends a message to chain B and also sends a different message to chain C which then sends it to chain B, which version will be considered to be accurate?

Can Wormhole mitigate its centralization factor? Is there a way to get the counterparty validator set on either side of the bridge to behave as additional members of the guardian network?
How does Wormhole deal with interactions between deterministic vs probabilistic consensus models?
Blockchain bridges by Dmitriy Berenzon
Thanks for reading and following me on Twitter @auroraByKunal. I’ll be publishing how a cross-chain poker app works on Wormhole soon.
No activity yet